Skip to content

Instantly share code, notes, and snippets.

@samstokes
Created November 9, 2010 15:13
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 samstokes/669205 to your computer and use it in GitHub Desktop.
Save samstokes/669205 to your computer and use it in GitHub Desktop.
Map a series of methods successively, plus extra goodies
require 'blankslate'
# Instead of writing
#
# > (1..3).map(&:even?).map(&:to_s).map(&:upcase).map(&:reverse)
# => ["ESLAF", "EURT", "ESLAF"]
#
# write the more concise
#
# > (1..3).map_chain.even?.to_s.upcase.reverse.result
# => ["ESLAF", "EURT", "ESLAF"]
#
#
# You can pass arguments to methods in the chain:
#
# > (1..3).map_chain.*(2).even?.result
# => [true, true, true]
#
# or call arbitrary blocks using _:
#
# > (1..3).map_chain._{|i| i * 2 + 1 }.even?.result
# => [false, false, false]
#
#
# Reuse intermediate results as you'd expect:
#
# > caps = %(foo bar baz).map_chain.upcase
# > caps.result
# => ["FOO", "BAR", "BAZ"]
# > twicecaps = caps._{|str| str * 2 }
# > twicecaps.length.result
# => [6, 6, 6]
# > caps.result
# => ["FOO", "BAR", "BAZ"]
#
#
# Error messages are still helpful in case of typos:
#
# > (1..3).map_chain.even?.non_existent_method
# NoMethodError: undefined method `non_existent_method' for false:FalseClass
module Enumerable
def map_chain
MapChain.new(self)
end
end
class MapChain < BlankSlate
def initialize(receiver); @mappable = receiver; end
def method_missing(sym, *args, &block)
MapChain.new(@mappable.map {|o| o.__send__(sym, *args, &block) })
end
def respond_to?(method)
@mappable.empty? || @mappable.first.respond_to?(method)
end
def _(&block)
yield self
end
def result
@mappable
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment