381

What's the best way to require all files from a directory in ruby ?

Gaetan Dubar
  • 4,538
  • 2
  • 27
  • 22

13 Answers13

498

How about:

Dir["/path/to/directory/*.rb"].each {|file| require file }
JasonSmith
  • 72,674
  • 22
  • 123
  • 149
Sam Stokes
  • 14,617
  • 7
  • 36
  • 33
  • 3
    You'll need to drop the .rb before requiring. Good other than that – rampion Apr 09 '09 at 17:27
  • 20
    According to the Pickaxe, the .rb extension is optional. Technically it changes the meaning: "require 'foo.rb'" requires foo.rb, whereas "require 'foo'" might require foo.rb, foo.so or foo.dll. – Sam Stokes Apr 09 '09 at 17:46
  • 29
    There's a subtle gotcha to not stripping the extension. If some other part of the code calls require 'foo' then ruby will load the same file again, which can lead to spurious errors. I added my own answer which explains that and shows how to strip the extension. – Pete Hodgson Feb 09 '10 at 18:40
  • 5
    @Pete, is this still true? See [Rene's comment](http://stackoverflow.com/questions/735073/best-way-to-require-all-files-from-a-directory-in-ruby#comment9237243_2231511) below. – Andres Riofrio Apr 17 '12 at 04:05
  • 5
    This might be obvious, but its worth noting that dropping the .rb will also require any non-.rb files in the dir, which might not be desired. – user2398029 Jun 18 '12 at 02:53
  • @louism I think the discussion is actually about dropping the `.rb` from the `require` portion: `Dir["/path/to/directory/*.rb"].each {|file| require file[0..-4] }` – JacobEvelyn Feb 15 '14 at 08:23
  • 12
    @PeteHodgson's suggestion is inaccurate. Ruby's `require` is not confused by the presence or absence of the `.rb` extension. Tested on MRI 1.8.7-p374, 2.1.5 and 2.2.0 tested. This urban legend comes from Rails, where "clever" autoloading exhibited the behaviour he describes in older versions (and may still exhibit it). – sheldonh Feb 25 '15 at 07:32
  • 2
    make sure to sort files first, for not introducing randomness caused by OS and keep require order deterministic: `Dir["/path/to/directory/*.rb"].sort.each {|file| require file }` – RngTng Mar 29 '16 at 14:23
  • even more concise would be: `Dir["/path/to/directory/*.rb"].each(&method(:require))` – Adverbly Feb 12 '19 at 15:37
366

If it's a directory relative to the file that does the requiring (e.g. you want to load all files in the lib directory):

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

Edit: Based on comments below, an updated version:

Dir[File.join(__dir__, 'lib', '*.rb')].each { |file| require file }
FeifanZ
  • 16,250
  • 7
  • 45
  • 84
jandot
  • 4,164
  • 1
  • 16
  • 10
  • 15
    You can also add all child directories like this `Dir[File.dirname(__FILE__) + '/support/**/*.rb'].each {|file| require file }` – jspooner Jul 05 '12 at 23:18
  • 64
    It's probably safer to use File.join rather than making assumptions about forward/backward slashes: `Dir[File.join(File.dirname(__FILE__), 'lib', '*.rb')].each {|file| require file }` – Chris Jul 06 '12 at 23:22
  • @ChristopherPatuzzo you are a live saver. I couldn't figure out why the files were never loaded. "\current\file\path/lib/*.rb" – grasingerm Oct 17 '12 at 18:59
  • 6
    There is also require_relative – maasha Feb 19 '14 at 12:28
  • 30
    If you're using >= ruby 2.0, you can use `__dir__` instead of `File.dirname(__FILE__)`. – Christian Bankester Apr 30 '14 at 21:05
  • 5
    @maasha How do you use `require_relative` to require all files in a directory? – David Moles Mar 17 '15 at 19:59
108

Try the require_all gem:

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

It lets you simply:

require_all 'path/to/directory'
  • I needed to include all of my ActiveRecord models, the require_all gem figured out all of the dependencies and required them perfectly. Thanks! – panupan Dec 07 '11 at 01:39
  • 3
    @panupan Just be aware that `require_all`'s cyclic dependency resolution works around a problem in your source code: you have Ruby source files that do not require their dependencies. This shuts the door on scalpel loading, committing you to all-or-nothing loading. That's not a problem in small libraries, but it's a decision you should be making consciously. – sheldonh Feb 25 '15 at 07:36
  • 7
    It doesn't have sense to bloat your app with gems that you can simply replace with a line of code. This increases the load time of your app and induces more bugs at long term. – Pere Joan Martorell Mar 15 '19 at 03:03
53
Dir[File.dirname(__FILE__) + '/../lib/*.rb'].each do |file| 
  require File.basename(file, File.extname(file))
end

If you don't strip the extension then you may end up requiring the same file twice (ruby won't realize that "foo" and "foo.rb" are the same file). Requiring the same file twice can lead to spurious warnings (e.g. "warning: already initialized constant").

