ruby.onl / sorcery

Pattern Matching: case/in Is case/when on Steroids

2026-03-05

Ruby 3.0 introduced structural pattern matching with case/in. Think of it as case/when that can reach inside your data, pull out specific values, and bind them to variables in one shot. If you've ever written five lines of Perl to unpack a nested hash ref, pattern matching does it in one expression.

Part 1: Basic Syntax

case response in { status: 200, body: } # destructure hash, bind 'body' variable process(body) in { status: 404 } puts "not found" in { status: s } if s >= 500 # guard clause with variable binding puts "server error: #{s}" end
The key difference from case/when: pattern matching uses in instead of when, and it destructures the data, binding variables automatically.

Part 2: Array Pattern Matching

case data in [Integer => first, *rest] # first must be Integer, rest is everything else puts "starts with number #{first}" in [String => name, Integer => age] puts "#{name} is #{age}" in [] # empty array puts "nothing here" end

Part 3: Hash Destructuring

# Pull specific keys out of a hash case config in { host: String => h, port: Integer => p } connect(h, p) in { host: String => h } connect(h, 5432) # default port end

Part 4: One-liner Destructure with =>

# Pin a pattern match to a variable data = { users: [{ name: "Alice", email: "a@b.com" }, { name: "Bob" }] } data => { users: [{ name:, email: }, *rest] } puts "First user: #{name} <#{email}>" # name => "Alice", email => "a@b.com"
One line. Reaches into a nested hash, pulls out the name and email from the first element of an array, and binds them to local variables. Try doing that in Perl without losing your mind.

Part 5: Find Pattern (Searching Arrays)

# Find an element matching a pattern inside an array case users in [*, { name: "Alice", role: } , *] puts "Alice's role: #{role}" end
The [*, pattern, *] syntax searches through the array for any element matching the middle pattern. It's grep for structured data.

Part 6: Practical Ops Example

Parsing a JSON API response:
require 'json' response = JSON.parse(api_result, symbolize_names: true) case response in { status: "ok", data: { servers: [{ hostname:, ip: }, *] } } puts "Primary server: #{hostname} (#{ip})" in { status: "error", message: } STDERR.puts "API error: #{message}" in { status: } STDERR.puts "Unknown status: #{status}" end

Part 7: Guard Clauses

case log_entry in { level: "ERROR", timestamp: t } if t > Time.now - 3600 puts "Recent error!" in { level: "ERROR" } puts "Old error, probably fine" end

Part 8: The in Operator (Standalone Check)

# Check if data matches a pattern (returns true/false) if config in { database: { host: String } } puts "Config has a database host string" end

Part 9: Perl Comparison

Perl has no direct equivalent. The closest would be manually unpacking hash refs and array refs with dereferencing. Ruby's pattern matching handles nested structures in a single expression that would take 5-10 lines of Perl. This is one area where Ruby genuinely leapfrogs Perl in expressiveness.

Created By: Wildcard Wizard. Copyright 2026