Leo
Leo

Reputation: 2103

What is the point of using "send" instead of a normal method call?

as far as I understand 'send' method, this

some_object.some_method("im an argument")

is same as this

some_object.send :some_method, "im an argument"

So what is the point using 'send' method?

Upvotes: 14

Views: 3717

Answers (5)

Intrepidd
Intrepidd

Reputation: 20858

It can come in handy if you don't know in advance the name of the method, when you're doing metaprogramming for example, you can have the name of the method in a variable and pass it to the send method.

It can also be used to call private methods, although this particular usage is not considered to be a good practice by most Ruby developers.

class Test
  private
  def my_private_method
    puts "Yay"
  end
end

t = Test.new

t.my_private_method # Error

t.send :my_private_method #Ok

You can use public_send though to only be able to call public methods.

Upvotes: 20

Ten Bitcomb
Ten Bitcomb

Reputation: 2374

In addition to everyone else's answers, a good use case would be for iterating through methods that contain an incrementing digit.

class Something
  def attribute_0
    "foo"
  end
  def attribute_1
    "bar"
  end
  def attribute_2
    "baz"
  end
end

thing = Something.new

3.times do |x|
  puts thing.send("attribute_#{x}")
end

#=> foo
# bar
# baz

This may seem trivial, but it's occasionally helped me keep my Rails code and templates DRY. It's a very specific case, but I think it's a valid one.

Upvotes: 4

Peter
Peter

Reputation: 84

I like this costruction

Object.get_const("Foo").send(:bar)

Upvotes: -1

Aleksei Matiushkin
Aleksei Matiushkin

Reputation: 121000

The summing briefly up what was already said by colleagues: send method is a syntax sugar for meta-programming. The example below demonstrates the case when native calls to methods are likely impossible:

class Validator
  def name
    'Mozart'
  end
  def location
    'Salzburg'
  end
end

v = Validator.new
'%name% was born in %location%'.gsub (/%(?<mthd>\w+)%/) do
  # v.send :"#{Regexp.last_match[:mthd]}"
  v.send Regexp.last_match[:mthd].to_sym
end
=> "Mozart was born in Salzburg" 

Upvotes: 0

sawa
sawa

Reputation: 168081

In addition to Intrepidd's use cases, it is convenient when you want to route different methods on the same receiver and/or arguments. If you have some_object, and want to do different things on it depending on what foo is, then without send, you need to write like:

case foo
when blah_blah then some_object.do_this(*some_arguments)
when whatever then some_object.do_that(*some_arguments)
...
end

but if you have send, you can write

next_method =
case foo
when blah_blah then :do_this
when whatever then :do_that
....
end
some_object.send(next_method, *some_arguments)

or

some_object.send(
  case foo
  when blah_blah then :do_this
  when whatever then :do_that
  ....
  end,
  *some_arguments
)

or by using a hash, even this:

NextMethod = {blah_blah: :do_this, whatever: :do_that, ...}
some_object.send(NextMethod[:foo], *some_arguments)

Upvotes: 6

Related Questions