Class: FunctionChain::RelayChain

Inherits:
BaseChain show all
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

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

Returns:

  • (Boolean)


169
170
171
# File 'lib/function_chain/relay_chain.rb', line 169

def last?
  @index == chain_elements.length
end