Pete Hodgson
  • 15,644
  • 5
  • 38
  • 46
  • 11
    Is this really the case? Documentation says: A feature will not be loaded if its name already appears in $". The file name is converted to an absolute path, so "require 'a'; require './a'" will not load a.rb twice. http://www.ruby-doc.org/core/classes/Kernel.html#M001418 – Derek Jan 29 '11 at 17:47
  • 15
    My testing shows the same that Derek said: `require "foo.rb"; require "foo";` will load `foo.rb` just once. – Rene Saarsoo Sep 30 '11 at 14:06
  • 1
    @PeteHodgson- Can you back this up? – Yarin Oct 31 '13 at 13:31
  • 5
    No. Ruby's `require` is not confused by the presence or absence of the `.rb` extension. Tested on MRI 1.8.7-p374, 2.1.5 and 2.2.0. This urban legend comes from Rails, where "clever" autoloading exhibited the behaviour described in older versions (and may still exhibit it). – sheldonh Feb 25 '15 at 07:32
49
Dir.glob(File.join('path', '**', '*.rb'), &method(:require))

or alternatively, if you want to scope the files to load to specific folders:

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

explanation:

Dir.glob takes a block as argument.

method(:require) will return the require method.

&method(:require) will convert the method to a bloc.

magicgregz
  • 7,471
  • 3
  • 35
  • 27
  • 2
    This is some beautiful code. I love how there are no visible blocks. – Nate Symer Apr 28 '14 at 01:39
  • 1
    `Dir.glob( File.join( File.dirname(__FILE__), '{lib,addons}', 'subfolder', '**', '*.rb' ), &method(:require) )` eliminates dependence on platform (such as '/' or '\'). Works well. Thanks. – Ivan Black Jul 10 '14 at 14:55
36

The best way is to add the directory to the load path and then require the basename of each file. This is because you want to avoid accidentally requiring the same file twice -- often not the intended behavior. Whether a file will be loaded or not is dependent on whether require has seen the path passed to it before. For example, this simple irb session shows that you can mistakenly require and load the same file twice.

$ 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

Note that the first two lines return true meaning the same file was loaded both times. When paths are used, even if the paths point to the same location, require doesn't know that the file was already required.

Here instead, we add a directory to the load path and then require the basename of each *.rb file within.

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

If you don't care about the file being required more than once, or your intention is just to load the contents of the file, perhaps load should be used instead of require. Use load in this case, because it better expresses what you're trying to accomplish. For example:

Dir["/path/to/directory/*.rb"].each {|file| load file }
Ryan McGeary
  • 235,892
  • 13
  • 95
  • 104
  • 1
    This seems to be the best solution to require all files while avoiding any accidental double requiring of files - and should be marked as the accepted answer ... – Mayinx Oct 08 '20 at 19:29
  • I feel like something has changed since 2009. `require` now needs `./` and `require_relative` realises those are paths to the same file. – Nakilon Nov 28 '21 at 02:34
17

Instead of concatenating paths like in some answers, I use File.expand_path:

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

Update:

Instead of using File.dirname you could do the following:

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

Where .. strips the filename of __FILE__.

Koen.
  • 25,449
  • 7
  • 83
  • 78
  • this seems definitely the way to go, and most up to date answer, after trying all the rest, +1 for `File.expand_path` – mswieboda May 30 '14 at 04:26
  • I definitely prefer this answer to the accepted one. Various `Rails.root.join` answers also work if you're in rails. – nzifnab Oct 06 '14 at 23:05
17
Dir[File.join(__dir__, "/app/**/*.rb")].each do |file|
  require file
end

This will work recursively on your local machine and a remote (Like Heroku) which does not use relative paths.

shushugah
  • 180
  • 1
  • 9
8

In Rails, you can do:

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

Update: Corrected with suggestion of @Jiggneshh Gohel to remove slashes.

Dan Kohn
  • 33,811
  • 9
  • 84
  • 100
  • Since `Rails.root` is a [`Pathname`](http://ruby-doc.org/stdlib/libdoc/pathname/rdoc/index.html) instance, you can do this in any Ruby environment, not just Rails (N.B. `Rails.root.join('lib/ext/*.rb')` reads a little nicer) – DMKE Sep 25 '14 at 22:00
  • Thanks for the recommendation; I edited to include your comment. – Dan Kohn Sep 26 '14 at 02:24
  • Using a forward slash (/) for sub-directories under Rails.root, for e.g. `Rails.root.join('/lib')` doesn't generate correct path. I found this one to work correctly: `Dir[Rails.root.join('lib', 'ext', '*.rb')].each { |file| require file }` – Jignesh Gohel Jul 17 '15 at 12:46
  • @Jiggneshh Gohel I removed slashes as you suggested, thanks. – Dan Kohn Nov 04 '15 at 18:14
3

I'm a few years late to the party, but I kind of like this one-line solution I used to get rails to include everything in app/workers/concerns:

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

Jazz
  • 1,435
  • 1
  • 15
  • 23
1

For Ruby older than 3.0, Rubocop warns against the accepted answer because load order is not deterministic for all OSes. Linux sorts upper and lower case differently than Mac or Windows. The following does what the OP requested for all versions of Ruby:

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

The following recurses through all subdirectories for all versions of Ruby:

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

Ruby 3.0 and later sort files consistently, so the following is all that is needed if you know that older Ruby versions will never be used:

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

The following recurses through all subdirectories for Ruby 3.0 and later:

Dir['/path/to/directory/**/*.rb'].each { |file| require file }
Mike Slinn
  • 7,705
  • 5
  • 51
  • 85
0

All these answers are great. To add, if you want to do this automagically, you can use Zeitwerk, which is what Rails uses to load files.

require 'zeitwerk'
loader = Zeitwerk::Loader.new
loader.push_dir('main/src/dir')
loader.setup

Then everything has access to everything

MGreenfield
  • 355
  • 1
  • 13
-2

And what about: require_relative *Dir['relative path']?

  • 1
    Require relative doesn't take multiple files: http://ruby-doc.org/core-2.1.2/Kernel.html#method-i-require_relative – fabriciofreitag Apr 21 '17 at 10:30
  • OK, but in my example it isn't. The '*' changes arity to 1. It works as multiple call to require_relative. – Aleksander May 10 '17 at 08:07
  • 1
    _The '*' changes arity to 1_ - What do you mean with it? `require_relative *Dir['*.rb']` work, if there is only one ruby-script. But if multiple ruby scripts are found, you get `require_relative': wrong number of arguments (4 for 1) (ArgumentError)` – knut May 25 '17 at 12:53