Was macht send () in Ruby?


94

Kann mir bitte jemand was sagen

send("#{Model.find...}")

ist und tut?


2
Ist das die ganze Codezeile? Ich meine, gibt es nichts vor dem "Senden"?
Giraff

Antworten:


107

send sendet eine Nachricht an eine Objektinstanz und ihre Vorfahren in Klassenhierarchie, bis eine Methode reagiert (da ihr Name mit dem ersten Argument übereinstimmt).

In der Praxis sind diese Zeilen gleichwertig:

1.send '+', 2
1.+(2)
1 + 2

Beachten Sie, dass sendSichtbarkeitsprüfungen umgangen werden, sodass Sie auch private Methoden aufrufen können (nützlich für Komponententests).


Wenn vor dem Senden wirklich keine Variable vorhanden ist, bedeutet dies, dass das globale Objekt verwendet wird:

send :to_s    # "main"
send :class   # Object

1
Oh, ich verstehe, also könnte man send verwenden, wenn man so etwas wie 1 Monat in der Datenbank speichern möchte, anstatt statisch die Anzahl der Tage anzugeben.
Christian Bankester

3
Richtig, Sie können damit eine Methode mit Namen aufrufen, die berechnet und nicht statisch sind. (Sie sollten jedoch keine uneingeschränkte Benutzereingabe zulassen, um das Aufrufen privater Methoden zu vermeiden ... Sie können ihnen jedoch ein eindeutiges Präfix geben: send 'user_method _' + methodname, * args)
giraff

2
Ein guter Anwendungsfall könnte sein, dass Sie eine geschützte Klassenmethode testen möchten. Sie können sie auch außerhalb einer Klasse aufrufen - in einer Testdatei.
GN.


63

Eine der nützlichsten Funktionen, die ich mit der .send-Methode denke, ist, dass sie die Methode dynamisch aufrufen kann. Dies kann Ihnen viel Tipparbeit ersparen. Eine der beliebtesten Anwendungen der .send-Methode ist die dynamische Zuweisung von Attributen. Beispielsweise:

class Car
  attr_accessor :make, :model, :year
end  

Um Attribute regelmäßig zuzuweisen, müsste man

c = Car.new
c.make="Honda"
c.model="CRV"
c.year="2014"

Oder mit der .send-Methode:

c.send("make=", "Honda")
c.send("model=", "CRV")
c.send("year=","2014")

Es kann jedoch alles durch Folgendes ersetzt werden:

Angenommen, Ihre Rails-App muss Ihrer Fahrzeugklasse Attribute aus Benutzereingaben zuweisen, können Sie dies tun

c = Car.new()
params.each do |key, value|
  c.send("#{key}=", value)
end

Vielen Dank für den tollen Link
sid_09

7
Die Verwendung von .send auf diese Weise erhöht die unnötige Komplexität und erleichtert das versehentliche Einfügen eines Fehlers in den Code. Wenn Sie beispielsweise in Ihrem obigen Code Ihrem Parameter-Hash einen neuen Eintrag hinzufügen (z. B. 'Zylinder'), schlägt der Code mit einem undefinierten Methodenfehler fehl.
Kevin Schwerdtfeger

1
Antworten auf? kann verwendet werden, um solche Fehler zu verhindern, falls dies gewünscht wird.
Richard_G

1
Das war eine großartige Erklärung! Danke Jha!
Sharath

1
@ Kevin du hast recht, aber manchmal kann es notwendig sein. Mehr Flexibilität bedeutet mehr Risiko, das gemindert werden kann.
Will Sheppard

12

Ein weiteres Beispiel, ähnlich dem von Antonio Jha unter https://stackoverflow.com/a/26193804/1897857

ist, wenn Sie Attribute für ein Objekt lesen müssen.

Wenn Sie beispielsweise über ein Array von Zeichenfolgen verfügen und versuchen, diese zu durchlaufen und sie für Ihr Objekt aufzurufen, funktioniert dies nicht.

atts = ['name', 'description']
@project = Project.first
atts.each do |a|
  puts @project.a
end
# => NoMethodError: undefined method `a'

Sie können jedoch senddie Zeichenfolgen für das Objekt festlegen:

atts = ['name', 'description']
@project = Project.first
atts.each do |a|
  puts @project.send(a)
end
# => Vandalay Project
# => A very important project

Danke für die einfache Erklärung!
Junan Chakma

Vielen Dank! Das ist genau die Antwort, nach der ich bin. Fragen Sie sich, ob dies häufig verwendet wird? Ich bin auf etwas Ähnliches im Legacy-Code gestoßen, nicht sicher, ob ich mich daran halten soll. @ Mike Vallano
B Liu

1
@ b-liu Ich habe gesehen, wie es von erfahrenen Entwicklern in neuem Code verwendet wurde. Dies kann auch hilfreich sein, wenn Sie Folgendes verwenden define_method: apidock.com/ruby/Module/define_method .
Mike Vallano

Genial! Tausend Dank! @ MikeVallano
B Liu

4

Was macht send?

send ist eine andere Möglichkeit, eine Methode aufzurufen.

Dies lässt sich am besten anhand eines Beispiels veranschaulichen:

o = Object.new
o.send(:to_s) # => "#<Object:0x00005614d7a24fa3>"
# is equivalent to:
o.to_s # => "#<Object:0x00005614d7a24fa3>"

Senden Sie Leben in der Object-Klasse .

Was ist der Vorteil von ths?

Der Vorteil dieses Ansatzes besteht darin, dass Sie die Methode, die Sie aufrufen möchten, als Parameter übergeben können. Hier ist ein einfaches Beispiel:

def dynamically_call_a_method(name)
    o = Object.new
    o.send name 
end
dynamically_call_a_method(:to_s) # => "#<Object:0x00005614d7a24fa3>"

Sie können die Methode übergeben, die Sie aufrufen möchten. In diesem Fall sind wir vorbeigekommen :to_s. Dies kann sehr praktisch sein, wenn Sie eine Ruby-Metaprogrammierung durchführen, da wir so verschiedene Methoden entsprechend unseren unterschiedlichen Anforderungen aufrufen können.


0

Ein weiterer Anwendungsfall für Ansichten:

    <%= link_to 
    send("first_part_of_path_#{some_dynamic_parameters}_end_path", 
    attr1, attr2), ....
    %>

Ermöglichen . Sie schreiben eine skalierbare Ansicht, die mit allen Arten von Objekten arbeitet mit:

    render 'your_view_path', object: "my_object"

Dies fügt Ansichten unnötige Logik hinzu und kann Auswirkungen auf die Sicherheit haben. Tu das nicht. Verwenden Sie Arrays und Hashes.
Derrek Bertrand
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.