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 defininga 
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.