Pattern-matching refinements in Ruby 3.3
With Ruby 3.3, pattern-matching received further enhancements: better guards, right-hand patterns, and more flexible destructuring. Let’s explore.
What is pattern matching
Ruby introduced pattern matching in version 2.7. It allows you to deconstruct objects, hashes, arrays, combine patterns and match against them. For example:
1
2
3
4
5
6
7
8
case shape
in { type: :circle, radius: r }
puts "Circle with radius #{r}"
in { type: :rectangle, width: w, height: h }
puts "Rectangle #{w}x#{h}"
else
puts "Unknown shape"
end
What’s new in Ruby 3.3
- Right-hand patterns — you can now match the right side of an expression directly
Example:
1
->(x) { x > 0 } => positive
- Enhanced guards — deeper, more expressive guard conditions.
- Better performance & diagnostics — faster backtracking and more helpful error details.
- More flexible destructuring — nested arrays/hashes are easier and cleaner to match.
Why this matters
- Reduces boilerplate
if/elsif/elsechains. - Improves readability and intent.
- Encourages a “match the shape” style that is great for domain logic.
Example
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def handle_event(event)
case event
in { type: :user_signed_up, data: { name: name, email: email } }
send_welcome_email(name, email)
in { type: :order_placed, order: { id: id, items: items } } if items.any?
process_order(id, items)
in { type: :error, code: 500, message: message }
log_error(message)
else
log_warning("Unhandled event: #{event.inspect}")
end
end
In Ruby 3.3, refinements let you make these branches even more concise, depending on your domain patterns.
Summary
Ruby 3.3’s pattern-matching refinements continue to push Ruby’s expressiveness, helping you write cleaner, more declarative code for data-centric logic. If you’re on Rails or Ruby 3.x, give pattern matching a look.