The Method gem you've been waiting for.
The method_missing gem brings the functional tools you need to Ruby: method composition, sequencing, and repeating. These are useful for when you must combine methods, apply different methods to the same argument, or "grow" a method.
I'll explain, but first:
gem install method_missing
This is the classic. In algebra class you learned that f(g(x))
can also be written (f . g)(x)
. This is handy because now you have this (f . g)
object that you can pass to integrals and whatnot.
So in Ruby, using the method_missing gem:
def escape_everything(text)
everything_escaper.call(text)
end
def everything_escaper
method(:html_escape) * method(:escape_javascript) * method(:json_escape)
end
And more algebraically:
(f * g).call(x) == f.call(g.call(x))
This doesn't come up as often but when it does, oh boy, does it ever! This is useful for when you have a bunch of methods to apply to the same argument. For example, using the method_missing gem:
def valid_options?(options_checker, options)
options_checker.at_most_one(
(method(:sort_mod_time) / method(:sort_access_time)).call(options)) &&
options_checker.at_most_one(
(method(:sort_file_size) / method(:sort_mod_time)).call(options))
end
Again, more algebraically:
(f / g / h).call(x) == [f.call(x), g.call(x), h.call(x)]
This one comes up the least in most people's day-to-day life. It's the concept of applying a method to its output, repeatedly. Here's a contrived example, using the method_missing gem:
def church_encoding(n)
if n.zero?
lambda{|f,x| x}
else
lambda{|f,x| (f ^ n).call(x)}
end
end
Algebraically:
(f ^ 3).call(4) == f.call(f.call(f.call(4)))
These are objects which can be combined! Here's an example, also contrived, that turns an object into a number, n, then adds four to n and multiplies n by six, then sums those results, using primitive methods that add one to a number and multiply a number by two:
def interesting_math(o)
four_and_six.call(o).sum
end
def four_and_six
((add1 ^ 4) / (mul2 ^ 3)) * method(:to_i)
end
To show this algebraically:
(((add1 ^ 4) / (mul2 ^ 3)) * method(:to_i)).call(o) == [
add1.call(add1.call(add1.call(add1.call(o.to_i)))),
mul2.call(mul2.call(mul2.call(o.to_i)))
]
Copyright 2017 Mike Burns