2012-03-03 29 views
3

如何让其他模块包含的模块在包含模块内查找常量?换句话说,我怎样才能让B.fooD.foo给出预期的结果?查看调用原始模块的模块

module A 
    module_function 
    public 
    def foo; C end 
end 
module B 
    extend A 
    C = "foo in B" 
end 
module D 
    extend A 
    C = "foo in D" 
end 

B.foo #=> (Expected) "foo in B" 
D.foo #=> (Expected) "foo in D" 

回答

3

你需要告诉它在哪里Aextend版在上下文中查找C

module A 
    def foo 
    self::C 
    end 
end 

module B 
    extend A 
    C = "foo in B" 
end 

module D 
    extend A 
    C = "foo in D" 
end 

B.foo #=> "foo in B" 
D.foo #=> "foo in D" 
+0

感谢您的回答。你能解释为什么'module_function'是不必要的吗? – sawa 2012-03-03 23:19:53

+1

@sawa,因为当你调用['Object#extend'](http://ruby-doc.org/core-1.9.3/Object.html#method-i-extend)时,你正在添加实例方法模块作为参数传递给接收器。如果接收者是一个Module对象,它的实例方法实际上就是“类方法”。 'module_function'使得它的方法被定义为模块的单例类(metaclass)上的实例方法。 – 2012-03-03 23:26:47

+1

@sawa据我所知,如果你打算在某个时候重新定义'A.foo','module_function'只会改变行为。而且也只有在模块混入类时才可能,而不是另一个模块。虽然我不是100%确定,因为我没有任何使用它的经验和[docs](http://www.ruby-doc.org/docs/ProgrammingRuby/html/ref_c_module.html#Module .module_function)没有特别的启发性。 (@MatheusMoreira先回复,我会顺从他) – 2012-03-03 23:28:00

2

我建议创建一个属性初始化可以由其他模块来使用:

module A 
    # This is actually executed in the context of each individual object. 
    # Since all modules and classes are also objects, each module extended 
    # by A gets to set its own state which the other methods can then use. 
    def attribute(*args) 
    @value = args.first if args.any? 
    @value || :default 
    end 

    def foo 
    attribute.to_s 
    end 
end 

module B 
    extend A 
    attribute :from_B 
end 

module C 
    extend A 
    attribute :from_C 
end 

module D 
    extend A 
end 

B.foo # => "from_B" 
C.foo # => "from_C" 
D.foo # => "default" 
+0

谢谢。我相信你会工作,但所需的编码似乎偏离我想要的。 – sawa 2012-03-03 23:22:30

+0

+1,因为即使它不是OP所要查找的,它仍然很好。 – 2012-03-03 23:29:39

0

你不能用常量做到这一点,因为他们不能被继承,但是你可以用方法:

module A 
    def foo 
    c 
    end 
end 

module B 
    extend A 
    def self.c 
    "foo in B" 
    end 
end 

module D 
    extend A 
    def self.c 
    "foo in D" 
    end 
end 

B.foo #=> "foo in B" 
D.foo #=> "foo in D" 
+1

在讨论模块时继承不是真正合适的词汇。 – 2012-03-03 23:16:12

+0

@Andrew - 当然可以。包括模块修改了祖先的链。 – nicholaides 2012-03-04 21:52:22