Ruby methods are executable language constructs. They are not objects. But we can get objects that represents methods with the Object
class's method
method.
Note: This is similar to how blocks are language syntax but not objects in Ruby and we can get object versions of blocks in the forms of procs and lambdas.
So the Object#method
takes a method name - either string or symbol - and return an Method
object. This object represents the named method on the receiver.
l = "hello".method(:length)
puts l.call #will return 5
Here we get a Method representing the length
method on the String
call, bound to the string "hello". And we can call this method with Method#call
.
Note: We can use public_method
which works the same as method
but ignores protected and private methods.
Method to Proc and Proc to Method
Method
objects work very much like Proc
objects and can be used in place of them. Method
even has a to_proc
method to convert it to Proc
if necessary. Here is an example where the method is passed in place of a proc with an &
:
def square(x)
x * x
end
puts (1..10).map(&method(:square))
We can also go in the other direction. Instead of getting Method
objects and converting them to Proc
, we can create a Method
from blocks and procs using define_method
of the Module
class.
define_method
expects a Symbol
as an argument and create a method with that name using the associated block as the method body like this define_method(:say_hello) { puts "hello" }
. This is the same as if we had done this:
def say_hello
puts "hello"
end
Unbounded Method objects and bind
So in the examples above we get Method
objects that are tied to an instance of a class that contains the method. These Method
objects have a receiver. Can we get a Method
object that was not bounded to an instance?
Turns out we can. It would be of a class called UnboundMethod
though. And we cannot actually call this UnboundMethod
as it wouldn't make sense. For example
unbounded_power = Fixnum.instance_method("**")
creates a unbounded_power
method that is of type UnboundMethod
. And in order to actually invoke this method we can have to bind
it to something
power_of_2 = unbounded_power.bind(2)
puts power_of_2.call(5) # prints 32
The power_of_2
is a Method
object now and we can use its call
method.
Lastly, Method
has some other handy methods name
, owner
, and receiver
that work as below.
> power_of_2.name
=> :**
> power_of_2.owner
=> Integer
> power_of_2.receiver
=> 2
That's all about Method
objects in Ruby and how they compare to Procs
.