Destructuring: JavaScript vs. Ruby
Combining Ruby 2.7’s pattern matching, and Ruby 3’s rightward assignment, we can achieve something similar to JavaScript’s destructuring assignment. Jared White covers this well in Everything You Need to Know About Destructuring in Ruby 3. For those familiar the JavaScript syntax, here are some comparisons for destructuring objects/hashes:
// JavaScript
const { a } = { a: 1 } // a === 1
# Ruby
{a: 1} => {a:} # a == 1
(Rightward assignment might take some getting used to: variables on the right get assigned values from the left.)
Variable Naming
// JavaScript
const { a: b } = { a: 1 } // b === 1
# Ruby
{a: 1} => {a: b} # b == 1
…rest
// JavaScript
const { a, ...rest } = { a: 1, b: 2 } // a === 1, rest === { b: 2 }
# Ruby
{a: 1, b: 2} => {a:, **rest} # a == 1, rest == {b: 2}
Default Values
There’s currently no Ruby syntax equivalent to that of JavaScript for setting default values whilst destructuring. merge
is probably the best choice here. Let’s say we wanted defaults of a = 42
and b = 2
:
// JavaScript
const { a = 42, b = 2 } = { a: 1 } // a === 1, b === 2
# Ruby
{a: 42, b: 2}.merge({a: 1}) => {a:, b:} # a == 1, b == 2
Nil Values
In JavaScript, attempting to destructure a key that does not exist on the source, results in a variable being undefined
. In Ruby, pattern matching expects a pattern to match (obviously), so if a key does not exist on the source it will throw NoMatchingPatternError
. However, we can mimic JavaScript’s relaxed behaviour by defining a deconstruct_keys
method on our source, and merge any undefined keys.
// JavaScript
const { a, b } = { a: 1 } // a === 1, b === undefined
class Props < Hash
def deconstruct_keys(keys)
Array(keys).to_h { |k| [k, nil] }.merge(self)
end
end
Props[{a: 1}] => {a:, b:} # a == 1, b == nil
Thanks to Elliot Crosby-McCullough on the StimulusReflex Discord for this idea and code snippet.