ruby 在Sinatra中需要规范文件的更简单的方法

knpiaxh1  于 2024-01-07  发布在  Ruby
关注(0)|答案(3)|浏览(104)

我有一个spec_helper,看起来像这样:

require 'pry'
require 'helpers/data_helper.rb'
require 'distributer.rb'
require 'house_distributer.rb'
require 'accounting_service.rb'
require 'mixer_worker.rb'
require 'mixer.rb'
require 'transaction_service.rb'

ENV['RACK_ENV'] = 'test'

RSpec.configure do |config|
  config.mock_with :rspec do |mocks|
    mocks.verify_partial_doubles = true
  end

  config.warnings = true

  config.order = :random
end

字符串
文件夹结构如下所示:

.
├── Gemfile
├── Gemfile.lock
├── README.md
├── app.rb
├── config.ru
├── lib
│   ├── accounting_service.rb
│   ├── distributer.rb
│   ├── house_distributer.rb
│   ├── mixer.rb
│   ├── mixer_worker.rb
│   └── transaction_service.rb
├── public
│   ├── css
│   │   └── add_coins.css
│   ├── images
│   │   └── bitcoin_dawg.jpg
│   └── javascripts
│       └── add_coins.js
├── spec
│   ├── helpers
│   │   └── data_helper.rb
│   ├── lib
│   │   ├── accounting_service_spec.rb
│   │   └── transaction_service_spec.rb
│   └── spec_helper.rb
└── views
    └── add_coins.erb


这不起作用:

Dir["lib/*.rb"].each {|file| require file }

[1] pry(main)> Dir["lib/*.rb"]
=> ["lib/house_distributer.rb", "lib/distributer.rb", "lib/mixer.rb", "lib/accounting_service.rb", "lib/mixer_worker.rb", "lib/transaction_service.rb"]


我得到这个错误消息:

/Users/jwan/.rbenv/versions/2.1.2/lib/ruby/2.1.0/rubygems/core_ext/kernel_require.rb:55:in `require': cannot load such file -- lib/house_distributer.rb (LoadError)
    from /Users/jwan/.rbenv/versions/2.1.2/lib/ruby/2.1.0/rubygems/core_ext/kernel_require.rb:55:in `require'


我能做些什么来使这更容易吗?
另外,distributer.rb必须在house_distributer.rb之前加载,因为:

class HouseDistributer < Distributer
end

rryofs0p

rryofs0p1#

  • 麦克斯·普莱纳的回答 *

当你写:

require 'lib/house_distributer.rb'

字符串
ruby在分配给$LOAD_PATH环境变量的目录中查找文件。$LOAD_PATH是一个String数组,其中每个String是一个目录的路径。$LOAD_PATH数组中的目录按顺序搜索,第一个匹配的获胜。
如果$LOAD_PATH包含名为的目录:

'/Users/7stud/ruby_programs'


然后上面的require语句将查找具有绝对路径的文件:

'/Users/7stud/ruby_programs/lib/house_distributer.rb'


您可以像这样检查$LOAD_PATH中的目录:

$ puts $LOAD_PATH


这就是我得到的:

/Users/7stud/.rvm/gems/ruby-2.4.0@global/gems/did_you_mean-1.1.0/lib
/Users/7stud/.rvm/rubies/ruby-2.4.0/lib/ruby/site_ruby/2.4.0
/Users/7stud/.rvm/rubies/ruby-2.4.0/lib/ruby/site_ruby/2.4.0/x86_64-darwin14
/Users/7stud/.rvm/rubies/ruby-2.4.0/lib/ruby/site_ruby
/Users/7stud/.rvm/rubies/ruby-2.4.0/lib/ruby/vendor_ruby/2.4.0
/Users/7stud/.rvm/rubies/ruby-2.4.0/lib/ruby/vendor_ruby/2.4.0/x86_64-darwin14
/Users/7stud/.rvm/rubies/ruby-2.4.0/lib/ruby/vendor_ruby
/Users/7stud/.rvm/rubies/ruby-2.4.0/lib/ruby/2.4.0
/Users/7stud/.rvm/rubies/ruby-2.4.0/lib/ruby/2.4.0/x86_64-darwin14


显然,您的应用程序的文件不在这样的目录中。
另一方面,如果你require一个文件的路径以/.开头--例如:

