I propose new pattern matching syntax.
Here's a summary of pattern syntax.
# case version case expr in pat [if|unless cond] ... in pat [if|unless cond] ... else ... end pat: var # Variable pattern. It matches any value, and binds the variable name to that value. | literal # Value pattern. The pattern matches an object such that pattern === object. | Constant # Ditto. | var_ # Ditto. It is equivalent to pin operator in Elixir. | (pat, ..., *var, pat, ..., id:, id: pat, ..., **var) # Deconstructing pattern. See below for more details. | pat(pat, ...) # Ditto. Syntactic sugar of (pat, pat, ...). | pat, ... # Ditto. You can omit the parenthesis (top-level only). | pat | pat | ... # Alternative pattern. The pattern matches if any of pats match. | pat => var # As pattern. Bind the variable to the value if pat match. # one-liner version $(pat, ...) = expr # Deconstructing pattern.
The patterns are run in sequence until the first one that matches.
If no pattern matches and no else clause, NoMatchingPatternError exception is raised.
This is similar to Extractor in Scala.
The patten matches if:
class Array alias deconstruct itself end case [1, 2, 3, d: 4, e: 5, f: 6] in a, *b, c, d:, e: Integer | Float => i, **f p a #=> 1 p b #=> [2] p c #=> 3 p d #=> 4 p i #=> 5 p f #=> {f: 6} e #=> NameError end
This pattern can be used as one-liner version like destructuring assignment.
class Hash alias deconstruct itself end $(x:, y: (_, z)) = {x: 0, y: [1, 2]} p x #=> 0 p z #=> 2
class Struct def deconstruct; [self] + values; end end A = Struct.new(:a, :b) case A[0, 1] in (A, 1, 1) :not_match in A(x, 1) # Syntactic sugar of above p x #=> 0 end
require 'json' $(x:, y: (_, z)) = JSON.parse('{"x": 0, "y": [1, 2]}', symbolize_names: true) p x #=> 0 p z #=> 2