From: David Masover Date: 2011-06-17T16:33:29+09:00 Subject: Re: Kernel#autoload vs require_relative On Thursday, June 16, 2011 11:50:57 AM Piotr Szotkowski wrote: > Hm, I do prefer using require_relative over require + $LOAD_PATH > changes; it looks cleaner to me and doesn’t touch shared > globals, but I guess that’s more of a personal preference. So, while writing the rest of this (long) post, I think I actually dug up a solution for you, in the form of the 'autoloader' gem I wrote awhile back: https://github.com/masover/autoloader If everything in your 'lib' hierarchy is normally loaded via autoload, and follows a decent naming convention, I think this solves your problem. In your example, somewhere in 'lib/foo.rb', you could do this: require 'autoloader' AutoLoader << File.dirname(__FILE__) module Foo include AutoLoader end Ok, there's some __FILE__ ugliness, but in exchange, you automagically get 'autoload' statements generated for everything, and you don't have to modify your load path. Caveat: I wrote this awhile ago, when Merb was still a thing. It seems to still work, but you might still want to read it to understand what it does. It's not that long: https://github.com/masover/autoloader/blob/master/lib/autoloader.rb > What I was trying to ask is whether there couldn’t be > a Kernel#autoload_relative call or a ‘relative: true’ > optional parameter to Kernel#autoload to make it symmetric > with the require/require_relative combination... There is one thing I would _much_ rather have than this: Enough hooks into either the language or the autoload mechanism so that things like this are possible to do entirely inside Ruby. That is: Currently, we have const_missing, but it isn't called when someone tries to define a constant. For example, if I have Rails-style const_missing hacks, and I want to re-open a previously-defined module, I need to do this: Foo::Bar.module_eval do ... end instead of: module Foo module Bar ... end end The latter will never hit const_missing, and would thus never load foo.rb or whatever. And sure, if I'm re-opening Bar, I'm probably better off defining a separate module and forcing Bar to include it. But what if this is inside foo/bar.rb? Now if I say require 'foo/bar' I'll get Foo::Bar, but I won't ever load foo.rb -- whereas, say, Foo.module_eval do module Bar ... end end ...ew. Anyway, what I really want is something like: autoload :Foo do # block to ensure Foo is defined end In this case, autoload is the wrong word, but this would let me write the ultimate autoload-based replacement for the old Rails const_missing hack. What I have now is in the 'autoloader' gem: AutoLoader << '/path/to/lib' It will crawl 'lib' one level deep, take every '.rb' file, and create an 'autoload' tag for it. But in order to map Foo::Bar to 'foo/bar.rb', I still need the user to have a foo.rb file which does some extra work: module Foo include AutoLoader end I can't think of any way to make this work other than having some callback fire when the file actually gets loaded. Last I checked, Kernel#autoload would call 'require' from C when fired, so overloading 'require' doesn't help. And const_missing isn't a substitute, nor is there any way to duplicate Kernel#autoload's functionality from Ruby. I actually think autoloading via require_relative is a bad idea, versus just adding something to the load path. Some people think autoload itself is a bad idea. There are probably workarounds enough for both of us. But it does frustrate me that Kernel#autoload is so inflexible, and it really doesn't seem like it needs to be.