Ruby 2.7 new feature: Method reference operator

By Seiei Miyagi

New operator .: was added.
https://bugs.ruby-lang.org/issues/12125
https://github.com/ruby/ruby/commit/67c574736912003c377218153f9d3b9c0c96a17b

It converts the method to Method object like method method.

42.:to_s
# => #<Method: Integer#to_s>

What is method method?

It converts the method to Method object.
https://docs.ruby-lang.org/en/trunk/Object.html#method-i-method

42.method(:to_s)
# => #<Method: Integer#to_s>

What is Method object?

Method object is a pair of receiver and the method, it's callable like a Proc.
https://docs.ruby-lang.org/en/trunk/Method.html

meth = 42.method(:to_s)
# => #<Method: Integer#to_s>
meth.receiver
# => 42
meth.name
# => :to_s
meth.call
# => "42"
meth.call(16)
# => "2a"

What is the differrence between Method reference operator .: and method method?

If method method is overwritten, .: still work.

class Object def method(*); end
end 42.method(:to_s)
# => nil
42.:to_s
# => #<Method: Integer#to_s>

Even if method method is refined, .: still work.

using Module.new { refine(Object) do def method(*); end end
} 42.method(:to_s)
# => nil
42.:to_s
# => #<Method: Integer#to_s>

Is it possible to convert refined method to Method?

No

using Module.new { refine(Object) do def foo(*); end end
} 42.:foo
# undefined method `foo' for class `Integer' (NameError)

How to convert the unary method to Method?

Add the suffix @ like method method argument.

42.method(:-@).call
# => -42
42.:-@.call
# => -42

Is it useful?

YES! It is useful for the API which takes the block, like methods in Enumerable.

[1,2,3].map { |n| 2 * n }
# => [2, 4, 6]
[1,2,3].map(&2.:*)
# => [2, 4, 6] ["NG"].any? { |word| "COPYING".include?(word) }
# => true
["NG"].any?(&"COPYING".:include?)
# => true require "prime" (1..10).select { |n| Prime.prime?(n) }
# => [2, 3, 5, 7]
(1..10).select(&Prime.:prime?)
# => [2, 3, 5, 7]

Conclusion

You can use new syntax Method reference operator .: now <3

$ rbenv install 2.7.0-dev
$ rbenv global 2.7.0-dev
$ ruby -e 'self.:puts.("Enjoy!")'
Enjoy!