Sample class to demonstrate chaining methods that return a copied instance without modifying the caller.
This might be a lib required by your app.
class Foo
attr_accessor :field
def initialize
@field=[]
end
def dup
# Note: objects in @field aren't dup'ed!
super.tap{|e| e.field=e.field.dup }
end
def a
dup.tap{|e| e.field << :a }
end
def b
dup.tap{|e| e.field << :b }
end
def c
dup.tap{|e| e.field << :c }
end
end
monkeypatch: this is what you want to add to your app to enable conditional chaining
class Object
# passes self to block and returns result of block.
# More cumbersome to call than #chain_if, but useful if you want to put
# complex conditions in the block, or call a different method when your cond is false.
def chain_block(&block)
yield self
end
# passes self to block
# bool:
# if false, returns caller without executing block.
# if true, return result of block.
# Useful if your condition is simple, and you want to merely pass along the previous caller in the chain if false.
def chain_if(bool, &block)
bool ? yield(self) : self
end
end
Sample usage
# sample usage: chain_block
>> cond_a, cond_b, cond_c = true, false, true
>> f.chain_block{|e| cond_a ? e.a : e }.chain_block{|e| cond_b ? e.b : e }.chain_block{|e| cond_c ? e.c : e }
=> #<Foo:0x007fe71027ab60 @field=[:a, :c]>
# sample usage: chain_if
>> cond_a, cond_b, cond_c = false, true, false
>> f.chain_if(cond_a, &:a).chain_if(cond_b, &:b).chain_if(cond_c, &:c)
=> #<Foo:0x007fe7106a7e90 @field=[:b]>
# The chain_if call can also allow args
>> obj.chain_if(cond) {|e| e.argified_method(args) }