2016-06-14 18 views
0

我正在構建一個類似於ActiveRecord的域特定的層次繼承結構,即我有一個Base類,然後n子類在Base下聲明。定義類聲明的方法調用Rails

我目前在兒童中聲明瞭具體細節作爲常量,然後調用Base類中的共享方法,但它變得笨拙。我想通過方法調用實現聲明類特定的實例化值的Rails風格。

如果您熟悉Rails,我基本上試圖複製ActiveRecord中的has_many/belongs_to或ActionPack中的before_action的通用結構。

的什麼,我試圖完成一個簡單的,人爲的例子...

class Widget < Base 

    important_value :foo, :bar 

end 

widget = Widget.new 
widget.foo 
# => :bar 

如果有人能向我解釋要放什麼Base類來實現上述目標,我會很好的我的方式。

回答

1
class Base 
    class << self 
    def important_value(key, value) 
     # define method named `key` which returns `value` 
     define_method(key) { value } 
    end 
    end 
end 

class Widget < Base 
    important_value :foo, :bar 
end 

Widget.new.foo # => :bar 

或者,如果「重要價值」的方法數小且事先知道:

class Base 
    def foo 
    self.class.foo 
    end 

    class << self 
    attr_reader :foo 

    def important_value(key, value) 
     self.instance_variable_set(:"@#{key}", value) 
    end 
    end 
end 

class Widget < Base 
    important_value :foo, :bar 
end 

Widget.new.foo # => :bar 
+0

所以它真的和調用聲明中的類方法一樣簡單嗎?我希望更多的反思是必需的,但看着這個,它有多少意義,我真的不知道爲什麼... –

+1

與幾個有用的答案 - 類似的問題陷入了一遍 - http://stackoverflow.com/questions/1344797 /紅寶石方法通話申報的一流體?RQ = 1 –

0

這並不精確匹配我原來的問題的條件,但它是非常有幫助讓我感動。

class Base 

    # defining variables happens at the class level 
    # the first line allows us to set a sane default (skip for a nil value) 
    # the second line makes the method a getter as well as a setter (this is required) 
    def self.title(val = nil) 
    @title ||= 'DEFAULT TITLE' 
    return @title if val.nil? 
    @title = val.upcase 
    end 

    # the instance-level reader 
    # if you want to change the values from the child, use attr_accessor 
    # in either case, the visibility of @title in the child is unchanged (we assume its not accessed directly) 
    attr_reader :title 

    # set the instance variable when the class is instantiated 
    def initialize 
    instance_variable_set("@title", self.class.title) 
    end 

end 

class Foo < Base 
    title "foo title" 
end 

class Bar < Base 
    # if left commented out, the value will be set to 'DEFAULT TITLE' 
    # title "BAR TITLE" 
end 

f = Foo.new 
f.title 
# => "FOO TITLE" 

b = Bar.new 
b.title 
# => "DEFAULT TITLE"