Rubyのディレクトリからすべてのファイルを要求する最良の方法は?


351

ルビーのディレクトリからすべてのファイルを要求する最良の方法は何ですか?


ディレクトリと同じ名前のファイルを作成して、すべてのファイルを要求させることができます。RSpecはこれを行います。
pedromanoel 2018

回答:


462

どうですか:

Dir["/path/to/directory/*.rb"].each {|file| require file }

18
つるはしによると、.rb拡張子はオプションです。技術的には、「require 'foo.rb'」にはfoo.rbが必要ですが、「require 'foo'」にはfoo.rb、foo.so、またはfoo.dllが必要になる場合があります。
Sam Stokes

28
拡張機能を削除しないという微妙な問題があります。コード呼び出しの他の部分で 'foo'が必要な場合、rubyは同じファイルを再度ロードするため、偽のエラーが発生する可能性があります。私はそれを説明し、拡張機能を取り除く方法を示す自分の答えを追加しました。
ピートホジソン

4
@ピート、これはまだ本当ですか?以下のルネのコメントを参照してください。
Andres Riofrio 2012

5
これは明白かもしれませんが、.rbをドロップする場合、dirに.rb以外のファイルも必要になるため、望ましくない可能性があることに注意してください。
user2398029

10
@PeteHodgsonの提案は不正確です。Ruby requireは、.rb拡張機能の有無に混乱しない。MRI 1.8.7-p374、2.1.5、2.2.0でテスト済み。この都市の伝説はRailsに由来し、「賢い」オートローディングは彼が以前のバージョンで説明している動作を示しました(そしてそれをまだ表示している可能性があります)。
sheldonh 2015

345

それが必要とするファイルに関連するディレクトリである場合(たとえば、libディレクトリ内のすべてのファイルをロードしたい場合):

Dir[File.dirname(__FILE__) + '/lib/*.rb'].each {|file| require file }

編集:以下のコメントに基づいて、更新されたバージョン:

Dir[File.join(__dir__, 'lib', '*.rb')].each { |file| require file }

14
次のようにすべての子ディレクトリを追加することもできますDir[File.dirname(__FILE__) + '/support/**/*.rb'].each {|file| require file }
jspooner

62
それはむしろ、前方/後方スラッシュについての仮定を作るよりも、File.joinを使用するために、おそらくほうが安全です:Dir[File.join(File.dirname(__FILE__), 'lib', '*.rb')].each {|file| require file }
クリス・

6
require_relativeもあります
maasha '19

30
> = ruby​​ 2.0を使用している場合は、の__dir__代わりに使用できますFile.dirname(__FILE__)
クリスチャンバンケスター2014

3
@maasha require_relativeディレクトリ内のすべてのファイルを要求するにはどのように使用しますか?
David Moles

101

require_all gemを試してください:

  1. http://github.com/jarmo/require_all
  2. https://rubygems.org/gems/require_all

それはあなたに簡単にさせます:

require_all 'path/to/directory'

私はすべてのActiveRecordモデルを含める必要があり、require_all gemはすべての依存関係を把握し、それらを完全に要求しました。ありがとう!
パヌパン

2
@panupan require_allの循環的な依存関係の解決は、ソースコードの問題を回避することに注意してください。依存関係を必要としないRubyソースファイルがあります。これにより、メスの読み込みのドアが閉まり、オールオアナッシングの読み込みが行われます。これは小さなライブラリでは問題ではありませんが、意識的に行うべき決定です。
sheldonh 2015

単純にコード行で置き換えることができる宝石でアプリを膨らませても意味がありません。これにより、アプリの読み込み時間が長くなり、長期的にはより多くのバグが発生します。
ペールジョーン

52
Dir[File.dirname(__FILE__) + '/../lib/*.rb'].each do |file| 
  require File.basename(file, File.extname(file))
end

拡張子を取り除かないと、同じファイルが2回必要になる可能性があります(Rubyは「foo」と「foo.rb」が同じファイルであることを認識しません)。同じファイルを2回要求すると、誤った警告(「警告:すでに初期化された定数」など)が発生する可能性があります。


11
これは本当ですか?ドキュメンテーションは言う:その名前がす​​でに$にある場合、機能はロードされません。ファイル名は絶対パスに変換されるため、「require 'a'; require './a' "はa.rbを2回ロードしません。ruby
Derek

13
私のテストを示しデレクが言っていることと同じ:require "foo.rb"; require "foo";ロードされますfoo.rb一度だけ。
Rene Saarsoo、2011

@ PeteHodgson-これをバックアップできますか?
Yarin 2013年

4
いいえ。Ruby require.rb拡張機能の有無によって混乱することはありません。MRI 1.8.7-p374、2.1.5および2.2.0でテスト済み。この都市の伝説はRailsに由来し、「巧妙な」オートローディングは古いバージョンで説明されている動作を示しました(それでもそれを示す場合があります)。
sheldonh 2015

