Skip to content

Instantly share code, notes, and snippets.

@patbenatar
Created October 25, 2019 23:51
Show Gist options
  • Save patbenatar/fb5976fa1183155cdc02655ff10529c4 to your computer and use it in GitHub Desktop.
Save patbenatar/fb5976fa1183155cdc02655ff10529c4 to your computer and use it in GitHub Desktop.
Experiment in using Ruby 2.7 case/in to implement pattern-matching methods
require 'active_support/concern'
require 'active_support/core_ext/class/attribute'
module PatternMatchingMethods
extend ActiveSupport::Concern
included do
class_attribute :defined_pattern_matching_methods, default: []
def send_match(name, input)
instance_eval <<-CODE
case #{input}
#{defined_pattern_matching_methods.select { |m| m[:name] == name.to_s }.map do |meth|
<<-CASE_IN
in #{meth[:pattern]}
defined_pattern_matching_methods
.find { |m| m[:name] == "#{meth[:name]}" && m[:pattern] == "#{meth[:pattern]}" }[:block]
.call(
local_variables.each_with_object({}) { |var, obj| obj[var] = binding.local_variable_get(var) }
)
CASE_IN
end.join("\n")}
end
CODE
end
def method_missing(name, *args, &block)
if defined_pattern_matching_methods.find { |m| m[:name] == name.to_s }
send_match(name, *args)
else
super
end
end
end
class_methods do
def def_match(name, pattern, &block)
defined_pattern_matching_methods << {
name: name.to_s,
pattern: pattern,
block: block
}
end
end
end
class MyClass
include PatternMatchingMethods
def_match :my_method, "[0, a]" do |captures|
puts "Matched first definition with captured value a=#{captures[:a]}"
end
def_match :my_method, "{ name: 'Alice', children: [{ name: 'Bob', age: age }] }" do |captures|
puts "Matched second definition with captured value age=#{captures[:age]}"
end
end
my_instance = MyClass.new
my_instance.my_method([0, 3])
my_instance.my_method([0, 5])
# my_instance.my_method([1, 5])
my_instance.my_method({ name: "Alice", children: [{ name: "Bob", age: 20 }]})
# my_instance.my_method({ name: "Frank", children: [{ name: "Bob", age: 20 }]})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment