2012-05-02 1 views
2

私はattr_accessorと同じことをし(クラス)メソッドattr_accessor_with_client_resetを、実装したいが、それはさらにそうルービーでattr_accessorを強化する方法は?

@client = nil 

を実行し、すべてのライターに、例えば、

attr_accessor_with_client_reset :foo 

を生成する必要があります

と同じ結果です。
attr_reader :foo 

def foo=(value) 
    @foo = value 
    @client = nil 
end 

どうすればよいですか?

+1

何か試しましたか? –

+0

ええ、私はしましたが、私は再び試したときに動作するので、私はタイプミスをしたと思います。あなたは正しい、私はそれを投稿しておくべきだった。 –

答えて

6

セルジオのソリューションは良いですが、不必要に複雑です:attr_readerの動作を複製する必要はありません。ただ委任するだけです。そして、この二重のモジュールにフックのハッカーを含める必要はありません。さらに、attr_accessorは複数の名前を取るので、attr_accessor_with_client_resetも同じ名前にする必要があります。

module AttrAccessorWithClientReset 
    def attr_accessor_with_client_reset(*names) 
    attr_reader *names 

    names.each do |name| 
     define_method :"#{name}=" do |v| 
     instance_variable_set(:"@#{name}", v) 
     @client = nil 
     end 
    end 
    end 
end 

class Foo 
    extend AttrAccessorWithClientReset 

    attr_reader :client 
    def initialize 
    @foo = 0 
    @client = 'client' 
    end 

    attr_accessor_with_client_reset :foo 
end 

f = Foo.new 
f.foo # => 0 
f.client # => "client" 
f.foo = 1 
f.foo # => 1 
f.client # => nil 
+0

申し訳ありませんが、 'base.extend ClassMethods'が自動的に出てきます:) + 1'd –

+0

BTW、' define_method'とcoはシンボルだけでなく文字列も受け入れています。なぜあなたはここでシンボルを使用していますか?私にとっては不要な視覚的ノイズです。 –

+0

私は彼らが自動的に出てくると思います:-) 'Symbol'sは名前を表しています。実際には、Rubyインタプリタ/コンパイラのシンボルテーブルのエントリを表します。まさにメソッド名と同じものです。だから、私にとっては意味的に「正しい」と感じるだけです。それはおそらくもっと味の問題です。 –

1

ルビーメタプログラミングの経験があれば、実際はかなり簡単です。見てみましょう:Metaprogramming Ruby:このコードはあなたに完全に明確ではありません

module Ext 
    def self.included base 
    base.extend ClassMethods 
    end 

    module ClassMethods 
    def attr_accessor_with_client_reset name 
     define_method name do 
     instance_variable_get "@#{name}" 
     end 

     define_method "#{name}=" do |v| 
     instance_variable_set "@#{name}", v 
     @client = nil 
     end 
    end 
    end 

end 

class Foo 
    include Ext 

    attr_reader :client 
    def initialize 
    @foo = 0 
    @client = 'client' 
    end 

    attr_accessor_with_client_reset :foo 
end 

f = Foo.new 
f.foo # => 0 
f.client # => "client" 
f.foo = 1 
f.foo # => 1 
f.client # => nil 

場合、私は強くこの本をお勧めします。

関連する問題