在 Sinatra 中获取规范文件的更简单方法

问题描述 投票:0回答:3

我有一个

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
ruby sinatra
3个回答
4
投票

maxplener的回答的一些解释...

当你写下:

require 'lib/house_distributer.rb'

ruby 在分配给

$LOAD_PATH
环境变量的目录中查找文件。
$LOAD_PATH
是一个字符串数组,其中每个字符串都是一个目录的路径。按顺序搜索 $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_relative

require_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 

这样您就可以将应用程序移动到另一个目录而无需更改任何内容。

或者,您可以从

lib/

返回的每条路径的前面删除

Dir[]
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"]



2
投票
"lib/*.rb"

而不是

./"lib/*.rb"

为了确保依赖项以正确的顺序加载,您可以这样做:

    将 HouseDistributor 移至
  1. lib/distributor/house_distributor.rb

    
    

  2. 需要这样的文件:
  3. Dir['./lib/**/*.rb'] .sort_by { |path| path.count("/") } .each { |path| require path }

    这使用 
    **/*.rb

    进行递归搜索,并在需要之前按“/”(其深度)的数量对文件进行排序

    
    

  4. 请注意,如果您正在执行递归要求,请记住您实际上确实想要要求所有这些文件。例如,如果您正在使用 ActiveRecord 并且有一个 schema.rb 文件,您可能不希望需要它。


2
投票
目标

,但不是目标。换句话说 - 你为什么要这样做? 例如,为什么这样做:

另外注意,distribuner.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

似乎需要来自

HouseDistributer
lib/house_distributer.rb

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

经验法则

如果一个文件需要另一个文件来运行,则

require(或

require_relative
)将其放在需要它的文件中。
然后你会得到:

一种仅运行所需内容的自然沙箱(也许 Distributer 工作正常,而 HouseDistributer 由于猴子补丁而出现错误 - 你如何知道你是否
    require
  • 文件实际上并不需要?)
    无需在其他地方处理需求。
  • 不需要(或者更不需要)知道需求的顺序。
  • 无需摆弄加载路径(自从引入
  • require_relative
  • 以来,这一直是一个可疑的需求)。
    更改加载路径,然后使用 
  • require
  • 可能会破坏沙箱并使规范正常工作,但通过加载已安装在系统上但未在 gemspec 中定义为依赖项的 gem,该规范应该会失败。
    
    
    
  • 我想补充一下,也使用捆绑程序的沙箱,以避免进一步的错误并让它处理您的加载路径,例如

bundle install --binstubs --path=vendor

(或Mac上的vendor.noindex)然后:


bin/rspec

以及您需要的任何命令行参数。

    

© www.soinside.com 2019 - 2024. All rights reserved.