2009-11-14 10 views
12

私はinstance_evalの後にattr_accessorの中にinitializeを入れようとしています。私はこれを続けます。 ``初期化する ':未定義のメソッド' attr_accessor '`。なぜこれは機能しないのですか?初期化の内部でattr_accessorを使用できないのはなぜですか?

コードは一種の次のようになります。

class MyClass 
    def initialize(*args) 
     instance_eval "attr_accessor :#{sym}" 
    end 
end 

答えて

20

attr_accessorは、MyClassのインスタンスメソッドとして定義されていないので、あなたは、インスタンス上でattr_accessor呼び出すことはできません。モジュールとクラスでのみ利用可能です。

class MyClass 
    def initialize(varname) 
    class <<self 
     self 
    end.class_eval do 
     attr_accessor varname 
    end 
    end 
end 

o1 = MyClass.new(:foo) 
o2 = MyClass.new(:bar) 
o1.foo = "foo" # works 
o2.bar = "bar" # works 
o2.foo = "baz" # does not work 
+0

class_evalメソッドはそれを置くと同じであるシンボルであると仮定するとあなたが自己書いたところ – johannes

+4

いいえ、そうではありません。 'class << self; ...; end'はクロージャではありません。その内部で 'varname'にアクセスすることはできませんが、' class_eval'ブロックでアクセスできます。 – sepp2k

+0

[半数の答え](http://stackoverflow.com/a/14978624/403664)が良いです。見てみな。 –

4

クリーナー実装(NB:これは、クラスのすべてのインスタンスにアクセサを追加するだけではなく、単一のインスタンス、以下のコメントを参照してください、私はこのように、あなたは、インスタンスのメタクラスにattr_accessor呼び出したい疑います):

class MyClass 
    def initialize(varname) 
    self.class.send(:attr_accessor, varname) 
    end 
end 
+6

これは、アクセサを 'MyClass'のインスタンスメソッドとして定義します。したがって、 'o1 = MyClass.new(:foo)'と 'o2 = MyClass.new(:bar)'を持つ場合、 'o1'と' o2'の両方に 'foo'と' bar'のためのアクセサがあります。意図された動作。 – sepp2k

+0

かなり正しい!ここに私の上船がある。私はそれを見いだすかもしれない人のために(あなたのコメントと共に)この答えを残します。 –

+0

ロブのソリューションは、はるかにきれいに見えます。しかし、私はsepp2kのソリューションに固執します。 – JAkk

4

ロブ・ドールアーピチェはほとんど権利を有します。あなただけ記述する必要があります。

self.singleton_class.send(:attr_accessor, varname) 

または

self.singleton_class.class_eval "attr_accessor :#{varname}" 

や私の好きな変種

self.singleton_class.class_exec do attr_accessor varname end 

varnameの値が

関連する問題