45
Dir.glob(File.join('path', '**', '*.rb'), &method(:require))

または、特定のフォルダにロードするファイルのスコープを設定する場合:

Dir.glob(File.join('path', '{folder1,folder2}', '**', '*.rb'), &method(:require))

説明:

Dir.globはブロックを引数として受け取ります。

method(:require)はrequireメソッドを返します。

&method(:require)は、メソッドをブロックに変換します。


2
これは美しいコードです。目に見えるブロックがないのが大好きです。
Nate Symer 2014

1
Dir.glob( File.join( File.dirname(__FILE__), '{lib,addons}', 'subfolder', '**', '*.rb' ), &method(:require) )プラットフォームへの依存を排除​​します( '/'や '\'など)。うまくいきます。ありがとう。
Ivan Black

30

最善の方法は、ディレクトリをロードパスに追加してから、require各ファイルのベース名を追加することです。これは、同じファイルを誤って2回必要としないようにするためです(多くの場合、意図した動作ではありません)。ファイルがロードされるかどうかrequireは、パスが以前に渡されたことがあるかどうかによって異なります。たとえば、この単純なirbセッションは、同じファイルを誤って要求し、2回ロードする可能性があることを示しています。

$ irb
irb(main):001:0> require 'test'
=> true
irb(main):002:0> require './test'
=> true
irb(main):003:0> require './test.rb'
=> false
irb(main):004:0> require 'test'
=> false

最初の2行trueは同じファイルが両方ともロードされたことを意味することに注意してください。パスが使用されている場合、パスが同じ場所を指してrequireいても、ファイルがすでに必要であることがわかりません。

ここでは代わりに、ロードパスにディレクトリを追加し、その中にある各* .rbファイルのベース名を要求します。

dir = "/path/to/directory"
$LOAD_PATH.unshift(dir)
Dir[File.join(dir, "*.rb")].each {|file| require File.basename(file) }

ファイルが2回以上必要になることを気にしない場合、またはファイルのコンテンツをロードするだけの場合は、のload代わりに使用する必要がありrequireます。この場合は、loadを使用してください。これは、達成しようとしていることをよりよく表現するためです。例えば:

Dir["/path/to/directory/*.rb"].each {|file| load file }

14

いくつかの回答のようにパスを連結する代わりに、私はFile.expand_path次を使用します:

Dir[File.expand_path('importers/*.rb', File.dirname(__FILE__))].each do |file|
  require file
end

更新:

を使用File.dirnameする代わりに、次のことを行うことができます。

Dir[File.expand_path('../importers/*.rb', __FILE__)].each do |file|
  require file
end

はの..ファイル名を取り除きます__FILE__


これは間違いなく進むべき道であり、残りすべてを試した後の最新の答えです、+ 1File.expand_path
SuckerForMayhem 2014年

私は間違いなく、この答えを受け入れられたものよりも好みます。Rails.root.joinレールにいる場合も、さまざまな回答が機能します。
nzifnab 2014年

14
Dir[File.join(__dir__, "/app/**/*.rb")].each do |file|
  require file
end

これは、ローカルマシンと、相対パスを使用しないリモート(Herokuなど)で再帰的に機能します。


8

Railsでは、次のことができます。

Dir[Rails.root.join('lib', 'ext', '*.rb')].each { |file| require file }

更新:@Jiggneshh Gohelの提案によりスラッシュを削除するように修正されました。


Rails.rootPathnameインスタンスなので、これはRailsだけでなく任意のRuby環境で実行できます(NB Rails.root.join('lib/ext/*.rb')は少し
優れています

推薦ありがとうございます。コメントを含めるように編集しました。
Dan Kohn 2014

たとえば、Rails.rootの下のサブディレクトリにスラッシュ(/)を使用すると、Rails.root.join('/lib')正しいパスが生成されません。私はこれが正しく機能することを発見しました:Dir[Rails.root.join('lib', 'ext', '*.rb')].each { |file| require file }
Jignesh Gohel

@Jiggneshh Gohelありがとうございます。
Dan Kohn

3

私はパーティーに数年遅れていますが、私はレールを取得してアプリ/ワーカー/懸念事項にすべてを含めるために使用していた次のような1行のソリューションが好きです。

Dir[ Rails.root.join *%w(app workers concerns *) ].each{ |f| require f }


-2

そして、どうrequire_relative *Dir['relative path']ですか?



わかりましたが、私の例ではそうではありません。「*」はアリティを1に変更します。require_relativeへの複数の呼び出しとして機能します。
Aleksander

1
「*」はアリティを1に変更します-それはどういう意味ですか?require_relative *Dir['*.rb']ルビスクリプトが1つしかない場合は機能します。複数のRubyスクリプトが検出された場合でも、あなたが得るrequire_relative': wrong number of arguments (4 for 1) (ArgumentError)
クヌート
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.