function_chain 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,404 @@
1
+ require "spec_helper"
2
+
3
+ describe FunctionChain::PullChain do
4
+
5
+ before(:context) do
6
+ City = Struct.new(:bookstore)
7
+ BookStore = Struct.new(:shelves, :recommended_shelf)
8
+ Shelf = Struct.new(:books, :recommended_book_num)
9
+ Book = Struct.new(:title, :author)
10
+
11
+ programing_books = []
12
+ programing_books << Book.new("The Ruby Programming Language",
13
+ "David Flanagan and Yukihiro Matsumoto")
14
+ programing_books << Book.new("Ruby Best Practices", "Gregory T Brown")
15
+ programing_books << Book.new("Metaprogramming Ruby", "Paolo Perrotta")
16
+
17
+ mystery_books = []
18
+ mystery_books << Book.new("And Then There Were None", "Agatha Christie")
19
+ mystery_books << Book.new("Tragedy of X", "Ellery Queen")
20
+
21
+ shelves = {
22
+ programing: Shelf.new(programing_books, 0),
23
+ mystery: Shelf.new(mystery_books, 1)
24
+ }
25
+ @city = City.new(BookStore.new(shelves, :mystery))
26
+
27
+ PullChain = FunctionChain::PullChain
28
+ end
29
+
30
+ it "[success case] symbol type function" do
31
+ chain = PullChain.new(@city) << :bookstore << :shelves
32
+ expect(chain.call).to eq(@city.bookstore.shelves)
33
+ end
34
+
35
+ it "[success case] array type function with args [:symbol, [args]]" do
36
+ chain = PullChain.new(@city)
37
+ chain << :bookstore << :shelves << [:[], [:mystery]]
38
+ expect(chain.call).to eq(@city.bookstore.shelves[:mystery])
39
+ end
40
+
41
+ it "[success case] array type function with args [:symbol, [proc]" do
42
+ chain = PullChain.new([1, 2, 3, 4, 5])
43
+ chain << [:find_all, [lambda { |n| n.even? }]]
44
+ expect(chain.call).to eq([2, 4])
45
+ end
46
+
47
+ it "[success case] array type function with args [:symbol, [arg, proc]]" do
48
+ chain = PullChain.new([1, 2, 3, 4, 5])
49
+ chain << [:inject, [0, lambda { |sum, n| sum + n }]]
50
+ expect(chain.call).to eq(15)
51
+ end
52
+
53
+ it "[success case] array type function with args [:symbol, [args, proc]]" do
54
+ chain = PullChain.new(self)
55
+ def block_caller(v1, v2, v3, v4, &block)
56
+ block.call(v1, v2, v3, v4)
57
+ end
58
+ union_args = lambda { |v1, v2, v3, v4| "#{v1}&#{v2}&#{v3}&#{v4}" }
59
+ chain << [:block_caller, [2, 4, 6, 8, union_args]]
60
+ expect(chain.call).to eq("2&4&6&8")
61
+ end
62
+
63
+ it "[success case] array type function with proc [:symbol, Proc]" do
64
+ chain = PullChain.new(@city) << :bookstore
65
+ chain << :shelves << [:[], Proc.new { |_| bookstore.recommended_shelf }]
66
+ expect(chain.call).to eq(@city.bookstore.shelves[:mystery])
67
+ end
68
+
69
+ it "[success case] string type function" do
70
+ chain = PullChain.new(@city)
71
+ chain << "/bookstore/shelves[:programing]/books[1]/title"
72
+ title = @city.bookstore.shelves[:programing].books[1].title
73
+ expect(chain.call).to eq(title)
74
+ end
75
+
76
+ it "[success case] string type function, add a plurality of times" do
77
+ chain = PullChain.new(@city)
78
+ chain << "/bookstore/shelves[:programing]"
79
+ chain << "/books[1]/title"
80
+ title = @city.bookstore.shelves[:programing].books[1].title
81
+ expect(chain.call).to eq(title)
82
+ end
83
+
84
+ it "[success case] string type function, with reference" do
85
+ chain = PullChain.new(@city)
86
+ chain << "/bookstore/shelves[bookstore.recommended_shelf]/books[0]/author"
87
+ store = @city.bookstore
88
+ author = @city.bookstore.shelves[store.recommended_shelf].books[0].author
89
+ expect(chain.call).to eq(author)
90
+ end
91
+
92
+ it "[success case] string type function, with reference & assign variable" do
93
+ chain = PullChain.new(@city)
94
+ chain << "/bookstore/@shelf = shelves[:mystery]"
95
+ chain << "/books[shelf.recommended_book_num]/title"
96
+ shelf = @city.bookstore.shelves[:mystery]
97
+ title = shelf.books[shelf.recommended_book_num].title
98
+ expect(chain.call).to eq(title)
99
+ end
100
+
101
+ it "[success case] string type function, with escaped /" do
102
+ chain = PullChain.new("AC") << "concat '\\/DC'"
103
+ expect(chain.call).to eq("AC".concat("/DC"))
104
+ end
105
+
106
+ it "[success case] mix type string, symbol, array" do
107
+ chain = PullChain.new(@city)
108
+ chain.add_all(:bookstore, "shelves[:programing]")
109
+ chain << "books" << [:[], [0]] << :title
110
+ title = @city.bookstore.shelves[:programing].books[0].title
111
+ expect(chain.call).to eq(title)
112
+ end
113
+
114
+ it "[success case] insert_all" do
115
+ chain = PullChain.new(@city, "/bookstore/shelves[:programing]/title")
116
+ chain.insert(2, "books[1]")
117
+ title = @city.bookstore.shelves[:programing].books[1].title
118
+ expect(chain.call).to eq(title)
119
+ end
120
+
121
+ it "[success case] inserts" do
122
+ chain = PullChain.new(@city, "/bookstore/title")
123
+ chain.insert_all(1, "shelves[:programing]", "books[1]")
124
+ title = @city.bookstore.shelves[:programing].books[1].title
125
+ expect(chain.call).to eq(title)
126
+ end
127
+
128
+ it "[success case] delete" do
129
+ chain = PullChain.new(@city, "/bookstore/shelves[:programing]/title")
130
+ chain.delete_at(2)
131
+ expect(chain.call).to eq(@city.bookstore.shelves[:programing])
132
+ end
133
+
134
+ it "[success case] clear" do
135
+ chain = PullChain.new(@city, "/bookstore/shelves[:programing]/title")
136
+ chain.clear
137
+ expect(chain.call).to eq(@city)
138
+ end
139
+
140
+ it "[success case] get a value of not exist key" do
141
+ chain = PullChain.new(@city)
142
+ chain << "/bookstore/shelves['not exist key']/books[1]/title"
143
+ expect(chain.call).to be_nil
144
+ end
145
+
146
+ it "[success case] get a nil at error(symbol)" do
147
+ chain = PullChain.new(@city) << :aaaa << :bbbb
148
+ chain.return_nil_at_error = true
149
+ expect(chain.call).to be_nil
150
+ end
151
+
152
+ it "[success case] get a nil at error(string)" do
153
+ chain = PullChain.new(@city) << "/bookstore/xyz/afasd"
154
+ chain.return_nil_at_error = true
155
+ expect(chain.call).to be_nil
156
+ end
157
+
158
+ it "[success case] get a nil at error(array)" do
159
+ chain = PullChain.new(@city) << :bookstore << :shelves << [:x, [:mystery]]
160
+ chain.return_nil_at_error = true
161
+ expect(chain.call).to be_nil
162
+ end
163
+
164
+ it "[success case] get a false" do
165
+ chain = PullChain.new(Object.new) << :nil? << :to_s << :upcase
166
+ expect(chain.call).to eq(false.to_s.upcase)
167
+ end
168
+
169
+ it "[success case] to_s" do
170
+ chain = PullChain.new(@city) << "bookstore/shelves[:programing]"
171
+ chain << :books << [:[], [1]] << :title
172
+ names = ["bookstore", "shelves[:programing]", :books, [:[], [1]], :title]
173
+ expect(chain.to_s).to eq("#{PullChain}#{names}")
174
+ end
175
+
176
+ it "[fail case] NameError" do
177
+ expect do
178
+ FunctionChain.pull(@city, "/bookstore/shelvesassss/")
179
+ end.to raise_error(NameError)
180
+ end
181
+
182
+ it "[fail case] NoMethodError" do
183
+ expect do
184
+ FunctionChain.pull(@city, :bookstore, :create_common_chain_element)
185
+ end.to raise_error(NoMethodError)
186
+ end
187
+
188
+ it "[fail case] ArgumentError:add not supported type" do
189
+ expect do
190
+ FunctionChain.pull(@city, :bookstore, 100)
191
+ end.to raise_error(ArgumentError)
192
+ end
193
+
194
+ it "[fail case] ArgumentError:array format wrong 1" do
195
+ expect do
196
+ FunctionChain.pull(@city, :bookstore, :shelves, [:[]])
197
+ end.to raise_error(ArgumentError)
198
+ end
199
+
200
+ it "[fail case] ArgumentError:array format wrong 2" do
201
+ expect do
202
+ FunctionChain.pull(@city, :bookstore, :shelves, [:[], 1])
203
+ end.to raise_error(ArgumentError)
204
+ end
205
+
206
+ it "[fail case] ArgumentError:wrong format variable define 1" do
207
+ expect do
208
+ chain = PullChain.new(@city)
209
+ chain << "/bookstore/@1shelf = shelves[:mystery]/books[0]/title"
210
+ chain.call
211
+ end.to raise_error(ArgumentError)
212
+ end
213
+
214
+ %w(! " ' # % & ( ) = ~ \\ ` @ [ ] * + < > ? 1 ; : . , ^).each do |e|
215
+ it "[fail case] ArgumentError:wrong format variable define #{e}" do
216
+ expect do
217
+ FunctionChain.pull(@city, "/@#{e}x = bookstore")
218
+ end.to raise_error(ArgumentError)
219
+ end
220
+ end
221
+
222
+ end
223
+
224
+ describe FunctionChain::RelayChain do
225
+
226
+ before(:context) do
227
+
228
+ class Decorator
229
+ def decorate1(value)
230
+ "#{value} is decorated"
231
+ end
232
+
233
+ def decorate2(value)
234
+ "#{value} is more decorated"
235
+ end
236
+ end
237
+
238
+ class EncloseDecorator
239
+ def decorate(value)
240
+ "'#{value}'"
241
+ end
242
+ end
243
+
244
+ class PrefixSuffixDecorator
245
+ def decorate(value, prefix, suffix)
246
+ "#{prefix}#{value}#{suffix}"
247
+ end
248
+ end
249
+
250
+ class MultivalueIO
251
+ def four_values
252
+ return "value1", [1, 2, 3, 4], [4, 3, 2, 1], "value4"
253
+ end
254
+
255
+ def union_four_values(value1, array1, array2, value4)
256
+ "#{value1} & #{array1} & #{array2} & #{value4}"
257
+ end
258
+ end
259
+
260
+ @decorator = Decorator.new
261
+ @enclose_decorator = EncloseDecorator.new
262
+ @prefix_suffix_decorator = PrefixSuffixDecorator.new
263
+ @multivalue_io = MultivalueIO.new
264
+ RelayChain = FunctionChain::RelayChain
265
+ end
266
+
267
+ it "[success case] same instance, use symbol" do
268
+ chain = RelayChain.new(@decorator) >> :decorate1 >> :decorate2
269
+ decorated_value = @decorator.decorate2(@decorator.decorate1("Evans"))
270
+ expect(chain.call("Evans")).to eq(decorated_value)
271
+ end
272
+
273
+ it "[success case] same instance, use string" do
274
+ chain = RelayChain.new(@decorator, "decorate1/decorate2")
275
+ decorated_value = @decorator.decorate2(@decorator.decorate1("Davis"))
276
+ expect(chain.call("Davis")).to eq(decorated_value)
277
+ end
278
+
279
+ it "[success case] same instance, insert_all" do
280
+ chain = RelayChain.new(@decorator) >> :decorate2
281
+ chain.insert(0, :decorate1)
282
+ decorated_value = @decorator.decorate2(@decorator.decorate1("Coltrane"))
283
+ expect(chain.call("Coltrane")).to eq(decorated_value)
284
+ end
285
+
286
+ it "[success case] same instance, delete" do
287
+ chain = RelayChain.new(@decorator) >> :decorate1 >> :decorate2
288
+ chain.delete_at(0)
289
+ expect(chain.call("Petrucciani")).to eq(@decorator.decorate2("Petrucciani"))
290
+ end
291
+
292
+ it "[success case] same instance, clear" do
293
+ chain = RelayChain.new(@decorator) >> :decorate1 >> :decorate2
294
+ chain.clear
295
+ expect(chain.call("Petrucciani")).to be_nil
296
+ end
297
+
298
+ it "[success case] same instance, multiple io" do
299
+ chain = RelayChain.new(@multivalue_io) >> :four_values >> :union_four_values
300
+ value = @multivalue_io.union_four_values(*@multivalue_io.four_values)
301
+ expect(chain.call).to eq(value)
302
+ end
303
+
304
+ it "[success case] differ instance" do
305
+ chain = RelayChain.new(@decorator, :decorate1)
306
+ chain.add_all(:decorate2, [@enclose_decorator, :decorate])
307
+ decorated_value = @decorator.decorate2(@decorator.decorate1("Peterson"))
308
+ decorated_value = @enclose_decorator.decorate(decorated_value)
309
+ expect(chain.call("Peterson")).to eq(decorated_value)
310
+ end
311
+
312
+ it "[success case] differ instance, designate of method name as string" do
313
+ chain = RelayChain.new(@decorator, :decorate1)
314
+ chain.add_all(:decorate2, [@enclose_decorator, "decorate"])
315
+ decorated_value = @decorator.decorate2(@decorator.decorate1("Peterson"))
316
+ decorated_value = @enclose_decorator.decorate(decorated_value)
317
+ expect(chain.call("Peterson")).to eq(decorated_value)
318
+ end
319
+
320
+ it "[success case] differ instance use string & add receiver" do
321
+ chain = RelayChain.new(@decorator)
322
+ chain >> "decorate1/decorate2/e_decorator.decorate"
323
+ chain.add_receiver("e_decorator", @enclose_decorator)
324
+ decorated_value = @decorator.decorate2(@decorator.decorate1("Brown"))
325
+ decorated_value = @enclose_decorator.decorate(decorated_value)
326
+ expect(chain.call("Brown")).to eq(decorated_value)
327
+ end
328
+
329
+ it "[success case] connect to methods that the different num of argument" do
330
+ connector = lambda { |c, value| c.call(value, "Bernard", "Purdie") }
331
+ chain = RelayChain.new >> [@enclose_decorator, :decorate]
332
+ chain >> connector >> [@prefix_suffix_decorator, :decorate]
333
+ decorated_value = @enclose_decorator.decorate("Pretty")
334
+ decorated_value = @prefix_suffix_decorator.decorate(decorated_value,
335
+ "Bernard", "Purdie")
336
+ expect(chain.call("Pretty")).to eq(decorated_value)
337
+ end
338
+
339
+ it "[success case] differ instance, use str & connector & receiver_table" do
340
+ chain = RelayChain.new(@decorator)
341
+ chain.add_receiver_table("e_decorator" => @enclose_decorator,
342
+ "ps_decorator" => @prefix_suffix_decorator)
343
+ connector = lambda { |c, value| c.call(value, "I Say ", ".") }
344
+ chain >> "decorate1/e_decorator.decorate"
345
+ chain >> connector >> "ps_decorator.decorate"
346
+
347
+ value = @enclose_decorator.decorate(@decorator.decorate1("Cake"))
348
+ value = @prefix_suffix_decorator.decorate(value, "I Say ", ".")
349
+ expect(chain.call("Cake")).to eq(value)
350
+ end
351
+
352
+ it "[success case] differ instance, use Method" do
353
+ chain = RelayChain.new
354
+ chain >> @decorator.method(:decorate1)
355
+ chain >> @enclose_decorator.method(:decorate)
356
+ v = @enclose_decorator.decorate(@decorator.decorate1("Skunk"))
357
+ expect(chain.call("Skunk")).to eq(v)
358
+ end
359
+
360
+ it "[success case] use Proc" do
361
+ process1 = lambda { |chain, arr| chain.call(arr.select(&:even?)) }
362
+ process2 = lambda { |_, arr| arr.map { |num| num * 10 } }
363
+ chain = RelayChain.new >> process1 >> process2
364
+ array = [1, 2, 3, 4, 5]
365
+ value = array.select(&:even?).map { |num| num * 10 }
366
+ expect(chain.call(array)).to eq(value)
367
+ end
368
+
369
+ it "[success case] stop of chain" do
370
+ chain = RelayChain.new(@decorator)
371
+ chain.add_all(:decorate1, :decorate2, [@enclose_decorator, :decorate])
372
+ stopper = lambda { |_, value| value }
373
+ chain.insert(2, stopper)
374
+ decorated_value = @decorator.decorate2(@decorator.decorate1("Montgomery"))
375
+ expect(chain.call("Montgomery")).to eq(decorated_value)
376
+ end
377
+
378
+ it "[success case] to_s" do
379
+ chain = RelayChain.new
380
+ stopper = lambda { |_, value| value }
381
+ chain >> @decorator.method(:decorate1) >> stopper
382
+ names = [@decorator.method(:decorate1), stopper]
383
+ expect(chain.to_s).to eq("#{RelayChain}#{names}")
384
+ end
385
+
386
+ it "[fail case] ArgumentError:add not supported type" do
387
+ expect do
388
+ RelayChain.new(@decorator) >> :decorate1 >> 100
389
+ end.to raise_error(ArgumentError)
390
+ end
391
+
392
+ it "[fail case] ArgumentError: wrong number of array's element" do
393
+ expect do
394
+ RelayChain.new(@decorator) >> [@enclose_decorator]
395
+ end.to raise_error(ArgumentError)
396
+ end
397
+
398
+ it "[fail case] ArgumentError: wrong type of array's second element" do
399
+ expect do
400
+ RelayChain.new(@decorator) >> [@enclose_decorator, 10]
401
+ end.to raise_error(ArgumentError)
402
+ end
403
+
404
+ end
@@ -0,0 +1,13 @@
1
+ require "simplecov"
2
+ require "coveralls"
3
+
4
+ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
5
+ SimpleCov::Formatter::HTMLFormatter,
6
+ Coveralls::SimpleCov::Formatter
7
+ ]
8
+ SimpleCov.start do
9
+ add_filter ".bundle/"
10
+ end
11
+
12
+ $LOAD_PATH.unshift File.expand_path("../../lib", __FILE__)
13
+ require "function_chain"
data/tasks/flay.rake ADDED
@@ -0,0 +1,11 @@
1
+ require "rake/tasklib"
2
+ require "flay"
3
+ require "flay_task"
4
+
5
+ FlayTask.new do |t|
6
+ t.dirs = FileList["lib/**/*.rb"].map do |each|
7
+ each[%r{[^/]+}]
8
+ end.uniq
9
+ t.threshold = 0
10
+ t.verbose = true
11
+ end
data/tasks/flog.rake ADDED
@@ -0,0 +1,18 @@
1
+ require "flog"
2
+
3
+ desc "Analyze for code complexity"
4
+ task :flog do
5
+ flog = Flog.new(continue: true)
6
+ flog.flog(*FileList["lib/**/*.rb"])
7
+ threshold = 28
8
+
9
+ bad_methods = flog.totals.select do |name, score|
10
+ !(/##{flog.no_method}$/ =~ name) && score > threshold
11
+ end
12
+ bad_methods.sort { |a, b| a[1] <=> b[1] }.reverse.each do |name, score|
13
+ printf "%8.1f: %s\n", score, name
14
+ end
15
+ unless bad_methods.empty?
16
+ $stderr.puts "#{bad_methods.size} methods have a complexity > #{threshold}"
17
+ end
18
+ end
data/tasks/rspec.rake ADDED
@@ -0,0 +1,3 @@
1
+ require "rspec/core/rake_task"
2
+
3
+ RSpec::Core::RakeTask.new
metadata ADDED
@@ -0,0 +1,68 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: function_chain
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Kenji Suzuki
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-10-14 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: 'FunctionChain objectifies of the method chain.chain objects can call
14
+ later or add chain or insert chain or delete chain.supported chain type is following:
15
+ foo.bar.baz, baz(bar(foo(value))).'
16
+ email:
17
+ - pujoheadsoft@gmail.com
18
+ executables: []
19
+ extensions: []
20
+ extra_rdoc_files: []
21
+ files:
22
+ - .coveralls.yml
23
+ - .gitignore
24
+ - .rspec
25
+ - .rubocop.yml
26
+ - .travis.yml
27
+ - Gemfile
28
+ - LICENSE.txt
29
+ - README.md
30
+ - Rakefile
31
+ - function_chain.gemspec
32
+ - lib/function_chain.rb
33
+ - lib/function_chain/base_chain.rb
34
+ - lib/function_chain/pull_chain.rb
35
+ - lib/function_chain/relay_chain.rb
36
+ - lib/function_chain/version.rb
37
+ - spec/function_chain_spec.rb
38
+ - spec/spec_helper.rb
39
+ - tasks/flay.rake
40
+ - tasks/flog.rake
41
+ - tasks/rspec.rake
42
+ homepage: https://github.com/pujoheadsoft/function_chain
43
+ licenses:
44
+ - MIT
45
+ metadata: {}
46
+ post_install_message:
47
+ rdoc_options: []
48
+ require_paths:
49
+ - lib
50
+ required_ruby_version: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: 1.9.3
55
+ required_rubygems_version: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - '>='
58
+ - !ruby/object:Gem::Version
59
+ version: 1.3.5
60
+ requirements: []
61
+ rubyforge_project:
62
+ rubygems_version: 2.4.1
63
+ signing_key:
64
+ specification_version: 4
65
+ summary: FunctionChain objectifies of the method chain.
66
+ test_files:
67
+ - spec/function_chain_spec.rb
68
+ - spec/spec_helper.rb