我如何懒惰地评估Ruby中尚未声明的类?

时间:2011-09-12 20:09:31

标签: ruby

或者说,我该如何完美地完成它?

这是我到目前为止所提出的:

# 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

这有效:

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.

这是我无法开展的工作:

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

为什么最后一行的Foo不会代表Foo?

3 个答案:

答案 0 :(得分:4)

您的代码没有任何问题 - 这是预期的行为。 #is_a?方法需要一个类或模块。尝试使用内置类,你会得到同样的错误:

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

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

如果你想改变它,你必须覆盖is_a? (不建议这样做)。更有可能的是,你想做这样的事情:

str.is_a? other_str.class
=> true

答案 1 :(得分:0)

如果您希望foo成为班级Foo

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

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

答案 2 :(得分:0)

如果您在模块中的类中定义了所需的行为,那该怎么办?

或者将课程包装在模块中?