Skip to content

Instantly share code, notes, and snippets.

@bastos
Created September 18, 2008 05:28
Show Gist options
  • Save bastos/11380 to your computer and use it in GitHub Desktop.
Save bastos/11380 to your computer and use it in GitHub Desktop.
Pattern Matching For Ruby Modules
# A not Nil or Unbound thing representation
class Unbound; end
module PatternMatching
def self.included(base)
base.send(:extend, PMMethods)
end
module PMMethods
attr_reader :pm_methods, :pattern
private
def match(*args)
@pattern = [*args]
end
def who_match(m, args)
@pm_methods.find_all do |el|
(el[:name] == m && pattern_match(el[:pattern], args))
end
end
def method_missing(m, *args)
super if @pm_methods == nil
return who_match(m, args)[0][:block].call(*args)
end
def pattern_match(pattern, args)
return false unless pattern.size == args.size
c = -1
pattern.each do |p|
c = c + 1
return false unless single_pattern_match(p, args[c])
end
end
def single_pattern_match(pattern, arg)
case
when (arg == pattern)
true
when (pattern == Unbound)
arg != nil
when (pattern.is_a? Regexp)
arg =~ pattern
when (pattern.is_a? Class)
arg.is_a?(pattern)
end
end
def fun (name, &block)
if @pattern == nil
raise "You need specify a pattern"
else
@pm_methods = [] if @pm_methods == nil
@pm_methods << {:name=>name ,:block=>block, :pattern=>@pattern}
@pattern = nil
end
end
end
end
module My
include PatternMatching
match 0
fun :fib do
0
end
match 1
fun :fib do
1
end
match Unbound
fun :fib do |n|
fib(n-1) + fib(n-2)
end
end
module Fruits
include PatternMatching
match :orange, Fixnum
fun :price do |type, n|
1.2 * n
end
match :banana, Fixnum
fun :price do |type, n|
0.4 * n
end
end
puts My::fib(17)
puts Fruits::price(:orange, 10)
puts Fruits::price(:banana, 10)
#Will show a error! puts Fruits::price(:apple, 10)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment