Pattern: Erlang-style pattern matching in Ruby
Message from 2022
This post is pretty old! Opinions and technical information in it are almost certainly oudated. Commands and configurations will probably not work. Consider the age of the content before putting any of it into practice.
p.match(/lmao/) { :butts }
p.match(/lol/) { :buttes }
p.match(wc) { "atomics" }
p[888]
# => "atomics"
p["a butt lmao"]
# => :butts
p["lolqdb"]
# => :buttes
Fork/clone Pattern on Github, and read on for commentary.
How it works
In the example above, p
is a Pattern::Matcher
object, that wraps arguments and blocks from the #match
method into a Pattern::Entry
object, and stores those objects in an array in order of definition. When
called with the #[]
method, it goes through that array and calls the stored block from the first entry that
answers positively to Pattern::Entry#match?
.
A Pattern::Entry
is basically a tuple of an argument list and a proc to execute on match. The only real
cleverness is checking for a Pattern::Wildcard
object, and checking with #===
, which picks an appropriate
comparison for the objects involved (uses Regexp#=~
if the left value is a Regexp
and right is a String
,
for example.)
What could be done
Things I’ve got ideas for but haven’t done yet include extending the Wildcard object to allow for Array#first
and Object#class
(or Class#ancestors
) checks, since those don’t work with #===
.