As the focus on multithreaded Ruby grows and grows, code autoloaders seem to be a less and less manageable solution. By the same token, it can be pretty ugly to manually require dozens of files or come up with complex schemes for requiring files.
Node.js has a pattern that I personally enjoy: if you require a directory, it will automatically look for a file called index.js
in that directory and require that if present. This, to me, presents a simple, usable way to manage complex require schemes. On a whim, I decided to see how easy it would be to implement such a pattern in Ruby. Turns out it’s not hard:
def require(path) super rescue LoadError => e searches = $:.map{|dir| File.join(dir, path)} searches.each do |search| if File.exist?(path + "/index.rb") return require path + "/index" end end raise e end
This implementation is simple, naive, and likely extremely dangerous in ways I don’t understand. What it does is simply take the path specified in the require
call and walk through the load path, looking for an index.rb
file in a directory denoted by the path. If it finds one, it requires that and returns. If it doesn’t, it raises the standard LoadError
.
I’m not an expert on Ruby’s file loading internals, which is why I spent five minutes making this hack method instead of trying to come up with an actual elegant solution. What I want to do, however, is start a conversation about whether this pattern makes sense or has a place in Rubyland. I think it would be nice to have a structure like this:
# In e.g. "application.rb" require 'app/models' # In app/models/index.rb require 'app/models/user' require 'app/models/post' # ...
It keeps everything explicit (I’ve become a big fan of explicit requires as opposed to directory or name-based autoloading) while still keeping a syntactically nice require call that describes what is happening quite well.
So what do you think? Is this a pattern worth exploring? Is this maybe a gem waiting to be written? Should it be made part of the core language? Let me know in the comments below or tweet @intridea with your thoughts!