Skip to content

Instantly share code, notes, and snippets.

@bjmllr
Last active September 21, 2017 23:26
Show Gist options
  • Save bjmllr/084d8d6dd30f9f8aecd100111aa1a019 to your computer and use it in GitHub Desktop.
Save bjmllr/084d8d6dd30f9f8aecd100111aa1a019 to your computer and use it in GitHub Desktop.
metaprogramming atrocity
module Mat
module_function def ch(input, &block)
matcher = Matcher.new
matcher.instance_exec(&block)
matcher.match(input)
end
module_function def cher(&block)
matcher = Matcher.new
matcher.instance_exec(&block)
matcher
end
class Matcher
def initialize
@patterns = []
end
def pattern(*args, &block)
@patterns << Pattern.new(*args, block)
end
def match(input)
# trivial decomposition for demo
@patterns.each do |pattern|
pattern.match?(input) &&
(return Context.new(pattern, input).instance_exec(&pattern.block))
end
raise "No match"
end
def method_missing(name, *rest)
return super unless rest.empty?
Placeholder.new(name)
end
end # class Matcher
class Pattern
attr_reader :block
def initialize(pattern, block)
@pattern = pattern
@block = block
end
def index(name)
@pattern.index { |ph| ph.is_a?(Placeholder) && ph.name == name }
end
def match?(input)
@pattern.zip(input).all? { |m, i| m === i }
end
end
class Placeholder
attr_reader :name
def initialize(name)
@name = name
end
def ===(_)
true
end
end
class Context
def initialize(pattern, input)
@pattern = pattern
@input = input
end
def method_missing(name, *args)
return super unless args.empty?
idx = @pattern.index(name) || (return super)
@input[idx]
end
end
end # module Mat
def go(input)
Mat.ch input do
pattern([:ok, status]) do
"You got! status: #{status}"
end
pattern([:ng, status]) do
"Nooo! status: #{status}"
end
end
end
go [:ok, 500] # => "You got! status: 500"
go [:ng, 404] # => "Nooo! status: 404"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment