Rubyでsend()は何をしますか?


回答:


107

send いくつかのメソッドが反応するまで(オブジェクトの名前が最初の引数と一致するため)、オブジェクトのインスタンスとそのクラスの祖先にメッセージを送信します。

実際には、これらの行は同等です。

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

sendは可視性チェックをバイパスするため、プライベートメソッドを呼び出すこともできます(単体テストに役立ちます)。


送信前に実際に変数がない場合は、グローバルオブジェクトが使用されていることを意味します。

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

1
ああ、なるほど、日数を静的に言うのではなく、1.monthのようなものをデータベースに保存したい場合は、sendを使用できます。
クリスチャンバンケスター、2010

3
確かに、静的ではなく、計算された名前でメソッドを呼び出すために使用できます。(ただし、プライベートメソッドの呼び出しを回避するために、無制限のユーザー入力を許可しないでください。ただし、一意のプレフィックスを与えることができます:send 'user_method _' + methodname、* args)
giraff

2
良いユースケースは、それはあなたが保護されたクラスのメソッドをテストしたいかもしれない、あなたはクラスでテストファイル..外でそれを呼び出すことができます
GN。


63

.sendメソッドで私が考える最も便利な機能の1つは、メソッドを動的に呼び出すことができることです。これにより、タイピングの手間を省くことができます。.sendメソッドの最も一般的な使用法の1つは、属性を動的に割り当てることです。例えば:

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

属性を定期的に割り当てるには、

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

または.sendメソッドを使用:

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

ただし、すべて次のものに置き換えることができます。

Railsアプリがユーザー入力から車のクラスに属性を割り当てる必要があると仮定すると、次のことができます

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

素晴らしいリンクをありがとう
sid_09 2015

7
この方法で.sendを使用すると、不必要な複雑さが追加され、コードに誤ってバグを導入しやすくなります。たとえば、上記のコードで、パラメーターハッシュ(「シリンダー」など)に新しいエントリを追加すると、コードは未定義のメソッドエラーで失敗します。
Kevin Schwerdtfeger

1
に対応する?必要に応じて、このようなエラーを防止するために使用できます。
Richard_G

1
これは素晴らしい説明でした!ありがとうJha!
Sharath

1
@Kevinあなたは正しいですが、時にはそれが必要かもしれません。柔軟性が高ければ高いほど、リスクを軽減できます。
シェパード、

12

Antonio Jhaのhttps://stackoverflow.com/a/26193804/1897857に類似した別の例

オブジェクトの属性を読み取る必要がある場合です。

たとえば、文字列の配列がある場合、それらを繰り返し処理してオブジェクトで呼び出しても、機能しません。

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

ただし、sendオブジェクトに文字列を指定できます。

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

シンプルで簡単な説明をありがとう!
Junan Chakma 2017

ありがとう!それがまさに私が求めている答えです。これはよく使われているのでしょうか?レガシーコードで似たようなものに出くわしましたが、それに固執する必要があるかわかりません。@ Mike Vallano
B Liu

1
@ b-liu経験豊富な開発者が新しいコードで使用するのを見てきました。使用した場合にも参考にすることができdefine_methodapidock.com/ruby/Module/define_method
Mike Vallano 2017年

驚くばかり!どうもありがとう!@MikeVallano
B Liu

4

送信は何をしますか?

send メソッドを呼び出す別の方法です。

これは例によって最もよく示されます:

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

Objectクラスでライブを送信します

これの利点は何ですか?

このアプローチの利点は、パラメーターとして呼び出すメソッドを渡すことができることです。以下に簡単な例を示します。

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

呼び出したいメソッドを渡すことができます。この場合、を渡しました:to_s。これはルビメタプログラミングを行うときに非常に便利です。これにより、さまざまな要件に応じてさまざまなメソッドを呼び出すことができるからです。


0

ビューの別の使用例:

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

許可します。あなたはあらゆる種類のオブジェクトを扱うスケーラブルなビューを書くために:

    render 'your_view_path', object: "my_object"

これにより、ビューに不要なロジックが追加され、セキュリティに影響を与える可能性があります。これを行わないでください。配列とハッシュを使用します。
Derrek Bertrand
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.