Wie überprüfe ich in Ruby, ob die Methode "foo = ()" definiert ist?

81

In Ruby kann ich eine Methode foo = (bar) definieren:

irb(main):001:0> def foo=(bar)
irb(main):002:1>   p "foo=#{bar}"
irb(main):003:1> end
=> nil

Jetzt möchte ich überprüfen, ob es definiert wurde,

irb(main):004:0> defined?(foo=)
SyntaxError: compile error
(irb):4: syntax error, unexpected ')'
 from (irb):4
 from :0

Was ist die richtige Syntax, um hier zu verwenden? Ich gehe davon aus, dass es einen Weg geben muss, "foo =" so zu entkommen, dass es analysiert und korrekt an das definierte übergeben wird. Operator.

Alex Boisvert
quelle

Antworten:

131

Das Problem ist, dass die foo=Methode für die Verwendung in Zuweisungen ausgelegt ist. Sie können defined?auf folgende Weise sehen, was los ist:

defined? self.foo=()
#=> nil
defined? self.foo = "bar"
#=> nil

def foo=(bar)
end

defined? self.foo=()
#=> "assignment"
defined? self.foo = "bar"
#=> "assignment"

Vergleichen Sie das mit:

def foo
end

defined? foo
#=> "method"

Um zu testen, ob die foo=Methode definiert ist, sollten Sie respond_to?stattdessen Folgendes verwenden :

respond_to? :foo=
#=> false

def foo=(bar)
end

respond_to? :foo=
#=> true
molf
quelle
Vielen Dank! Dies löst mein Problem. Ich bin immer noch neugierig zu wissen, ob es einen Weg gibt, foo zu entkommen = so, dass es definiert definiert werden kann? aber zumindest kann ich jetzt weitermachen.
Alex Boisvert
1
Das Problem hierbei ist, dass foo=es immer in Aufgaben verwendet wird, sodass Ruby zurückkehrt, "assignment"wenn Sie testen defined? foo()(siehe aktualisierte Antwort).
Wolf
41

Sie können mithilfe der respond_to?Methode überprüfen, ob eine Methode vorhanden ist , und Sie übergeben ihr ein Symbol, z. B. bar.respond_to?(:foo=)um festzustellen, ob das Objekt barüber eine Methode verfügt foo=. Wenn Sie wissen möchten, ob Instanzen einer Klasse auf eine Methode reagieren, die Sie method_defined?für die Klasse (oder das Modul) verwenden können, z Foo.method_defined?(:bar=).

defined?ist keine Methode, sondern ein Operator, der eine Beschreibung des Operanden zurückgibt (oder null, wenn er nicht definiert ist, weshalb er in einer if-Anweisung verwendet werden kann). Der Operand kann ein beliebiger Ausdruck sein, dh eine Konstante, eine Variable, eine Zuweisung, eine Methode, ein Methodenaufruf usw. Der Grund, warum er in diesem Fall nicht funktioniert, defined?(foo=)liegt in den Klammern. Überspringen Sie sie und es sollte mehr funktionieren oder weniger wie erwartet. That being said, defined?ist ein ziemlich komisch Operator, und niemand nutzt sie , um Test für die Existenz von Methoden.

Das Ö
quelle
Es ist reply_to?, Nicht reply_to?
0x4a6f4672
3
Ah, die Schreibweise der Ruby-Kernbibliothek ... respond_to?,start_with? , end_with?.
Theo
3
stackoverflow.com/questions/5280556/… hat eine schöne Erklärung der Wahl hinter der Benennung TL; DRyou.knock if you.respond_to?(:knock)
zog