Skip to content

Instantly share code, notes, and snippets.

@JoshCheek
Last active February 27, 2020 02:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JoshCheek/20f1bd6d82b4de4423be6bfb6bf4a8a5 to your computer and use it in GitHub Desktop.
Save JoshCheek/20f1bd6d82b4de4423be6bfb6bf4a8a5 to your computer and use it in GitHub Desktop.
Using refinements to monkey patch a reversed `reduce` in Ruby
module Consistency
original = Enumerable.instance_method :reduce
refine Enumerable do
# I didn't actually check it against the real impl or docs or anything, but its something like this
alias_method :inject, define_method(:reduce) { |*args, &block|
block = args.pop if args.size == 2
Enumerator.new do |y|
original.bind(self).call(*args) { |l, r| y.yield r, l }
end.each &block
}
end
end
class A
# # it is reversed
%w[a b c].reduce &:+ # => "abc"
using Consistency
%w[a b c].reduce &:+ # => "cba"
# initial value + a symbol
%w[a b c].reduce "-abc", :+ # => "cba-abc"
# initial value + a block
%w[a b c].reduce "-abc", &:+ # => "cba-abc"
# initial value + a symbol + a block (prefers symbol over block)
%w[a b c].reduce("-abc", :+) { |l, r| r + l } # => "cba-abc"
# chainable
%w[a b c].reduce("!").with_index do |(char, str), index|
"#{str} #{index}:#{char}"
end # => "! 0:a 1:b 2:c"
# wrong number of args
%w[a b c].reduce("", :+, 123) # => #<Enumerator: #<Enumerator::Generator:0x00007fbffc983d20>:each>
end
# no effect outside the lexical scope, we're back to normal
%w[a b c].reduce &:+ # => "abc"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment