2011-09-12 49 views
1

或者,我该如何做到完美?如何在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的双打不会站出来吗?

回答

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 
+0

是的,我想这是一个隐藏在双层背后的类的想法不起作用的时刻。只需要学会忍受它。 –

0

如果你想foo是类Foo

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

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

,如果你定义的行为,你想在班什么的模块中,而不是?

或者也许包装类在一个模块?