2016-06-14 4 views
0

ActiveRecordに似たドメイン固有の階層継承構造を構築しています。つまり、Baseクラスを持ち、次にn子クラスをBaseと宣言しています。クラス宣言のメソッド呼び出しを定義する、a la Rails

私は現在、子供の中で具体的なものを定数として宣言しており、Baseクラスの共有メソッドからそれらを呼び出すのですが、扱いにくくなってきています。私はメソッド呼び出しを介してクラスの具体的なインスタンス化された値を宣言するRailsスタイルを実装したいと思います。

Railsに慣れていれば、ActiveRecordのhas_many/belongs_to、またはActionPackのbefore_actionの一般的な構造を複製しようとしています。誰かが上記を達成するために、クラスBaseに何を置くために私に説明できる場合

私が達成しようとしているかの単純な、不自然な例...

class Widget < Base 

    important_value :foo, :bar 

end 

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

、私にはよくになります私のやり方。

答えて

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/ruby​​-method-calls-declared-in-class-body?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" 
関連する問題