Skip to content

Instantly share code, notes, and snippets.

@jpfuentes2
Created January 22, 2014 03:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jpfuentes2/8553172 to your computer and use it in GitHub Desktop.
Save jpfuentes2/8553172 to your computer and use it in GitHub Desktop.
Horribly inefficient, mostly incorrect, and underwhelming pattern matching in Ruby
class Any; end;
class Pattern
attr :values
def initialize(*args)
@values = args
@matchers = []
end
def find_match
matcher = @matchers.find { |matcher| matcher.match?(@values) }
matcher && matcher.result
end
def match(*args)
result = args.pop
@matchers << Match.new(result, args.last)
end
class Match
attr :result
def initialize(result, expected)
@result = result
@expected = expected
end
def match?(given)
@expected == :default || find_match?(given)
end
private
def find_match?(given)
@expected.zip(given).each do |expected_val, given_val|
matched = expected_val == Any || given_val == expected_val
return false if not matched
end
true
end
end
end
module Kernel
def pattern(*args, &blk)
pattern = Pattern.new(*args)
pattern.instance_eval(&blk)
pattern.find_match
end
end
# Basic example
val = pattern(:a, :b) do
match [:a, :c], "Nope"
match [:a, :b], "Yay!"
end
p val == "Yay!" # => true
# FizzBuzz
vals = (1..10).map do |i|
pattern(i % 3, i % 5) do
match [0, 0], "FizzBuzz" # match i%3 == 0, i%5 == 0
match [0, Any], "Fizz" # match i%3 == 0, i%5 == anything
match [Any, 0], "Buzz" # match i%3 == anything, i%5 == 0
match :default, i
end
end
p vals == [1,2,"Fizz",4,"Buzz","Fizz",7,8,"Fizz","Buzz"] # => true
class Person
attr_accessor :name
end
(person = Person.new).name = "Joe"
# TODO: Object destructuring
val = pattern(Person => person) do
match({:name => "Jack"}, "Yay!")
match({:name => "Joe"}, "Nope")
end
p val # => nil
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment