Manu

Making use of Ruby 3 destructuring

Ruby 3 has some nice set of features, but destructuring is something that I am using a lot. Noting few of them here.

With Ruby 3 we have hash destructuring based on improved pattern matching.

Tried on ruby version ruby 3.1.1p18 (2022-02-18 revision 53f5fc4236) [arm64-darwin21]

What we used to do

We could destructure an array like this

irb(main):002:0> head, *rest = [1,2,3]
=> [1, 2, 3]
irb(main):003:0> head
=> 1
irb(main):004:0> rest
=> [2, 3]

But for hashes the below did not work

irb(main):005:0> {head, *rest } = {head:1, rest: 3}
# eval': (irb):5: syntax error, unexpected ',', expecting => (SyntaxError)
# {head, *rest } = {head:1, rest: 3}

We could although do this

irb(main):006:0> head = { head: 1, rest: 3}.values_at(:head)
=> [1]
irb(main):007:0> head
=> [1]

but then we get an array as a result and not the best experience.

What we can do now

In ruby 3 with rightward assignment operator we can do

irb(main):008:0> h = { x:1, y:2, z:3 }
=> {:x=>1, :y=>2, :z=>3}
irb(main):009:0> h => {x:}
=> nil
irb(main):010:0> x
=> 1
irb(main):011:0> h
=> {:x=>1, :y=>2, :z=>3}

Also, if not found

irb(main):012:0> h => {k:}
(irb):12:in `<main>': {:x=>1, :y=>2, :z=>3}: key not found: :k (NoMatchingPatternKeyError)

But this a runtime error, so we need to rescue this

irb(main):013:0> h => {k:} rescue nil
=> nil
irb(main):014:0> k
=> nil

We can also do rightward assignment as well

irb(main):019:0>  h = { x:1, y:2, z:3 }
=> {:x=>1, :y=>2, :z=>3}
irb(main):020:0> h => { y: k}
=> nil
irb(main):021:0> k
=> 2

And one the best use cases

irb(main):022:1* def sambar
irb(main):023:1*   result = 42
irb(main):024:1*   { result: }
irb(main):025:0> end
=> :sambar
irb(main):026:0> r = sambar
=> {:result=>42}
irb(main):027:0> r
=> {:result=>42}

Looking at you JS 😏

Another sample usage

irb(main):056:0> x = {:height=>'6 ft', :weight=>'160 lbs', :hair=>'brown', :name=>'bob'}
=> {:height=>"6 ft", :weight=>"160 lbs", :hair=>"brown", :name=>"bob"}
irb(main):057:0> x => {height: user_height}
=> nil
irb(main):058:0> user_height
=> "6 ft"

Further Reading

There are more use cases and patterns, which can be seen in the docs.