Class: FunctionChain::RelayChain
- Defined in:
- lib/function_chain/relay_chain.rb
Overview
RelayChain
RelayChain is object like a connect to function’s input from function’s output. (methods well as can connect Proc.)
Chain is object, so can call later.
Supported call chain type is like a
filter3(filter2(filter1(value))).
Unsupported call chain type is like a
account.user.name
(PullChain to support such type.)
Example
class Decorator
def decorate1(value)
"( #{value} )"
end
def decorate2(value)
"{ #{value} }"
end
end
chain = RelayChain.new(Decorator.new, :decorate1, :decorate2)
chain.call("Hello") # => { ( Hello ) }
similar.
# Strings separated by a slash
chain = RelayChain.new(Decorator.new, "decorate1/decorate2")
chain.call("Hello")
# use >> operator.
chain = RelayChain.new(Decorator.new)
chain >> :decorate1 >> :decorate2
chain.call("Hello")
# use Method object
chain = RelayChain.new
chain >> decorator.method(:decorate1) >> decorator.method(:decorate2)
chain.call("Hello")
# use add method
chain.add(:decorate1).add(:decorate2).call("Hello")
# use add_all method
chain.add_all(:decorate1, :decorate2).call("Hello")
insert, insert_all method is insert function to chain. delete_at method is delete function from chain. clear method is delete all function from chain.
How to connect method of differed instance
Example, following two class. Introduce how to connect method of these class.
class Decorator
def decorate1(value) "( #{value} )" end
def decorate2(value) "{ #{value} }" end
end
class Decorator2
def decorate(value) "[ #{value} ]" end
end
Solution1:Array, format is [instance, Symbol or String of method]
chain = RelayChain.new(Decorator.new)
chain >> :decorate1 >> :decorate2 >> [Decorator2.new, :decorate]
# String ver.
# chain >> :decorate1 >> :decorate2 >> [Decorator2.new, "decorate"]
chain.call("Hello") # => [ { ( Hello ) } ]
Solution2:String, use registered instance.
chain = RelayChain.new(Decorator.new)
# register name and instance
chain.add_receiver("d2", Decorator2.new)
# use registered instance
chain >> "/decorate1/decorate2/d2.decorate"
chain.call("Hello") # => [ { ( Hello ) } ]
# add_receiver_table method is register name and instance at once.
chain.add_receiver_table({"x" => X.new, "y" => Y.new})
Case of method’s output and method’s input mismatch
Following example, decorate output is 1, and union input is 2. How to do connect these methods?
class Decorator
def decorate(value)
"#{value} And"
end
def union(value1, value2)
"#{value1} #{value2}"
end
end
Solution1:define connect method.
class Decorator
def connect(value)
return value, "Palmer"
end
end
chain = RelayChain.new(Decorator.new)
chain >> :decorate >> :connect >> :union
chain.call("Emerson, Lake") # => Emerson, Lake And Palmer
Solution2:add lambda or Proc to between these methods.
lambda's format is following.
lambda {|chain, *args| chain.call(next function's arguments) }.
lambda's parameter:chain is chain object.
lambda's parameter:*args is previous function's output.
can call next function by chain object.
chain = RelayChain.new(Decorator.new)
arg_adder = lambda { |chain, value| chain.call(value, "Jerry") }
chain >> :decorate >> arg_adder >> :union
chain.call("Tom") # => Tom And Jerry
Appendix
Chain stop by means of lambda.
class Decorator
def decorate1(value) "( #{value} )" end
def decorate2(value) "{ #{value} }" end
end
def create_stopper(&stop_condition)
lambda do |chain, value|
# if stop conditions are met then return value
if stop_condition.call(value)
value
else
chain.call(value)
end
end
end
chain = RelayChain.new(Decorator.new, :decorate1, :decorate2)
# insert_all conditional chain stopper
chain.insert(1, create_stopper { |value| value =~ /\d/ })
chain.call("Van Halen 1984") # => ( Van Halen 1984 ) not enclosed to {}
chain.call("Van Halen Jump") # => { ( Van Halen Jump ) } enclosed to {}
Instance Method Summary collapse
-
#add_receiver(name, receiver) ⇒ Object
add receiver use by string type function.
-
#add_receiver_table(table) ⇒ Object
register name and instance at once.
-
#call(*args) ⇒ Object
Call to all added function.
-
#initialize(common_receiver = nil, *functions) ⇒ RelayChain
constructor
Initialize chain.
-
#last? ⇒ Boolean
Whether chain last.
Methods inherited from BaseChain
#add, #add_all, #clear, #delete_at, #insert, #insert_all, #to_s
Constructor Details
#initialize(common_receiver = nil, *functions) ⇒ RelayChain
Initialize chain
initialize(common_receiver = nil, *functions) common_receiver:used if the instance is omitted *functions: more than one symbol, string, array, method, proc
150 151 152 153 154 |
# File 'lib/function_chain/relay_chain.rb', line 150 def initialize(common_receiver = nil, *functions) @common_receiver = common_receiver @index = 0 add_all(*functions) end |
Instance Method Details
#add_receiver(name, receiver) ⇒ Object
add receiver use by string type function.
add_receiver(name, receiver) name:receiver’s name receiver:register this receiver
179 180 181 182 |
# File 'lib/function_chain/relay_chain.rb', line 179 def add_receiver(name, receiver) receiver_table[name] = receiver self end |
#add_receiver_table(table) ⇒ Object
register name and instance at once.
add_receiver_table(table) table:hash name as String => receiver, …
188 189 190 191 |
# File 'lib/function_chain/relay_chain.rb', line 188 def add_receiver_table(table) receiver_table.merge! table self end |
#call(*args) ⇒ Object
Call to all added function.
157 158 159 160 161 162 163 164 165 166 |
# File 'lib/function_chain/relay_chain.rb', line 157 def call(*args) begin return if last? chain_element = chain_elements[@index] @index += 1 chain_element.call(self, *args) ensure @index = 0 end end |
#last? ⇒ Boolean
Whether chain last
169 170 171 |
# File 'lib/function_chain/relay_chain.rb', line 169 def last? @index == chain_elements.length end |