Differencebetween Ruby's Send and Public_Send Methods

What is the difference between Ruby's send and public_send methods?

Unlike send, public_send calls public methods only.

Source

Example:

class Klass
private
def private_method
puts "Hello"
end
end

k = Klass.new
k.send(:private_method)
# => "Hello"

k.public_send(:private_method)
# => `public_send': private method `private_method' called for #<Klass:0x007f5fd7159a80> (NoMethodError)

You may want to prefer #public_send over #send so as not to circumvent private/protected visibility.

Ruby send vs __send__

Some classes (for example the standard library's socket class) define their own send method which has nothing to do with Object#send. So if you want to work with objects of any class, you need to use __send__ to be on the safe side.

Now that leaves the question, why there is send and not just __send__. If there were only __send__ the name send could be used by other classes without any confusion. The reason for that is that send existed first and only later it was realized that the name send might also usefully be used in other contexts, so __send__ was added (that's the same thing that happened with id and object_id by the way).

How to use send or public_send for a 'Model' name in ruby on rails?

you want to get class name from string, something like this will work:

Object.const_get("User").all

This will throw an error if class is not found:

NameError: uninitialized constant User

If you want something that will return nil instead of raising error, you can try:

"User".safe_constantize

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

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.

Ruby difference between send and instance_eval?

From the fine manual:

send(symbol [, args...]) → obj
send(string [, args...]) → obj

Invokes the method identified by symbol, passing it any arguments specified. [...] When the method is identified by a string, the string is converted to a symbol.

and for instance_eval:

instance_eval(string [, filename [, lineno]] ) → obj
instance_eval {| | block } → obj

Evaluates a string containing Ruby source code, or the given block, within the context of the receiver (obj). In order to set the context, the variable self is set to obj while the code is executing, giving the code access to obj’s instance variables.

So send executes a method whereas instance_eval executes an arbitrary block of code (as a string or block) with self set to the object that you're calling instance_eval on.

In your case, there isn't much difference as the string you're handing to instance_eval is just a single method. The main difference is that anyone reading your code (including you in six months) will be wondering why you're using instance_eval to call a single method.

You might also be interested in Object#public_send and BasicObject#__send__

What does send() do in Ruby?

send sends a message to an object instance and its ancestors in class hierarchy until some method reacts (because its name matches the first argument).

Practically speaking, those lines are equivalent:

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

Note that send bypasses visibility checks, so that you can call private methods, too (useful for unit testing).


If there is really no variable before send, that means that the global Object is used:

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

Ruby nested send

You can use instance_eval:

obj.instance_eval("foo.bar")

You can even access the instance variable directly:

obj.instance_eval("@foo.bar")


Related Topics



Leave a reply



Submit