17 Stimmen

Wie kann ich einen attr_reader dynamisch hinzufügen?

Ich erwarte, dass der folgende Code wie erwartet funktioniert, aber ich erhalte einen NoMethodError (private Methode "foo" aufgerufen für #<MyClass...)

class MyClass
end

my_object = MyClass.new

my_object.instance_variable_set(:@foo, "bar")
MyClass.send("attr_reader", :foo)

puts my_object.foo

Das Problem ist, ich bin mit buchstäblich identischen Code in einer größeren Anwendung und es funktioniert genau wie ich erwarte, aber wenn ich es zu diesem grundlegenden Beispiel vereinfachen es fehlschlägt.

(Ich weiß, dass es viele andere Möglichkeiten gibt, das zu tun, was ich in Ruby tue)

12voto

Mike Lewis Punkte 62061

Verwenden Sie Modul#Klasse_Eval :

Dadurch versetzt der Block Sie in den Kontext von MyClass und ermöglicht Ihnen den Aufruf von attr_reader

ruby-1.9.2-p136 :028 > my_object.instance_variable_set(:@foo, "bar")
 => "bar" 
ruby-1.9.2-p136 :029 > MyClass.class_eval{attr_reader :foo}
 => nil 
ruby-1.9.2-p136 :030 > my_object.foo
 => "bar"

5voto

DVG Punkte 17144

Nehmen wir für einen Moment an, dass Sie einen Accessor für diese bestimmte Instanz der Klasse erstellen möchten (wovon ich ausgehe, da Sie mit der Instanz arbeiten).

Sie können einfach die Singleton-Klasse der Instanz öffnen und instance_eval verwenden, um den Accessor

class MyClass
end
my_instance = MyClass.new
my_instance.singleton_class.instance_eval { attr_accessor :foo }
my_instance.foo = :bar
my_instance.foo # => :bar

3voto

Adrien Jarthon Punkte 966

Interessantes Problem, ich fand diese Lösung funktioniert gut:

MyClass.class_eval("attr_reader :foo")

1voto

Phrogz Punkte 283167

Die Antwort von @MikeLewis ist nett, aber warum wird die Klasse nicht einfach wieder eröffnet?

irb(main):001:0> class MyClass; end
#=> nil
irb(main):002:0> m = MyClass.new
#=> #<MyClass:0x2d43ae0>
irb(main):003:0> class MyClass; attr_accessor :foo; end
#=> nil
irb(main):004:0> m.foo = 42
#=> 42

0voto

Josh Lee Punkte 159535

Zwingen Sie die Methode einfach, öffentlich zu werden:

MyClass.send("public", :foo)

Ich habe keine Ahnung, warum sie in manchen Fällen privat ist.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X