Techioz Blog

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

解決策

max pleaner の答えについての説明…

書くとき:

require 'lib/house_distributer.rb'

Ruby は、環境変数に割り当てられたディレクトリ内でファイルを検索します。は文字列の配列であり、各文字列はディレクトリへのパスです。配列内のディレクトリが順番に検索され、最初に一致したものが優先されます。

というディレクトリが含まれている場合:

'/Users/7stud/ruby_programs'

次に、上記の require ステートメントは絶対パスを持つファイルを検索します。

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

次のようにして、どのディレクトリがディレクトリにあるかを確認できます。

$ 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 './lib/house_distributer.rb'

この場合、ruby は現在の作業ディレクトリを基準にしてファイルを探します。ただし、現在の作業ディレクトリは、require ステートメントを含むファイルを含むディレクトリではない可能性があることに注意してください。たとえば、sinatra プログラムを別のディレクトリ (require ステートメントを含むファイルから 2 レベル上) から実行する場合、2 レベル上のディレクトリが現在の作業ディレクトリとなり、ruby はそのディレクトリを基準にして必要なファイルを検索します。 2 レベル上のディレクトリ。

「require_relative」と入力します。 require_relative は、現在の作業ディレクトリではなく、現在のファイルのパスに相対してファイルを検索します。

そのため、相対パスを指定した require は決して使用せず、代わりに require_relative を使用する必要があります。

いつでもプログラムでパスを追加できることに注意してください。

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

そして、そのディレクトリに Dog.rb というファイルがある場合は、次のように要求できます。

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