2012-07-17 54 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