2012-07-17 55 views
5

在Ruby中,我试图创建一个类,它基于初始化期间给定的值将从下列模块之一继承。我想创建一个基本模块,这两个模块都继承自那些包含常用方法的常用方法,这些方法使用继承它的模块中定义的常量。例如:在Ruby模块中继承常量

module BaseMod 
    def what_am_i 
    puts OUTPUT 
    end 
end 

module Tall 
    OUTPUT = "I am tall" 
    include BaseMod 
end 

module Short 
    OUTPUT = "I am short" 
    include BaseMod 
end 

class Person 
    def initialize type 
    if type =~ /short/i 
     extend Short 
    else 
     extend Tall 
    end 
    end 
end 

p = Person.new "short" 
p.what_am_i 

我的问题是,当“p.what_am_i”叫我收到以下错误:

NameError: uninitialized constant BaseMod::OUTPUT 
    const_missing at org/jruby/RubyModule.java:2642 
     what_am_i at test_logic2.rb:3 
     (root) at test_logic2.rb:28 

我也想知道如果有一个更好的方式去这样做。

回答

2

要获得你的情况,你有固定的写是这样的:

module Tall 
::OUTPUT = "I am tall" 
include BaseMod 
end 

不过,请注意,您正在重新定义常量与模块短的声明。为此,你将永远得到“我很短”。

因此,要正确地做到这一点,你应该尝试:

module BaseMod 
OUTPUT="Before" 
def what_am_i 
    puts OUTPUT 
end 
end 

module Tall 
def self.extended(k) 
    OUTPUT.replace "I am tall" 
end 
include BaseMod 
end 

module Short 
def self.extended(k) 
    OUTPUT.replace "I am short" 
end 
include BaseMod 
end 

ķ

0

看来,当你的消息的人员P与#what_am_i消息,解释寻找方法实现连续的较高和在类祖先中更高,并最终在BaseMod中找到它,但在该级别,OUTPUT常量不再被定义。所以我认为Ruby继续寻找OUTPUT常量向上的层次结构,但不考虑向下看,在Tall和Short模块中定义。士气高昂,即使你包含了许多子模块,他们也不会进入一个所有常量都可以被所有人访问的堆,而是他们保持它们的层次结构与它们包含的相反顺序(见Tall.Ancestors)。在任何级别,只能访问相同级别或更高级别的常量。我会用以下方式解决你的问题:

module Personhood 
    def what_am_i; @output end 
end 

class Tall 
    include Personhood 
    def initialize 
     @output = "I am tall" 
    end 
    end 
end 

class Short 
    include Personhood 
    def initialize 
     @output = "I am short" 
    end 
    end 
end 

def Person(type) 
    if type =~ /short/i 
    Short.new 
    else 
    Tall.new 
    end 
end 

pete = Person "short" 
pete.what_am_i 
=> I am short 

我处理了一个常量,以支持实例变量。在Ruby中,无论如何都没有真正的常量。 “高”和“矮”是由类构成的,“人”是构造函数方法,根据其输入返回高或短类。这就是我觉得应该完成的。

1

我打算再带上一个选项。我不太清楚你的复杂,现实世界的情况是什么,所以这里是我的选择:

module BaseMod 
    def what_am_i 
    puts output 
    end 
end 

module Tall 
    include BaseMod 
    def self.extended klass 
    define_method :output do 
     "I am tall" 
    end 
    end 
end 

module Short 
    include BaseMod 
    def self.extended klass 
    define_method :output do 
     "I am short" 
    end 
    end 
end 

class Person 
    def initialize type 
    extend (type =~ /short/i ? Short : Tall) # Because I didn't wanna type all those lines 
    end 
end 

p = Person.new "short" 
p.what_am_i 

请注意,这种情况下,你可以很容易地做到这一点:

module Tall 
    include BaseMod 
    def output 
    "I am tall" 
    end 
end 

但我不知道这对你是否真的有帮助。

+0

这样做的有趣的方式。 – 2012-07-18 03:26:56

+0

@BorisStitnicky根据你想要构建的方法,一个方法可能比实例变量更有意义。 YMMV :) – Trevoke 2012-07-18 13:35:30

4
module BaseMod 
    def what_am_i 
    puts self.class::OUTPUT 
    end 
end 

module Tall 
    OUTPUT = "I am tall" 
    include BaseMod 
end 

module Short 
    OUTPUT = "I am short" 
    include BaseMod 
end 

class Person 
    def initialize(type) 
    if type =~ /short/i 
     self.class.send(:include, Short) 
    else 
     self.class.send(:include, Tall) 
    end 
    end 
end 

p = Person.new "short" 
p.what_am_i 

编辑:上面的代码不实际工作:

p = Person.new "short" 
p.what_am_i 
>> I am short 
p = Person.new "tall" 
p.what_am_i 
>> I am tall 
p = Person.new "short" 
p.what_am_i 
>> I am tall 

这里是另一个尝试:

module BaseMod 
    def self.included(base) 
    base.send(:define_method, :what_am_i) do 
     puts base::OUTPUT 
    end 
    end 
end 

module Tall 
    OUTPUT = "I am tall" 
    include BaseMod 
end 

module Short 
    OUTPUT = "I am short" 
    include BaseMod 
end 

class Person 
    def initialize type 
    if type =~ /short/i 
     extend Short 
    else 
     extend Tall 
    end 
    end 
end 

p = Person.new "short" 
p.what_am_i 
p = Person.new "tall" 
p.what_am_i 
p = Person.new "short" 
p.what_am_i 
+0

好戏,谢谢。但个人而言,作为设计选择,我仍然避免在这种情况下使用常量。 – 2012-07-18 03:26:16

+0

我可以看到它。从“高”和“短”模块的角度来看,这些常量是合适的。从Person的角度来看,这个常数很奇怪,但这不是what_am_i方法应该生活的地方。无论如何,我的代码无法正常工作,所以我添加了另一个解决方案。 – 2012-07-20 14:36:41

+0

我明白了。我没有尝试,所以我没有注意到它没有工作:) – 2012-07-22 16:18:37