SkillAgentSearch skills...

Methodchain

ruby helpers for method chaining: tap, then, else

Install / Use

/learn @gregwebs/Methodchain
About this skill

Quality Score

0/100

Supported Platforms

Universal

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

View on GitHub
GitHub Stars12
CategoryDevelopment
Updated5mo ago
Forks3

Languages

Ruby

Security Score

72/100

Audited on Oct 26, 2025

No findings