更容易在Sinatra中需要spec文件的方法

时间:2018-01-30 07:49:05

标签: ruby sinatra

我的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

3 个答案:

答案 0 :(得分:4)

对最大辩护人答案的一些解释......

当你写:

require 'lib/house_distributer.rb'

ruby​​在分配给$LOAD_PATH环境变量的目录中查找该文件。 $LOAD_PATH是一个字符串数组,其中每个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是您的app目录的路径,所以:

$LOAD_PATH.unshift setttings.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"]

答案 1 :(得分:2)

找不到文件是因为您使用的是defmodule MyApp.Guardian do use Guardian, otp_app: :my_app def subject_for_token(resource, _claims) do sub = to_string(resource.id) {:ok, sub} end def subject_for_token(_, _) do {:error, :reason_for_error} end def resource_from_claims(claims) do resource = %{id: 1} {:ok, resource} end def resource_from_claims(_claims) do {:error, :reason_for_error} end def after_encode_and_sign(resource, claims, token, _options) do with {:ok, _} <- Guardian.DB.after_encode_and_sign(resource, claims["typ"], claims, token) do {:ok, token} else whatever -> IO.inspect whatever end end def on_verify(claims, token, _options) do with {:ok, _} <- Guardian.DB.on_verify(claims, token) do {:ok, claims} end end def on_revoke(claims, token, _options) do with {:ok, _} <- Guardian.DB.on_revoke(claims, token) do {:ok, claims} end end end 而不是"lib/*.rb"

要确保以正确的顺序加载依赖项,您可以执行以下操作:

  1. 将HouseDistributor移至./"lib/*.rb"

  2. 需要这样的文件:

    lib/distributor/house_distributor.rb

    这使用Dir['./lib/**/*.rb'] .sort_by { |path| path.count("/") } .each { |path| require path } 进行递归搜索,并按照&#34; /&#34;的计数对文件进行排序。 (他们的深度)在要求

  3. 之前

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

答案 2 :(得分:2)

其他2个答案在技术上是正确的并且解决目标而不是目标。换句话说 - 你为什么要这样做呢? 例如,为什么这样做:

  

另外注意,distributer.rb必须在house_distributer.rb之前加载,因为:

class HouseDistributer < Distributer
end

而不是这个?

require_relative "distributer.rb"
class HouseDistributer < Distributer
end

在测试中( cough )抱歉, specs

# 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的{​​{1}} ...

lib/house_distributer.rb

经验法则

如果某个文件需要另一个文件运行,那么# lib/transaction_service.rb require_relative "house_distributer.rb" (或require)就会在需要它的文件中运行。然后你得到:

  • 一种天然的沙盒,只运行所需的东西(可能是Distributer完美运行,HouseDistributer因猴子补丁而出错)你怎么知道你require_relative文件是否真的需要?)
  • 无需在其他地方处理。
  • 不需要(或更少需要)知道要求的顺序。
  • 无需摆弄负载路径(自require引入以来一直是一个可疑的需求)。
  • 更改加载路径然后使用require_relative可能会破坏沙盒并使规格工作失败,方法是加载已安装在系统上的gem,但未在gemspec中定义为依赖项。< / LI>

我添加,也使用捆绑器的沙盒,以避免进一步的错误,让它处理你的负载路径,例如。

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

bundle install --binstubs --path=vendor以及你需要的任何命令行args。