require './lib/house_distributer.rb'


然后ruby跳过$LOAD_PATH,在这种情况下,ruby查找相对于 * 当前工作目录 * 的文件。但是,请注意,* 当前工作目录 * 可能不是包含require语句的文件的目录。例如,如果您从不同的目录执行sinatra程序,比如从包含require语句的文件向上两级,那么两级目录将是 * 当前工作目录 *,ruby将查找与两级目录相关的所需文件。
输入require_relativerequire_relative将查找相对于当前文件路径的文件,而不是当前工作目录。
因此,您可能永远不应该将require与相对路径一起使用,而应该使用require_relative
请注意,您也可以随时以编程方式向$LOAD_PATH添加路径:

$LOAD_PATH << '/Users/7stud/ruby_programs'


如果该目录中有一个名为dog.rb is的文件,我可以这样要求它:

require 'dog'  #extension is unnecessary

回复评论

最简单的方法是:

$LOAD_PATH << "/Users/jwan/Desktop/programming/interview_questions/gemini/‌​jobcoin_mixer/"


但在sinatra中,settings.root是应用程序目录的路径,所以:

$LOAD_PATH.unshift settings.root


这样,您就可以将应用程序移动到另一个目录,而无需更改任何内容。
或者,您可以从Dir[]返回的每个路径的前面删除lib/

require 'pathname'

paths = [
  "lib/house_distributer.rb", 
  "lib/distributer.rb", 
  "lib/mixer.rb", 
  "lib/accounting_service.rb", 
]

new_paths = paths.map do |path|
  pn = Pathname.new path
  pn.relative_path_from(pn.parent).to_s
end

p new_paths

--output:--
["house_distributer.rb", "distributer.rb", "mixer.rb", "accounting_service.rb"]

ux6nzvsh

ux6nzvsh2#

找不到文件是因为您使用的是"lib/*.rb"而不是./"lib/*.rb"
要确保以正确的顺序加载依赖项,可以执行以下操作:
1.将HouseDistributor移动到lib/distributor/house_distributor.rb
1.需要这样的文件:

Dir['./lib/**/*.rb']
.sort_by { |path| path.count("/") }
.each { |path| require path }

字符串
这将使用**/*.rb进行递归搜索,并在需要之前按“/”(它们的深度)的计数对文件进行排序。
需要注意的是,如果你在做递归require,请记住你实际上需要所有这些文件。例如,如果你使用ActiveRecord并且有一个schema.rb文件,你可能不想要求它。

8wtpewkr

8wtpewkr3#

其他2个答案在技术上是正确的,并解决了 * 目标 *,但不是 * 目的 。换句话说- * 你为什么要这样做? 例如,为什么这样做:
另外,由于以下原因,distributer.rb必须在house_distributer.rb之前加载:

class HouseDistributer < Distributer
end

字符串
而不是这个

require_relative "distributer.rb"
class HouseDistributer < Distributer
end


在测试中(* 咳嗽 )对不起, 规格 *:

# spec/house_distributer_spec.rb
require 'spec_helper'
require_relative "../lib/house_distributer.rb"

# spec/transaction_service_spec.rb
require 'spec_helper'
require_relative "../lib/transaction_service.rb"


由于transaction_service.rb似乎需要从lib/house_distributer.rb得到HouseDistributer.

# lib/transaction_service.rb
require_relative "house_distributer.rb"

经验法则

  • 如果一个文件需要另一个文件来运行,那么require(或require_relative)将其放在需要它的文件中。* 然后您会得到:
  • 一种自然的沙盒,只运行需要的东西(也许Distributer工作得很好,而HouseDistributer因为一个猴子补丁而出现错误-你怎么知道你的require文件实际上并不需要?)
  • 不需要在其他地方处理。
  • 不需要(或更不需要)知道需求的顺序。
  • 不需要摆弄加载路径(自从引入require_relative以来,这一直是一个可疑的需求)。
  • 更改加载路径,然后使用require可以打破沙箱,并使规范工作,应该通过加载您在系统上安装但在gemspec中没有定义为依赖项的gem来失败。

我想补充一点,也要使用Maple的沙箱,以避免进一步的错误,并让它处理你的加载路径,例如。
bundle install --binstubs --path=vendor(或Mac上的vendor.noindex),然后:
bin/rspec和你需要的任何命令行参数。

相关问题