Ruby'de send () ne yapar?


98

Lütfen birisi bana ne söyleyebilir mi

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

ve yapar mı?


2
Kodun tamamı bu mu? Demek istediğim, 'göndermeden önce hiçbir şey yok mu?
zürafa

Yanıtlar:


111

send bir yöntem tepki verene kadar bir nesne örneğine ve onun üst öğelerine sınıf hiyerarşisindeki bir mesaj gönderir (çünkü adı ilk argümanla eşleşir).

Pratik olarak bu satırlar eşdeğerdir:

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

sendÖzel yöntemleri de çağırabilmeniz için görünürlük kontrollerini atladığını unutmayın (birim testi için kullanışlıdır).


Göndermeden önce gerçekten değişken yoksa, bu, global Object'in kullanıldığı anlamına gelir:

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

1
Oh anladım, bu yüzden gün sayısını statik olarak söylemek yerine veri tabanında 1. ay gibi bir şey depolamak istendiğinde send kullanabilirsiniz.
Christian Bankester

3
Doğru, yöntemi statik değil, hesaplanan adlarla çağırmak için kullanabilirsiniz. (Onlara eşsiz önek vermek, ancak, ben burada ... kısıtlamasız kullanıcı girişi olsa da, özel yöntemleri çağırmadan önlemek için izin vermemelidir: send 'user_method _' + yontemadi, * args)
giraff

2
İyi bir kullanım durumu, korumalı bir sınıf yöntemini test etmek isteyebilirsiniz, onu bir sınıfın dışında - test dosyasında ..
GN olarak


65

.Send yöntemi ile düşündüğüm en kullanışlı özelliklerden biri, yöntemi dinamik olarak çağırabilmesidir. Bu size çok fazla yazı yazmadan tasarruf sağlayabilir. .Send yönteminin en popüler kullanımlarından biri, öznitelikleri dinamik olarak atamaktır. Örneğin:

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

Nitelikleri düzenli olarak atamak için birinin

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

Veya .send yöntemini kullanarak:

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

Ancak tümü aşağıdakilerle değiştirilebilir:

Rails uygulamanızın, kullanıcı girdisinden araç sınıfınıza özellikler ataması gerektiğini varsayarsak,

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

Harika bağlantı için teşekkürler
sid_09

7
.Send'i bu şekilde kullanmak gereksiz karmaşıklık ekler ve koda yanlışlıkla bir hata eklemeyi kolaylaştırır. Örneğin, yukarıdaki kodunuzda, parametre karmalarınıza yeni bir giriş eklerseniz ('silindirler' gibi), kod, tanımsız bir yöntem hatasıyla başarısız olur.
Kevin Schwerdtfeger

1
cevap ver? istenirse bu tür hataları önlemek için kullanılabilir.
Richard_G

1
Bu harika bir açıklamaydı! Teşekkürler Jha!
Sharath

1
@Kevin haklısın, ama bazen gerekli olabilir. Daha fazla esneklik, azaltılabilecek daha fazla riskle ilişkilidir.
Will Sheppard

13

Antonio Jha'nın https://stackoverflow.com/a/26193804/1897857'ye benzer başka bir örnek

bir nesnedeki nitelikleri okumanız gerekmesidir.

Örneğin, bir dizi dizginiz varsa, bunları yinelemeye ve onları nesnenizde çağırmaya çalışırsanız, işe yaramaz.

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

Ancak, sendnesneye dizeleri yapabilirsiniz :

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

Basit ve kolay açıklama için teşekkürler!
Junan Chakma

Teşekkürler! Tam da peşinde olduğum cevap bu. Bunun yaygın olarak kullanıldığını merak mı ediyorsunuz? Eski kodda benzer bir şeyle karşılaştım, buna bağlı kalmam gerektiğinden emin değilim. @ Mike Vallano
B Liu

1
@ b-liu Deneyimli geliştiriciler tarafından yeni kodda kullanıldığını gördüm. Kullanırken Ayrıca yararlı olabilir define_method: apidock.com/ruby/Module/define_method .
Mike Vallano

Harika! Çok teşekkürler! @MikeVallano
B Liu

4

Send ne yapar?

send bir yöntemi çağırmanın başka bir yoludur.

Bu, en iyi örnekle açıklanır:

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

Object sınıfında can gönderin .

Bunun faydası nedir?

Bu yaklaşımın yararı, çağırmak istediğiniz yöntemi parametre olarak geçirebilmenizdir. İşte basit bir örnek:

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

Çağrılmasını istediğiniz yöntemi geçebilirsiniz. Bu durumda biz geçtik :to_s. Ruby metaprogramlama yaparken bu çok kullanışlı olabilir, çünkü bu bizim farklı gereksinimlerimize göre farklı yöntemler çağırmamıza izin verir.


0

Görünümler için başka bir kullanım örneği:

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

İzin vermek . her tür nesneyle çalışan ölçeklenebilir görünüm yazmanız için:

    render 'your_view_path', object: "my_object"

Bu, görünümlere gereksiz mantık ekler ve güvenlik açısından sonuçları olabilir. Bunu yapma. Dizileri ve karmaları kullanın.
Derrek Bertrand
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.