function_chain 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.coveralls.yml +1 -0
- data/.gitignore +16 -0
- data/.rspec +2 -0
- data/.rubocop.yml +41 -0
- data/.travis.yml +10 -0
- data/Gemfile +20 -0
- data/LICENSE.txt +22 -0
- data/README.md +421 -0
- data/Rakefile +7 -0
- data/function_chain.gemspec +27 -0
- data/lib/function_chain/base_chain.rb +110 -0
- data/lib/function_chain/pull_chain.rb +297 -0
- data/lib/function_chain/relay_chain.rb +251 -0
- data/lib/function_chain/version.rb +3 -0
- data/lib/function_chain.rb +13 -0
- data/spec/function_chain_spec.rb +404 -0
- data/spec/spec_helper.rb +13 -0
- data/tasks/flay.rake +11 -0
- data/tasks/flog.rake +18 -0
- data/tasks/rspec.rake +3 -0
- metadata +68 -0
@@ -0,0 +1,297 @@
|
|
1
|
+
require "function_chain/base_chain"
|
2
|
+
|
3
|
+
module FunctionChain
|
4
|
+
# == PullChain
|
5
|
+
# PullChain is object as represent method call chain.
|
6
|
+
# Can inner object's method call of object.
|
7
|
+
#
|
8
|
+
# Chain is object, so can call later.
|
9
|
+
#
|
10
|
+
# Supported call chain type is like a
|
11
|
+
# account.user.name
|
12
|
+
#
|
13
|
+
# Unsupported call chain type is like a
|
14
|
+
# filter3(filter2(filter1(value)))
|
15
|
+
# (RelayChain to support such type.)
|
16
|
+
#
|
17
|
+
# === Example
|
18
|
+
# Account = Struct.new(:user)
|
19
|
+
# User = Struct.new(:name)
|
20
|
+
# account = Account.new(User.new("Louis"))
|
21
|
+
#
|
22
|
+
# chain = PullChain.new(account, :user, :name, :upcase)
|
23
|
+
# chain.call # => LOUIS
|
24
|
+
#
|
25
|
+
# similar.
|
26
|
+
# # Strings separated by a slash
|
27
|
+
# PullChain.new(account, "user/name/upcase").call
|
28
|
+
#
|
29
|
+
# # use << operator.
|
30
|
+
# chain = PullChain.new(account)
|
31
|
+
# chain << :user << :name << :upcase
|
32
|
+
# chain.call
|
33
|
+
#
|
34
|
+
# # use add method.
|
35
|
+
# chain.add(:user).add(:name).add(:upcase).call
|
36
|
+
#
|
37
|
+
# # use add_all method.
|
38
|
+
# chain.add_all(:user, :name, :upcase).call
|
39
|
+
#
|
40
|
+
# can exist nil value on the way, like a following case.
|
41
|
+
# user.name = nil
|
42
|
+
# chain.call # => nil
|
43
|
+
#
|
44
|
+
# insert, insert_all method is insert_all method to chain.
|
45
|
+
# delete_at method is delete method from chain.
|
46
|
+
# clear method is delete all method from chain.
|
47
|
+
#
|
48
|
+
# === Require arguments on method
|
49
|
+
# Following example is required two arguments.
|
50
|
+
# class Foo
|
51
|
+
# def say(speaker, message)
|
52
|
+
# puts "#{speaker} said '#{message}'"
|
53
|
+
# end
|
54
|
+
# end
|
55
|
+
#
|
56
|
+
# Solution1:Array, format is [Symbol, [*Args]].
|
57
|
+
# chain = PullChain.new(Foo.new) << [:say, ["Andres", "Hello"]]
|
58
|
+
# chain.call => Andres said 'Hello'
|
59
|
+
#
|
60
|
+
# Solution2:String
|
61
|
+
# chain = PullChain.new(foo) << "say('John', 'Goodbye')"
|
62
|
+
# chain.call => John said 'Goodbye'
|
63
|
+
#
|
64
|
+
# === Require block on method
|
65
|
+
# [1,2,3,4,5].inject(3) { |sum, n| sum + n } # => 18
|
66
|
+
#
|
67
|
+
# Solution1:Array, format is [Symbol, [*Args, Proc]].
|
68
|
+
# chain = PullChain.new([1,2,3,4,5])
|
69
|
+
# chain << [:inject, [3, lambda { |sum, n| sum + n }]]
|
70
|
+
# chain.call # => 18
|
71
|
+
#
|
72
|
+
# Solution2:String
|
73
|
+
# chain = PullChain.new([1,2,3,4,5])
|
74
|
+
# chain << "inject(3) { |sum, n| sum + n }"
|
75
|
+
# chain.call # => 18
|
76
|
+
#
|
77
|
+
# === Use result on chain
|
78
|
+
# Like a following example, can use result on chain.
|
79
|
+
# Example1:String
|
80
|
+
# Foo = Struct.new(:bar)
|
81
|
+
# Bar = Struct.new(:baz) {
|
82
|
+
# def speaker ; "Julian" end
|
83
|
+
# }
|
84
|
+
# class Baz
|
85
|
+
# def say(speaker, message) puts "#{speaker} said '#{message}'" end
|
86
|
+
# end
|
87
|
+
# foo = Foo.new(Bar.new(Baz.new))
|
88
|
+
#
|
89
|
+
# # can use bar instance in backward!
|
90
|
+
# chain = PullChain.new(foo) << "bar/baz/say(bar.speaker, 'Good!')"
|
91
|
+
# chain.call # => Julian said 'Good!'
|
92
|
+
#
|
93
|
+
# furthermore, can use variable name assigned.
|
94
|
+
# # @b is bar instance alias.
|
95
|
+
# chain = PullChain.new(foo) << "@b = bar/baz/say(b.speaker, 'Cool')"
|
96
|
+
# chain.call # => Julian said 'Cool'
|
97
|
+
#
|
98
|
+
# Example2:Array
|
99
|
+
# can access result by Proc.
|
100
|
+
# chain = PullChain.new(foo) << :bar << :baz
|
101
|
+
# chain << [:say, Proc.new { next bar.speaker, "Oh" }]
|
102
|
+
# chain.call # => Julian said 'Oh'
|
103
|
+
#
|
104
|
+
# case of use a lambda, can use result access object explicit.
|
105
|
+
# chain = PullChain.new(foo) << :bar << :baz
|
106
|
+
# arg_reader = lambda { |accessor| next accessor.bar.speaker, "Oh" }
|
107
|
+
# chain << [:say, arg_reader]
|
108
|
+
# chain.call # => Julian said 'Oh'
|
109
|
+
#
|
110
|
+
# === etc
|
111
|
+
# How to use slash in strings separated by a slash.
|
112
|
+
# like following, please escaped by backslash.
|
113
|
+
# chain = PullChain.new("AC") << "concat '\\/DC'"
|
114
|
+
# chain.call # => AC/DC
|
115
|
+
#
|
116
|
+
# Use return_nil_at_error= method, then can ignore error.
|
117
|
+
# chain = PullChain.new("Test") << :xxx
|
118
|
+
# begin
|
119
|
+
# chain.call # => undefined method `xxx'
|
120
|
+
# rescue
|
121
|
+
# end
|
122
|
+
# chain.return_nil_at_error = true
|
123
|
+
# chain.call # => nil
|
124
|
+
#
|
125
|
+
# Note:use operator in string type chain
|
126
|
+
# table = {name: %w(Bill Scott Paul)}
|
127
|
+
# PullChain.new(table, "[:name]").call # NG
|
128
|
+
# PullChain.new(table, "self[:name]").call # OK
|
129
|
+
# # Array type chain
|
130
|
+
# PullChain.new(table, [:[], [:name]]).call # OK
|
131
|
+
#
|
132
|
+
# following is also the same.
|
133
|
+
# # <<operator of String
|
134
|
+
# PullChain.new("Led", "self << ' Zeppelin'").call
|
135
|
+
# # []operator of Array
|
136
|
+
# PullChain.new(%w(Donald Walter), "self[1]").call
|
137
|
+
#
|
138
|
+
# Some classes, such Fixnum and Bignum not supported.
|
139
|
+
# # NG
|
140
|
+
# PullChain.new(999999999999999, "self % 2").call
|
141
|
+
#
|
142
|
+
class PullChain < BaseChain
|
143
|
+
attr_writer :return_nil_at_error
|
144
|
+
|
145
|
+
# Initialize chain
|
146
|
+
#
|
147
|
+
# initialize(receiver, *functions)
|
148
|
+
# receiver: starting point of method call.
|
149
|
+
# *functions: more than one symbol, string, array.
|
150
|
+
def initialize(receiver, *functions)
|
151
|
+
@start_receiver = receiver
|
152
|
+
@return_nil_at_error = false
|
153
|
+
add_all(*functions)
|
154
|
+
end
|
155
|
+
|
156
|
+
# Call to all added method.
|
157
|
+
def call
|
158
|
+
@result_accessor = Object.new
|
159
|
+
begin
|
160
|
+
chain_elements.reduce(@start_receiver) do |receiver, chain_element|
|
161
|
+
break receiver if receiver.nil?
|
162
|
+
chain_element.call receiver
|
163
|
+
end
|
164
|
+
rescue
|
165
|
+
raise unless return_nil_at_error?
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
def return_nil_at_error?
|
170
|
+
@return_nil_at_error
|
171
|
+
end
|
172
|
+
|
173
|
+
private
|
174
|
+
|
175
|
+
attr_accessor :result_accessor
|
176
|
+
|
177
|
+
def create_common_chain_element(&block)
|
178
|
+
lambda do |receiver|
|
179
|
+
name, result = block.call(receiver)
|
180
|
+
define_result_access_method(name, result)
|
181
|
+
result
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
def define_result_access_method(name, result)
|
186
|
+
result_accessor.singleton_class.class_eval do
|
187
|
+
define_method name do
|
188
|
+
result
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
def create_chain_element_by_symbol(symbol)
|
194
|
+
create_common_chain_element do |receiver|
|
195
|
+
next symbol, execute(receiver, symbol)
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
def create_chain_element_by_array(array)
|
200
|
+
validate_array_length(array, 2, "symbol, [*args] or Proc")
|
201
|
+
validate_element_type_of_array(array, 1, [Array, Proc], "[*args] or Proc")
|
202
|
+
|
203
|
+
do_create_chain_element_by_array(array[0], array[1])
|
204
|
+
end
|
205
|
+
|
206
|
+
def do_create_chain_element_by_array(name, array_function_param)
|
207
|
+
create_common_chain_element do |receiver|
|
208
|
+
args, block = extract_args_and_block(array_function_param)
|
209
|
+
next name, execute(receiver, name, *args, &block)
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
def extract_args_and_block(array_function_param)
|
214
|
+
if array_function_param.is_a? Proc
|
215
|
+
return result_accessor.instance_eval(&array_function_param)
|
216
|
+
end
|
217
|
+
if array_function_param.last.is_a? Proc
|
218
|
+
return array_function_param[0...-1], array_function_param.last
|
219
|
+
end
|
220
|
+
array_function_param
|
221
|
+
end
|
222
|
+
|
223
|
+
def create_chain_element_by_string(string)
|
224
|
+
name, function = split_to_name_and_function(string)
|
225
|
+
create_common_chain_element do |receiver|
|
226
|
+
next name, execute_by_string(receiver, function)
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
def split_to_name_and_function(string)
|
231
|
+
name = string
|
232
|
+
function = string
|
233
|
+
|
234
|
+
md = string.match(/^@.+?=/)
|
235
|
+
if md
|
236
|
+
name = md[0][1...-1].strip
|
237
|
+
validate_variable_name_format(name)
|
238
|
+
function = string.sub(md[0], "").strip
|
239
|
+
end
|
240
|
+
|
241
|
+
return name, function
|
242
|
+
end
|
243
|
+
|
244
|
+
def validate_variable_name_format(name)
|
245
|
+
if name =~ /^[^a-zA-Z_]/
|
246
|
+
fail ArgumentError, "wrong format variable defined #{name}"
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
def execute(receiver, name, *args, &block)
|
251
|
+
receiver.__send__(name, *args, &block)
|
252
|
+
end
|
253
|
+
|
254
|
+
def execute_by_string(receiver, function)
|
255
|
+
begin
|
256
|
+
inject_result_accessor(receiver)
|
257
|
+
receiver.instance_eval(function)
|
258
|
+
rescue => ex
|
259
|
+
raise ex, "#{receiver}.#{function}"
|
260
|
+
ensure
|
261
|
+
eject_result_accessor(receiver)
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
def inject_result_accessor(receiver)
|
266
|
+
store_method_missing(receiver)
|
267
|
+
define_intercepted_method_missing(receiver)
|
268
|
+
end
|
269
|
+
|
270
|
+
def store_method_missing(receiver)
|
271
|
+
receiver.singleton_class.class_eval do
|
272
|
+
alias_method :original_method_missing, :method_missing
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
def define_intercepted_method_missing(receiver)
|
277
|
+
# interception method_missing
|
278
|
+
accessor = result_accessor
|
279
|
+
receiver.singleton_class.class_eval do
|
280
|
+
define_method :method_missing do |name, *args, &block|
|
281
|
+
super(name, *args, &block) unless accessor.respond_to? name
|
282
|
+
accessor.send(name, *args, &block)
|
283
|
+
end
|
284
|
+
end
|
285
|
+
end
|
286
|
+
|
287
|
+
def eject_result_accessor(receiver)
|
288
|
+
# cleanup to interception
|
289
|
+
receiver.singleton_class.class_eval do
|
290
|
+
alias_method :method_missing, :original_method_missing
|
291
|
+
undef_method :original_method_missing
|
292
|
+
end
|
293
|
+
end
|
294
|
+
|
295
|
+
alias_method :<<, :add
|
296
|
+
end
|
297
|
+
end
|
@@ -0,0 +1,251 @@
|
|
1
|
+
require "function_chain/base_chain"
|
2
|
+
|
3
|
+
module FunctionChain
|
4
|
+
# == RelayChain
|
5
|
+
# RelayChain is object like a connect to
|
6
|
+
# function's input from function's output.
|
7
|
+
# (methods well as can connect Proc.)
|
8
|
+
#
|
9
|
+
# Chain is object, so can call later.
|
10
|
+
#
|
11
|
+
# Supported call chain type is like a
|
12
|
+
# filter3(filter2(filter1(value))).
|
13
|
+
#
|
14
|
+
# Unsupported call chain type is like a
|
15
|
+
# account.user.name
|
16
|
+
# (PullChain to support such type.)
|
17
|
+
#
|
18
|
+
# === Example
|
19
|
+
# class Decorator
|
20
|
+
# def decorate1(value)
|
21
|
+
# "( #{value} )"
|
22
|
+
# end
|
23
|
+
# def decorate2(value)
|
24
|
+
# "{ #{value} }"
|
25
|
+
# end
|
26
|
+
# end
|
27
|
+
# chain = RelayChain.new(Decorator.new, :decorate1, :decorate2)
|
28
|
+
# chain.call("Hello") # => { ( Hello ) }
|
29
|
+
#
|
30
|
+
# similar.
|
31
|
+
# # Strings separated by a slash
|
32
|
+
# chain = RelayChain.new(Decorator.new, "decorate1/decorate2")
|
33
|
+
# chain.call("Hello")
|
34
|
+
#
|
35
|
+
# # use >> operator.
|
36
|
+
# chain = RelayChain.new(Decorator.new)
|
37
|
+
# chain >> :decorate1 >> :decorate2
|
38
|
+
# chain.call("Hello")
|
39
|
+
#
|
40
|
+
# # use Method object
|
41
|
+
# chain = RelayChain.new
|
42
|
+
# chain >> decorator.method(:decorate1) >> decorator.method(:decorate2)
|
43
|
+
# chain.call("Hello")
|
44
|
+
#
|
45
|
+
# # use add method
|
46
|
+
# chain.add(:decorate1).add(:decorate2).call("Hello")
|
47
|
+
#
|
48
|
+
# # use add_all method
|
49
|
+
# chain.add_all(:decorate1, :decorate2).call("Hello")
|
50
|
+
#
|
51
|
+
# insert, insert_all method is insert function to chain.
|
52
|
+
# delete_at method is delete function from chain.
|
53
|
+
# clear method is delete all function from chain.
|
54
|
+
#
|
55
|
+
# === How to connect method of differed instance
|
56
|
+
# Example, following two class.
|
57
|
+
# Introduce how to connect method of these class.
|
58
|
+
# class Decorator
|
59
|
+
# def decorate1(value) "( #{value} )" end
|
60
|
+
# def decorate2(value) "{ #{value} }" end
|
61
|
+
# end
|
62
|
+
# class Decorator2
|
63
|
+
# def decorate(value) "[ #{value} ]" end
|
64
|
+
# end
|
65
|
+
#
|
66
|
+
# Solution1:Array, format is [instance, Symbol or String of method]
|
67
|
+
# chain = RelayChain.new(Decorator.new)
|
68
|
+
# chain >> :decorate1 >> :decorate2 >> [Decorator2.new, :decorate]
|
69
|
+
# # String ver.
|
70
|
+
# # chain >> :decorate1 >> :decorate2 >> [Decorator2.new, "decorate"]
|
71
|
+
# chain.call("Hello") # => [ { ( Hello ) } ]
|
72
|
+
#
|
73
|
+
# Solution2:String, use registered instance.
|
74
|
+
# chain = RelayChain.new(Decorator.new)
|
75
|
+
# # register name and instance
|
76
|
+
# chain.add_receiver("d2", Decorator2.new)
|
77
|
+
# # use registered instance
|
78
|
+
# chain >> "/decorate1/decorate2/d2.decorate"
|
79
|
+
# chain.call("Hello") # => [ { ( Hello ) } ]
|
80
|
+
#
|
81
|
+
# # add_receiver_table method is register name and instance at once.
|
82
|
+
# chain.add_receiver_table({"x" => X.new, "y" => Y.new})
|
83
|
+
#
|
84
|
+
# === Case of method's output and method's input mismatch
|
85
|
+
# Following example, decorate output is 1, and union input is 2.
|
86
|
+
# How to do connect these methods?
|
87
|
+
# class Decorator
|
88
|
+
# def decorate(value)
|
89
|
+
# "#{value} And"
|
90
|
+
# end
|
91
|
+
# def union(value1, value2)
|
92
|
+
# "#{value1} #{value2}"
|
93
|
+
# end
|
94
|
+
# end
|
95
|
+
#
|
96
|
+
# Solution1:define connect method.
|
97
|
+
# class Decorator
|
98
|
+
# def connect(value)
|
99
|
+
# return value, "Palmer"
|
100
|
+
# end
|
101
|
+
# end
|
102
|
+
# chain = RelayChain.new(Decorator.new)
|
103
|
+
# chain >> :decorate >> :connect >> :union
|
104
|
+
# chain.call("Emerson, Lake") # => Emerson, Lake And Palmer
|
105
|
+
#
|
106
|
+
# Solution2:add lambda or Proc to between these methods.
|
107
|
+
# lambda's format is following.
|
108
|
+
# lambda {|chain, *args| chain.call(next function's arguments) }.
|
109
|
+
# lambda's parameter:chain is chain object.
|
110
|
+
# lambda's parameter:*args is previous function's output.
|
111
|
+
# can call next function by chain object.
|
112
|
+
#
|
113
|
+
# chain = RelayChain.new(Decorator.new)
|
114
|
+
# arg_adder = lambda { |chain, value| chain.call(value, "Jerry") }
|
115
|
+
# chain >> :decorate >> arg_adder >> :union
|
116
|
+
# chain.call("Tom") # => Tom And Jerry
|
117
|
+
#
|
118
|
+
# === Appendix
|
119
|
+
# Chain stop by means of lambda.
|
120
|
+
#
|
121
|
+
# class Decorator
|
122
|
+
# def decorate1(value) "( #{value} )" end
|
123
|
+
# def decorate2(value) "{ #{value} }" end
|
124
|
+
# end
|
125
|
+
#
|
126
|
+
# def create_stopper(&stop_condition)
|
127
|
+
# lambda do |chain, value|
|
128
|
+
# # if stop conditions are met then return value
|
129
|
+
# if stop_condition.call(value)
|
130
|
+
# value
|
131
|
+
# else
|
132
|
+
# chain.call(value)
|
133
|
+
# end
|
134
|
+
# end
|
135
|
+
# end
|
136
|
+
#
|
137
|
+
# chain = RelayChain.new(Decorator.new, :decorate1, :decorate2)
|
138
|
+
#
|
139
|
+
# # insert_all conditional chain stopper
|
140
|
+
# chain.insert(1, create_stopper { |value| value =~ /\d/ })
|
141
|
+
# chain.call("Van Halen 1984") # => ( Van Halen 1984 ) not enclosed to {}
|
142
|
+
# chain.call("Van Halen Jump") # => { ( Van Halen Jump ) } enclosed to {}
|
143
|
+
#
|
144
|
+
class RelayChain < BaseChain
|
145
|
+
# Initialize chain
|
146
|
+
#
|
147
|
+
# initialize(common_receiver = nil, *functions)
|
148
|
+
# common_receiver:used if the instance is omitted
|
149
|
+
# *functions: more than one symbol, string, array, method, proc
|
150
|
+
def initialize(common_receiver = nil, *functions)
|
151
|
+
@common_receiver = common_receiver
|
152
|
+
@index = 0
|
153
|
+
add_all(*functions)
|
154
|
+
end
|
155
|
+
|
156
|
+
# Call to all added function.
|
157
|
+
def call(*args)
|
158
|
+
begin
|
159
|
+
return if last?
|
160
|
+
chain_element = chain_elements[@index]
|
161
|
+
@index += 1
|
162
|
+
chain_element.call(self, *args)
|
163
|
+
ensure
|
164
|
+
@index = 0
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
# Whether chain last
|
169
|
+
def last?
|
170
|
+
@index == chain_elements.length
|
171
|
+
end
|
172
|
+
|
173
|
+
# add receiver
|
174
|
+
# use by string type function.
|
175
|
+
#
|
176
|
+
# add_receiver(name, receiver)
|
177
|
+
# name:receiver's name
|
178
|
+
# receiver:register this receiver
|
179
|
+
def add_receiver(name, receiver)
|
180
|
+
receiver_table[name] = receiver
|
181
|
+
self
|
182
|
+
end
|
183
|
+
|
184
|
+
# register name and instance at once.
|
185
|
+
#
|
186
|
+
# add_receiver_table(table)
|
187
|
+
# table:hash {receiver's name as String => receiver, ...}
|
188
|
+
def add_receiver_table(table)
|
189
|
+
receiver_table.merge! table
|
190
|
+
self
|
191
|
+
end
|
192
|
+
|
193
|
+
protected
|
194
|
+
|
195
|
+
def supported_types
|
196
|
+
super() | [Method, Proc]
|
197
|
+
end
|
198
|
+
|
199
|
+
private
|
200
|
+
|
201
|
+
def create_chain_element(function)
|
202
|
+
case function
|
203
|
+
when Method then create_chain_element_by_method(function)
|
204
|
+
when Proc then function
|
205
|
+
else super(function)
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
def create_common_chain_element(&block)
|
210
|
+
lambda do |chain, *args|
|
211
|
+
chain.last? ? block.call(*args) : chain.call(*block.call(*args))
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
def create_chain_element_by_method(method)
|
216
|
+
create_common_chain_element { |*args| method.call(*args) }
|
217
|
+
end
|
218
|
+
|
219
|
+
def create_chain_element_by_array(arr)
|
220
|
+
validate_array_length(arr, 2, "receiver, symbol or string of receiver's method name")
|
221
|
+
validate_element_type_of_array(arr, 1, [Symbol, String], "[Symbol or String]")
|
222
|
+
|
223
|
+
create_common_chain_element { |*args| arr[0].__send__(arr[1], *args) }
|
224
|
+
end
|
225
|
+
|
226
|
+
def create_chain_element_by_symbol(symbol)
|
227
|
+
create_common_chain_element do |*args|
|
228
|
+
@common_receiver.__send__(symbol, *args)
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
def create_chain_element_by_string(string)
|
233
|
+
create_common_chain_element do |*args|
|
234
|
+
index = string.index(".")
|
235
|
+
if index
|
236
|
+
receiver_key = string[0...index]
|
237
|
+
receiver_method = string[index + 1..-1]
|
238
|
+
receiver_table[receiver_key].send(receiver_method, *args)
|
239
|
+
else
|
240
|
+
@common_receiver.__send__(string, *args)
|
241
|
+
end
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
def receiver_table
|
246
|
+
@receiver_table ||= {}
|
247
|
+
end
|
248
|
+
|
249
|
+
alias_method :>>, :add
|
250
|
+
end
|
251
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require "function_chain/version"
|
2
|
+
require "function_chain/pull_chain"
|
3
|
+
require "function_chain/relay_chain"
|
4
|
+
|
5
|
+
module FunctionChain
|
6
|
+
module_function
|
7
|
+
|
8
|
+
# Shortcut to
|
9
|
+
# PullChain.new(receiver, *functions).call
|
10
|
+
def pull(receiver, *functions)
|
11
|
+
PullChain.new(receiver, *functions).call
|
12
|
+
end
|
13
|
+
end
|