I love the autoload functionality of Ruby; however, it's going away in future versions of Ruby since it was never thread-safe.
So right now I would like to pretend it's already gone and write my code without it, by implementing the lazy-loading mechanism myself. I'd like to implement it in the simplest way possible (I don't care about thread-safety right now). Ruby should allow us to do this.
Let's start by augmenting a class' const_missing
:
class Dummy
def self.const_missing(const)
puts "const_missing(#{const.inspect})"
super(const)
end
end
Ruby will call this special method when we try to reference a constant under "Dummy" that's missing, for instance if we try to reference "Dummy::Hello", it will call const_missing
with the Symbol :Hello
. This is exactly what we need, so let's take it further:
class Dummy
def self.const_missing(const)
if :OAuth == const
require 'dummy/oauth'
const_get(const) # warning: possible endless loop!
else
super(const)
end
end
end
Now if we reference "Dummy::OAuth", it will require the "dummy/oauth.rb" file which is expected to define the "Dummy::OAuth" constant. There's a possibility of an endless loop when we call const_get
(since it can call const_missing
internally), but guarding against that is outside the scope of this question.
The big problem is, this whole solution breaks down if there exists a module named "OAuth" in the top-level namespace. Referencing "Dummy::OAuth" will skip its const_missing
and just return the "OAuth" from the top-level. Most Ruby implementations will also make a warning about this:
warning: toplevel constant OAuth referenced by Dummy::OAuth
This was reported as a problem way back in 2003 but I couldn't find evidence that the Ruby core team was ever concerned about this. Today, most popular Ruby implementations carry the same behavior.
The problem is that const_missing
is silently skipped in favor of a constant in the top-level namespace. This wouldn't happen if "Dummy::OAuth" was declared with Ruby's autoload
functionality. Any ideas how to work around this?