How do I lazy evaluate yet-to-be-declared classes in Ruby?

Or, rather, how do I do it perfectly?

This is what I came up with so far:

# A double that stands in for a yet-to-be-defined class. Otherwise
# known as "lazy evaluation."
#
# Idea lifted from:
# http://github.com/soveran/ohm/
class Double < BasicObject
  def initialize(name)
    @name = name
  end

  def to_s
    @name.to_s
  end

  alias_method :inspect, :to_s

  def method_missing(mth, *args, &block)
    @unwrapped ? super : @unwrapped = true
    ::Kernel.const_get(@name).send(mth, *args, &block)
  ensure
    @unwrapped = false
  end; private :method_missing
end

This works:

foo = Double(:Foo)  # Now we can safely pass around Foo without 
                    # having initialised it.
foo.class           # Uninitialised constant
                    # That's expected because Foo doesn't exist yet!
class Foo; end      # So there, we shoo it into existence.
foo.class # Foo     # foo indeed is Foo. The sleight of hand of works.

This is what I can't get to work:

inst = Foo.new
inst.is_a? Foo      # true, of course
inst.is_a? foo      # TypeError: class or module required

Why won't the double stand in for Foo in the last line?

Answers


There's nothing wrong with your code - that's expected behavior. The #is_a? method expects a class or module. Try it with build-in classes and you get the same error:

str = "a string"
str.is_a? String
=> true

other_str = "another string"
str.is_a? other_str
=> TypeError: class or module required

If you want to change that you'll have to override is_a? (wouldn't recommend that). More likely, you want to do something like this:

str.is_a? other_str.class
=> true

If you want foo to be the class Foo:

foo = Foo
inst = Foo.new
inst.is_a? foo    #=> true

inst2 = foo.new
inst2.is_a? Foo   #=> true

What if you defined the behaviors you want in the class in a module instead?

Or perhaps wrapping the class in a module?


Need Your Help

Changing the default times in the Django TimeInput

python django

I am writing a small application in Django to help our training department manage training classes. I have a model called Schedule that holds the scheduled days for a specific class.