== Summary methodchain - ruby helpers for method chaining: chain, tap, then, else Easy ways to navigate around nil without creating local variables. == Author and License Copyright (c) 2008 Greg Weber, http://gregweber.info Licensed under the MIT license == Examples === ##then and ##else ==== old way person = nil name = person ? person.name : nil ==== new way name = person.then {|p| p.name} not a huge savings. But sometimes the person variable is actually a function call, and then we must save it in a variable first. ==== old way def find(*args) # do some expensive database queries end person = find(:first) @phone = person && person.phone # => nil ==== new way @phone = find(:first).then {phone} # => nil We have reduced a line of code and removed a local variable. #then and #else can return a default value instead of evaluating a block 'a'.then('b') #=> 'b' nil.then('b').else('c') #=> 'c' === ##tap if you don't already know about this method, look it up on the net. The tap included here allows message sending. ==== old way arr = [1] arr.compact! # => nil arr.first # => 1 ==== normal ##tap (still valid) [1].tap {|arr| arr.compact!}.first # => 1 ==== new ##tap [1].tap(:compact!).first # => 1 ==== normal ##tap (still valid) [1].tap {|arr| arr.compact!}.tap {|arr| arr * 2}.first # => 1 ==== new ##tap [1].tap( :compact!, [:*, 2] ).first # => 1 You can also pass Procs as arguments [1].tap( :compact!, lambda{|arr| arr * 2} ).first # => 1 === ##chain chain is like tap, but instead of always returning self, it will return the result of the method call. [1].chain(:first) == [1].first But there is an important difference- chain guards against certain results (by default it guards against nil and false) ==== old way customer = nil customer && customer.order && customer.order.id ==== new way customer.chain(:order, :id) note that this is equivalent to customer.then {order}.then {id} === ##chain - Custom guards, multiple arguments, and Procs ==== old way - guarding against zero value = 0 result = if value == 0 then value else tmp = value.abs if tmp == 0 then tmp else tmp * 20 end end result # => 0 ==== new way value.chain(:abs, [:*, 20]) {|s| s == 0 } # => 0 Procs can be used, so this is equivalent to value.chain(:abs, lambda {|n| n * 20 }) {|s| s == 0 } # => 0 == Usage require 'rubygems' === import all MethodChain methods into Object require 'methodchain' === selectively import MethodChain methods require 'methodchain/not-included' You can then include methodchain into selected classes, or you can use the module-import gem to include only certain methods gem install module-import require 'module-import' class Object import MethodChain, :chain # I only want Object#chain end import will still load all the private methods from the module: - yield_or_eval - send_as_function - send_as_functions ==== not into Object To import nothing into the Object namespace require 'methodchain/no-import' Then include where needed: class MyObject include MethodChain end == Implementation There are no proxy objects and no use of method_missing- these are simply function calls, so it should be fast. private methods: * yield_or_eval: allows the two different block forms {|p| p.name} and {name}, where the first form yields self and the second form is called using instance_eval. * send_as_function: allows symbols and arrays to be sent as messages, and calls yield_or_eval on Proc arguments * send_as_functions: def send_arguments_as_functions *args args.each {|arg| send_as_function arg} self end == Install gem install methodchain == Source === browser http://github.com/gregwebs/methodchain/tree/master === repository git clone git://github.com/gregwebs/methodchain.git == Homepage http://gregweber.info/projects/methodchain.html == RDoc documentation included with gem