Class: FunctionChain::PullChain

Inherits:
BaseChain show all
Defined in:
lib/function_chain/pull_chain.rb

Overview

PullChain

PullChain is object as represent method call chain. Can inner object’s method call of object.

Chain is object, so can call later.

Supported call chain type is like a

.user.name

Unsupported call chain type is like a

filter3(filter2(filter1(value)))

(RelayChain to support such type.)

Example

Account = Struct.new(:user)
User = Struct.new(:name)
 = Account.new(User.new("Louis"))

chain = PullChain.new(, :user, :name, :upcase)
chain.call # => LOUIS

similar.

# Strings separated by a slash
PullChain.new(, "user/name/upcase").call

# use << operator.
chain = PullChain.new()
chain << :user << :name << :upcase
chain.call

# use add method.
chain.add(:user).add(:name).add(:upcase).call

# use add_all method.
chain.add_all(:user, :name, :upcase).call

can exist nil value on the way, like a following case.

user.name = nil
chain.call # => nil

insert, insert_all method is insert_all method to chain. delete_at method is delete method from chain. clear method is delete all method from chain.

Require arguments on method

Following example is required two arguments.

class Foo
  def say(speaker, message)
    puts "#{speaker} said '#{message}'"
  end
end

Solution1:Array, format is [Symbol, [*Args]].

chain = PullChain.new(Foo.new) << [:say, ["Andres", "Hello"]]
chain.call => Andres said 'Hello'

Solution2:String

chain = PullChain.new(foo) << "say('John', 'Goodbye')"
chain.call => John said 'Goodbye'

Require block on method

[1,2,3,4,5].inject(3) { |sum, n| sum + n } # => 18

Solution1:Array, format is [Symbol, [*Args, Proc]].

chain = PullChain.new([1,2,3,4,5])
chain << [:inject, [3, lambda { |sum, n| sum + n }]]
chain.call # => 18

Solution2:String

chain = PullChain.new([1,2,3,4,5])
chain << "inject(3) { |sum, n| sum + n }"
chain.call # => 18

Use result on chain

Like a following example, can use result on chain. Example1:String

Foo = Struct.new(:bar)
Bar = Struct.new(:baz) {
  def speaker ; "Julian" end
}
class Baz
  def say(speaker, message) puts "#{speaker} said '#{message}'" end
end
foo = Foo.new(Bar.new(Baz.new))

# can use bar instance in backward!
chain = PullChain.new(foo) << "bar/baz/say(bar.speaker, 'Good!')"
chain.call # => Julian said 'Good!'

furthermore, can use variable name assigned.

# @b is bar instance alias.
chain = PullChain.new(foo) << "@b = bar/baz/say(b.speaker, 'Cool')"
chain.call # => Julian said 'Cool'

Example2:Array can access result by Proc.

chain = PullChain.new(foo) << :bar << :baz
chain << [:say, Proc.new { next bar.speaker, "Oh" }]
chain.call # => Julian said 'Oh'

case of use a lambda, can use result access object explicit.

chain = PullChain.new(foo) << :bar << :baz
arg_reader = lambda { |accessor| next accessor.bar.speaker, "Oh" }
chain << [:say, arg_reader]
chain.call # => Julian said 'Oh'

etc

How to use slash in strings separated by a slash. like following, please escaped by backslash.

chain = PullChain.new("AC") << "concat '\\/DC'"
chain.call # => AC/DC

Use return_nil_at_error= method, then can ignore error.

chain = PullChain.new("Test") << :xxx
begin
  chain.call # => undefined method `xxx'
rescue
end
chain.return_nil_at_error = true
chain.call # => nil

Note:use operator in string type chain

table = {name: %w(Bill Scott Paul)}
PullChain.new(table, "[:name]").call # NG
PullChain.new(table, "self[:name]").call # OK
# Array type chain
PullChain.new(table, [:[], [:name]]).call # OK

following is also the same.

# <<operator of String
PullChain.new("Led", "self << ' Zeppelin'").call
# []operator of Array
PullChain.new(%w(Donald Walter), "self[1]").call

Some classes, such Fixnum and Bignum not supported.

# NG
PullChain.new(999999999999999, "self % 2").call

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods inherited from BaseChain

#add, #add_all, #clear, #delete_at, #insert, #insert_all, #to_s

Constructor Details

#initialize(receiver, *functions) ⇒ PullChain

Initialize chain

initialize(receiver, *functions) receiver: starting point of method call. *functions: more than one symbol, string, array.



150
151
152
153
154
# File 'lib/function_chain/pull_chain.rb', line 150

def initialize(receiver, *functions)
  @start_receiver = receiver
  @return_nil_at_error = false
  add_all(*functions)
end

Instance Attribute Details

#return_nil_at_error=(value) ⇒ Object (writeonly)

Sets the attribute return_nil_at_error

Parameters:

  • value

    the value to set the attribute return_nil_at_error to.



143
144
145
# File 'lib/function_chain/pull_chain.rb', line 143

def return_nil_at_error=(value)
  @return_nil_at_error = value
end

Instance Method Details

#callObject

Call to all added method.



157
158
159
160
161
162
163
164
165
166
167
# File 'lib/function_chain/pull_chain.rb', line 157

def call
  @result_accessor = Object.new
  begin
    chain_elements.reduce(@start_receiver) do |receiver, chain_element|
      break receiver if receiver.nil?
      chain_element.call receiver
    end
  rescue
    raise unless return_nil_at_error?
  end
end

#return_nil_at_error?Boolean

Returns:

  • (Boolean)


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

def return_nil_at_error?
  @return_nil_at_error
end