DEV Community

Seiei Miyagi for Okinawa Ruby User Group

Posted on

4

Ruby 2.6 new feature: refine `#to_proc`

Refinements take place at block passing. [Feature #14223]
https://github.com/ruby/ruby/blob/v2_6_0/NEWS

It's very useful when you want to use the literals as DSL for the block.
Following example refines Integer#to_proc and Array#to_proc to slice the values.

using Module.new {
  refine(Integer) do
    def to_proc
      -> o { o[self] }
    end
  end

  refine(Array) do
    def to_proc
      # Same as -> o { map(&o.method(:[]) }
      # https://dev.to/hanachin/ruby-27-new-feature-method-reference-operator-38l2
      -> o { map(&o.:[]) }
    end
  end
}

p "foo".match(/(a)(b)(c)/)&.then(&1) #=> nil
p "abc".match(/(a)(b)(c)/)&.then(&1) #=> "a"
p "abc".match(/(a)(b)(c)/)&.then(&[1]) #=> ["a"]
p "abc".match(/(a)(b)(c)/)&.then(&[1,2,3]) #=> ["a","b","c"]

Heroku

This site is built on Heroku

Join the ranks of developers at Salesforce, Airbase, DEV, and more who deploy their mission critical applications on Heroku. Sign up today and launch your first app!

Get Started

Top comments (5)

Collapse
 
defman profile image
Sergey Kislyakov

&o.:[] the amount of sugar in these 6 symbols gave me diabetes.

Collapse
 
hanachin profile image
Seiei Miyagi

140% symbols😋🍭

  • map(&o.:[])
    • (
    • &
    • .
    • :
    • [
    • ]
    • )
  • map{|k|o[k]}
    • {
    • |
    • [
    • ]
    • }
Collapse
 
dhnaranjo profile image
Desmond Naranjo

I don't have a damn idea what I am looking at.

Collapse
 
defman profile image
Sergey Kislyakov

My guess is &1 is 1.to_proc() and o is the receiver object (e.g. a.map(&0) would do a.map( -> a[0])) and the sugar diabetes thingy is a.[].to_proc(). If I'm wrong please correct me @hanachin .

There's something similar in Kotlin though I like their implementation more.

Collapse
 
hanachin profile image
Seiei Miyagi

That's correct!

& would implicitly call #to_proc to convert the object to Proc object.

Any object that implements the to_proc method can be converted into a proc by the & operator, and therefore con be consumed by iterators.
docs.ruby-lang.org/en/2.6.0/Proc.h...

But before 2.6, #to_proc that defined in Refinements are ignored at & operator.

# foo.rb
using Module.new {
  refine(Integer) do
    def to_proc
      -> o { o[self] }
    end
  end
}

p 1.then(&0)
Enter fullscreen mode Exit fullscreen mode
% ruby -v foo.rb
ruby 2.5.3p105 (2018-10-18 revision 65156) [x86_64-darwin17]
Traceback (most recent call last):
foo.rb:9:in `<main>': wrong argument type Integer (expected Proc) (TypeError)
Enter fullscreen mode Exit fullscreen mode

In 2.6, we can use #to_proc for & operator.

% ruby -v foo.rb
ruby 2.6.1p33 (2019-01-30 revision 66950) [x86_64-darwin17]
1
Enter fullscreen mode Exit fullscreen mode

AWS GenAI LIVE image

Real challenges. Real solutions. Real talk.

From technical discussions to philosophical debates, AWS and AWS Partners examine the impact and evolution of gen AI.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay