This repository is private.
All pages are served over SSL and all pushing and pulling is done over SSH.
No one may fork, clone, or view it unless they are added as a member.
Every repository with this icon (
) is private.
Every repository with this icon (
This repository is public.
Anyone may fork, clone, or view it.
Every repository with this icon (
) is public.
Every repository with this icon (
Greg Weber (author)
Wed Nov 26 17:53:17 -0800 2008
commit f9ff210ecfb3668c27bd841d672bf27e43ef23ee
tree 92ae0b296fece2c765ed8513670f34a2b092e76d
parent 6dc628681807d25065021e1427540a4f11913a9c
tree 92ae0b296fece2c765ed8513670f34a2b092e76d
parent 6dc628681807d25065021e1427540a4f11913a9c
| name | age | message | |
|---|---|---|---|
| |
README | Mon Mar 24 12:26:13 -0700 2008 | |
| |
Rakefile | Mon Mar 24 13:51:27 -0700 2008 | |
| |
lib/ | Sat Nov 01 18:41:43 -0700 2008 | |
| |
spec/ | Sat Nov 01 18:41:43 -0700 2008 | |
| |
tasks/ | Wed Nov 26 18:37:05 -0800 2008 |
README
== Summary methodchain - ruby helpers for method chaining: chain, tap, then, else, and, or === Easy ways to navigate around nil without creating local variables. === Initial blog post describing previous ideas: http://blog.thoughtfolder.com/2008-03-16-navigating-nil-method-chaining-in-ruby.html == 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} # or name = person.then {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. ##else is the opposite of #then, and the two methods can be used together 'a'.then{'b'} #=> 'b' nil.then{'b'}.else{'c'} #=> 'c' ==== message sending The normal conditional for ##then and ##else is self if self # inside MethodChain#then # evaluate block end ##then and ##else allow message sending as the conditional. See more examples of message sending with the MethodChain#chain examples below "not empty".then(:empty?) {"N/A"} # => "not empty" "".then(:empty?) {"N/A"} # => "N/A" === ##and, ##or ==== old way Return a default value or the original value depending on whether multiple conditions are met Person = Struct.new(:phone ) blank = Person.new('') # or {:phone => nil} blank.phone && (not blank.phone.empty?) ? blank.phone : "N/A" # => "N/A" p = Person.new('123') p.phone && (not p.phone.empty?) ? p.phone : "N/A" # => "123" ==== new way blank.phone.and {not empty?} || "N/A" # => "N/A" p.phone.and {not empty?} || "N/A" # => "123" === ##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 == 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







