Created
October 25, 2019 23:51
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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