Skip to content

Instantly share code, notes, and snippets.

@dasch
Created April 19, 2012 12:02
Show Gist options
  • Save dasch/2420529 to your computer and use it in GitHub Desktop.
Save dasch/2420529 to your computer and use it in GitHub Desktop.
require 'pattern'
# Returns the n'th number in the Fibonacci sequence.
def fib(n)
Pattern.match(n) do
on(0) { 0 }
on(1) { 1 }
on(Integer) { fib(n - 2) + fib(n - 1) }
end
end
# A simple implementation of pattern matching in Ruby.
class Pattern
class NoMatch < RuntimeError
end
def self.match(value, &block)
catch(:ok) do
matcher = Matcher.new(value)
matcher.instance_eval(&block)
# If none of the patterns matched, we'll end up here.
raise NoMatch
end
end
end
class Pattern::Matcher
def initialize(value)
@value = value
end
def on(pattern)
if pattern === @value
throw :ok, yield
end
end
end
require 'rubygems'
require 'rspec/autorun'
describe Pattern::Matcher do
describe "#on" do
let(:matcher) { Pattern::Matcher.new("foo") }
it "throws :ok when the pattern matches the value" do
catch(:ok) { matcher.on(/foo/) { "bar" } }.should eq "bar"
end
it "does not throw :ok when the pattern doesn't match the value" do
matcher.on("baz") { "bar" }.should be_nil
end
end
end
describe Pattern, ".match" do
it "returns the value from the matching clause" do
Pattern.match "foo" do
on("foo") { "bar" }
on("baz") { "bim" }
end.should eq "bar"
end
it "returns nil if that's what the matching clause returns" do
Pattern.match "foo" do
on("foo") { nil }
end.should be_nil
end
it "raises NoMatch if there were no matches" do
lambda do
Pattern.match "foo" do
on("baz") { "bar" }
end
end.should raise_error(Pattern::NoMatch)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment