callable_tree 0.3.5 → 0.3.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +6 -0
  3. data/.ruby-version +1 -1
  4. data/CHANGELOG.md +17 -0
  5. data/Gemfile.lock +2 -2
  6. data/README.md +366 -108
  7. data/callable_tree.gemspec +1 -0
  8. data/examples/builder/hooks.rb +67 -0
  9. data/examples/builder/internal-seekable.rb +69 -73
  10. data/examples/builder/logging.rb +129 -0
  11. data/examples/{external-verbosify.rb → class/external-verbosify.rb} +1 -1
  12. data/examples/class/hooks.rb +70 -0
  13. data/examples/{identity.rb → class/identity.rb} +1 -1
  14. data/examples/{internal-broadcastable.rb → class/internal-broadcastable.rb} +0 -0
  15. data/examples/{internal-composable.rb → class/internal-composable.rb} +0 -0
  16. data/examples/{internal-seekable.rb → class/internal-seekable.rb} +1 -1
  17. data/examples/{logging.rb → class/logging.rb} +45 -43
  18. data/lib/callable_tree/node/builder.rb +20 -4
  19. data/lib/callable_tree/node/external/builder.rb +1 -1
  20. data/lib/callable_tree/node/external/verbose.rb +1 -1
  21. data/lib/callable_tree/node/external.rb +15 -0
  22. data/lib/callable_tree/node/hooks/caller.rb +110 -0
  23. data/lib/callable_tree/node/hooks/matcher.rb +101 -0
  24. data/lib/callable_tree/node/hooks/terminator.rb +99 -0
  25. data/lib/callable_tree/node/internal.rb +27 -12
  26. data/lib/callable_tree/node/root.rb +3 -1
  27. data/lib/callable_tree/node.rb +8 -0
  28. data/lib/callable_tree/version.rb +1 -1
  29. data/lib/callable_tree.rb +3 -1
  30. metadata +17 -12
  31. data/examples/builder/hooks-call.rb +0 -38
  32. data/examples/hooks-call.rb +0 -39
  33. data/lib/callable_tree/node/hooks/call.rb +0 -81
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 83716fbdef2881db33e8f046f056a17d8a8866423951493902088bf1af53218f
4
- data.tar.gz: 8906217b71482e1717798329d172640a50f7cc73613a2187beba0702bf8b8d74
3
+ metadata.gz: 227de74d1378baca4b51a6b1e808ee59d984f20a53fc2ae77fb8b7902e6e4558
4
+ data.tar.gz: 2a138d14128114298e95642885f72da427b7ce69f1753ce855598c91e35df9fb
5
5
  SHA512:
6
- metadata.gz: 5e5ece858eb3347c41ea5f573e37c972d1a127d9fa234cd2512b18ef9e882b33d0da900b46c8f8e539fcee36fccb6643d21bb0945169019e7734232907c412c1
7
- data.tar.gz: ce58af4b926c9201f4133f02da848dcfff7962f9fa08588c1d4b4b61765b9c5ffaf03f2cfb4367da7d14a80bc1dcd55ea4b53de39d4075be25ef6e2abaf9ae7e
6
+ metadata.gz: 8ceb4df3df81b33ea9b8298c48b1068b9707e7b26550e1b8a35bc72501d495692c8969418ccb8a1a3e09f1661117f3bdd9aa9c0fd83a8eb87970305c961deb0b
7
+ data.tar.gz: a90186fd44e964090a656957a7ab29a423b2287164550093332f7f149f263d5d841fd8ba213d8e56e9e12fdc576f89fe5043966f5bfc74301891e6453520cea3
data/.rubocop.yml ADDED
@@ -0,0 +1,6 @@
1
+ AllCops:
2
+ NewCops: enable
3
+ Style/HashSyntax:
4
+ EnforcedShorthandSyntax: never
5
+ Naming/BlockForwarding:
6
+ EnforcedStyle: explicit
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 3.1.1
1
+ 3.1.2
data/CHANGELOG.md CHANGED
@@ -1,5 +1,22 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.3.8] - 2022-05-05
4
+
5
+ - (Experimental) Add `CallableTree::Node::Internal::Builder#identifier`.
6
+ - (Experimental) Add `CallableTree::Node::External::Builder#identifier`.
7
+ - (Experimental) Add `CallableTree::Node::Hooks::Terminator`.
8
+
9
+ ## [0.3.7] - 2022-04-09
10
+
11
+ - Add `CallableTree::Node#internal?`
12
+ - Add `CallableTree::Node#external?`
13
+ - (Experimental) Change the callables (matcher, caller, terminator) specified in the builder style to receive the current node instance as the `_node_` keyword argument.
14
+
15
+ ## [0.3.6] - 2022-03-29
16
+
17
+ - (Experimental) Add `CallableTree::Node::Hooks::Matcher`.
18
+ Using this together with `CallableTree::Node::Hooks::Caller` helps to output logs. See `examples/builder/logging.rb` for details.
19
+
3
20
  ## [0.3.5] - 2022-03-20
4
21
 
5
22
  - Add `CallableTree::Node::Internal#seekable?` as an alias for `CallableTree::Node::Internal#seek?`.
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- callable_tree (0.3.5)
4
+ callable_tree (0.3.8)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -17,7 +17,7 @@ GEM
17
17
  rspec-expectations (3.11.0)
18
18
  diff-lcs (>= 1.2.0, < 2.0)
19
19
  rspec-support (~> 3.11.0)
20
- rspec-mocks (3.11.0)
20
+ rspec-mocks (3.11.1)
21
21
  diff-lcs (>= 1.2.0, < 2.0)
22
22
  rspec-support (~> 3.11.0)
23
23
  rspec-support (3.11.0)
data/README.md CHANGED
@@ -21,10 +21,10 @@ Or install it yourself as:
21
21
 
22
22
  ## Usage
23
23
 
24
- Builds a tree by linking instances of the nodes. The `call` method of the node where the `match?` method returns a truthy value is called in a chain from the root node to the leaf node.
24
+ Builds a tree by linking `CallableTree` node instances. The `call` methods of the nodes where the `match?` method returns a truthy value are called in a chain from the root node to the leaf node.
25
25
 
26
26
  - `CallableTree::Node::Internal`
27
- - This `module` is used to define a node that can have child nodes. An instance of this node has several strategies. The strategy can be changed by calling the method of the instance.
27
+ - This `module` is used to define a node that can have child nodes. An instance of this node has several strategies (`seekable`, `broadcastable`, `composable`). The strategy can be changed by calling the method of the instance.
28
28
  - `CallableTree::Node::External`
29
29
  - This `module` is used to define a leaf node that cannot have child nodes.
30
30
  - `CallableTree::Node::Root`
@@ -32,11 +32,15 @@ Builds a tree by linking instances of the nodes. The `call` method of the node w
32
32
 
33
33
  ### Basic
34
34
 
35
- #### `CallableTree::Node::Internal#seekable` (default)
35
+ There are two ways to define the nodes: class style and builder style (experimental).
36
+
37
+ #### `CallableTree::Node::Internal#seekable` (default strategy)
36
38
 
37
39
  This strategy does not call the next sibling node if the `call` method of the current node returns a value other than `nil`. This behavior is changeable by overriding the `terminate?` method.
38
40
 
39
- `examples/internal-seekable.rb`:
41
+ ##### Class style
42
+
43
+ `examples/class/internal-seekable.rb`:
40
44
  ```ruby
41
45
  module Node
42
46
  module JSON
@@ -148,9 +152,115 @@ Dir.glob("#{__dir__}/docs/*") do |file|
148
152
  end
149
153
  ```
150
154
 
151
- Run `examples/internal-seekable.rb`:
155
+ Run `examples/class/internal-seekable.rb`:
156
+ ```sh
157
+ % ruby examples/class/internal-seekable.rb
158
+ {"Dog"=>"🐶", "Cat"=>"🐱"}
159
+ ---
160
+ {"Dog"=>"🐶", "Cat"=>"🐱"}
161
+ ---
162
+ {"Red Apple"=>"🍎", "Green Apple"=>"🍏"}
163
+ ---
164
+ {"Red Apple"=>"🍎", "Green Apple"=>"🍏"}
165
+ ---
166
+ ```
167
+
168
+ ##### Builder style (experimental)
169
+
170
+ `examples/builder/internal-seekable.rb`:
171
+ ```ruby
172
+ JSONParser =
173
+ CallableTree::Node::Internal::Builder
174
+ .new
175
+ .matcher do |input, **_options|
176
+ File.extname(input) == '.json'
177
+ end
178
+ .caller do |input, **options, &block|
179
+ File.open(input) do |file|
180
+ json = ::JSON.load(file)
181
+ # The following block call is equivalent to calling `super` in the class style.
182
+ block.call(json, **options)
183
+ end
184
+ end
185
+ .terminator do
186
+ true
187
+ end
188
+ .build
189
+
190
+ XMLParser =
191
+ CallableTree::Node::Internal::Builder
192
+ .new
193
+ .matcher do |input, **_options|
194
+ File.extname(input) == '.xml'
195
+ end
196
+ .caller do |input, **options, &block|
197
+ File.open(input) do |file|
198
+ # The following block call is equivalent to calling `super` in the class style.
199
+ block.call(REXML::Document.new(file), **options)
200
+ end
201
+ end
202
+ .terminator do
203
+ true
204
+ end
205
+ .build
206
+
207
+ def build_json_scraper(type)
208
+ CallableTree::Node::External::Builder
209
+ .new
210
+ .matcher do |input, **_options|
211
+ !!input[type.to_s]
212
+ end
213
+ .caller do |input, **_options|
214
+ input[type.to_s]
215
+ .map { |element| [element['name'], element['emoji']] }
216
+ .to_h
217
+ end
218
+ .build
219
+ end
220
+
221
+ AnimalsJSONScraper = build_json_scraper(:animals)
222
+ FruitsJSONScraper = build_json_scraper(:fruits)
223
+
224
+ def build_xml_scraper(type)
225
+ CallableTree::Node::External::Builder
226
+ .new
227
+ .matcher do |input, **_options|
228
+ !input.get_elements("//#{type}").empty?
229
+ end
230
+ .caller do |input, **_options|
231
+ input
232
+ .get_elements("//#{type}")
233
+ .first
234
+ .map { |element| [element['name'], element['emoji']] }
235
+ .to_h
236
+ end
237
+ .build
238
+ end
239
+
240
+ AnimalsXMLScraper = build_xml_scraper(:animals)
241
+ FruitsXMLScraper = build_xml_scraper(:fruits)
242
+
243
+ tree = CallableTree::Node::Root.new.seekable.append(
244
+ JSONParser.new.seekable.append(
245
+ AnimalsJSONScraper.new,
246
+ FruitsJSONScraper.new
247
+ ),
248
+ XMLParser.new.seekable.append(
249
+ AnimalsXMLScraper.new,
250
+ FruitsXMLScraper.new
251
+ )
252
+ )
253
+
254
+ Dir.glob("#{__dir__}/../docs/*") do |file|
255
+ options = { foo: :bar }
256
+ pp tree.call(file, **options)
257
+ puts '---'
258
+ end
259
+ ```
260
+
261
+ Run `examples/builder/internal-seekable.rb`:
152
262
  ```sh
153
- % ruby examples/internal-seekable.rb
263
+ % ruby examples/builder/internal-seekable.rb
154
264
  {"Dog"=>"🐶", "Cat"=>"🐱"}
155
265
  ---
156
266
  {"Dog"=>"🐶", "Cat"=>"🐱"}
@@ -165,7 +275,9 @@ Run `examples/internal-seekable.rb`:
165
275
 
166
276
  This strategy calls all child nodes of the internal node and ignores their `terminate?` methods, and then outputs their results as array.
167
277
 
168
- `examples/internal-broadcastable.rb`:
278
+ ##### Class style
279
+
280
+ `examples/class/internal-broadcastable.rb`:
169
281
  ```ruby
170
282
  module Node
171
283
  class LessThan
@@ -199,9 +311,99 @@ end
199
311
 
200
312
  ```
201
313
 
202
- Run `examples/internal-broadcastable.rb`:
314
+ Run `examples/class/internal-broadcastable.rb`:
203
315
  ```sh
204
- % ruby examples/internal-broadcastable.rb
316
+ % ruby examples/class/internal-broadcastable.rb
317
+ 0 -> [[0, 1], [0, -1]]
318
+ 1 -> [[2, 2], [3, 0]]
319
+ 2 -> [[4, 3], [6, 1]]
320
+ 3 -> [[6, 4], [9, 2]]
321
+ 4 -> [[8, 5], [12, 3]]
322
+ 5 -> [nil, [15, 4]]
323
+ 6 -> [nil, [18, 5]]
324
+ 7 -> [nil, [21, 6]]
325
+ 8 -> [nil, [24, 7]]
326
+ 9 -> [nil, [27, 8]]
327
+ 10 -> [nil, nil]
328
+ ```
329
+
330
+ ##### Builder style (experimental)
331
+
332
+ `examples/builder/internal-broadcastable.rb`:
333
+ ```ruby
334
+ less_than = proc do |num|
335
+ # The following block call is equivalent to calling `super` in the class style.
336
+ proc { |input, &block| block.call(input) && input < num }
337
+ end
338
+
339
+ LessThan5 =
340
+ CallableTree::Node::Internal::Builder
341
+ .new
342
+ .matcher(&less_than.call(5))
343
+ .build
344
+
345
+ LessThan10 =
346
+ CallableTree::Node::Internal::Builder
347
+ .new
348
+ .matcher(&less_than.call(10))
349
+ .build
350
+
351
+ add = proc do |num|
352
+ proc { |input| input + num }
353
+ end
354
+
355
+ Add1 =
356
+ CallableTree::Node::External::Builder
357
+ .new
358
+ .caller(&add.call(1))
359
+ .build
360
+
361
+ subtract = proc do |num|
362
+ proc { |input| input - num }
363
+ end
364
+
365
+ Subtract1 =
366
+ CallableTree::Node::External::Builder
367
+ .new
368
+ .caller(&subtract.call(1))
369
+ .build
370
+
371
+ multiply = proc do |num|
372
+ proc { |input| input * num }
373
+ end
374
+
375
+ Multiply2 =
376
+ CallableTree::Node::External::Builder
377
+ .new
378
+ .caller(&multiply.call(2))
379
+ .build
380
+
381
+ Multiply3 =
382
+ CallableTree::Node::External::Builder
383
+ .new
384
+ .caller(&multiply.call(3))
385
+ .build
386
+
387
+ tree = CallableTree::Node::Root.new.broadcastable.append(
388
+ LessThan5.new.broadcastable.append(
389
+ Multiply2.new,
390
+ Add1.new
391
+ ),
392
+ LessThan10.new.broadcastable.append(
393
+ Multiply3.new,
394
+ Subtract1.new
395
+ )
396
+ )
397
+
398
+ (0..10).each do |input|
399
+ output = tree.call(input)
400
+ puts "#{input} -> #{output}"
401
+ end
402
+ ```
403
+
404
+ Run `examples/builder/internal-broadcastable.rb`:
405
+ ```sh
406
+ % ruby examples/builder/internal-broadcastable.rb
205
407
  0 -> [[0, 1], [0, -1]]
206
408
  1 -> [[2, 2], [3, 0]]
207
409
  2 -> [[4, 3], [6, 1]]
@@ -219,7 +421,9 @@ Run `examples/internal-broadcastable.rb`:
219
421
 
220
422
  This strategy calls all child nodes of the internal node in order to input the output of the previous node to the next node and ignores their `terminate?` methods, and then outputs a single result.
221
423
 
222
- `examples/internal-composable.rb`:
424
+ ##### Class style
425
+
426
+ `examples/class/internal-composable.rb`:
223
427
  ```ruby
224
428
  module Node
225
429
  class LessThan
@@ -253,9 +457,99 @@ end
253
457
 
254
458
  ```
255
459
 
256
- Run `examples/internal-composable.rb`:
460
+ Run `examples/class/internal-composable.rb`:
461
+ ```sh
462
+ % ruby examples/class/internal-composable.rb
463
+ 0 -> 2
464
+ 1 -> 8
465
+ 2 -> 14
466
+ 3 -> 20
467
+ 4 -> 26
468
+ 5 -> 14
469
+ 6 -> 17
470
+ 7 -> 20
471
+ 8 -> 23
472
+ 9 -> 26
473
+ 10 -> 10
474
+ ```
475
+
476
+ ##### Builder style (experimental)
477
+
478
+ `examples/builder/internal-composable.rb`:
479
+ ```ruby
480
+ less_than = proc do |num|
481
+ # The following block call is equivalent to calling `super` in the class style.
482
+ proc { |input, &block| block.call(input) && input < num }
483
+ end
484
+
485
+ LessThan5 =
486
+ CallableTree::Node::Internal::Builder
487
+ .new
488
+ .matcher(&less_than.call(5))
489
+ .build
490
+
491
+ LessThan10 =
492
+ CallableTree::Node::Internal::Builder
493
+ .new
494
+ .matcher(&less_than.call(10))
495
+ .build
496
+
497
+ add = proc do |num|
498
+ proc { |input| input + num }
499
+ end
500
+
501
+ Add1 =
502
+ CallableTree::Node::External::Builder
503
+ .new
504
+ .caller(&add.call(1))
505
+ .build
506
+
507
+ subtract = proc do |num|
508
+ proc { |input| input - num }
509
+ end
510
+
511
+ Subtract1 =
512
+ CallableTree::Node::External::Builder
513
+ .new
514
+ .caller(&subtract.call(1))
515
+ .build
516
+
517
+ multiply = proc do |num|
518
+ proc { |input| input * num }
519
+ end
520
+
521
+ Multiply2 =
522
+ CallableTree::Node::External::Builder
523
+ .new
524
+ .caller(&multiply.call(2))
525
+ .build
526
+
527
+ Multiply3 =
528
+ CallableTree::Node::External::Builder
529
+ .new
530
+ .caller(&multiply.call(3))
531
+ .build
532
+
533
+ tree = CallableTree::Node::Root.new.composable.append(
534
+ LessThan5.new.composable.append(
535
+ Multiply2.new,
536
+ Add1.new
537
+ ),
538
+ LessThan10.new.composable.append(
539
+ Multiply3.new,
540
+ Subtract1.new
541
+ )
542
+ )
543
+
544
+ (0..10).each do |input|
545
+ output = tree.call(input)
546
+ puts "#{input} -> #{output}"
547
+ end
548
+ ```
549
+
550
+ Run `examples/builder/internal-composable.rb`:
257
551
  ```sh
258
- % ruby examples/internal-composable.rb
552
+ % ruby examples/builder/internal-composable.rb
259
553
  0 -> 2
260
554
  1 -> 8
261
555
  2 -> 14
@@ -275,7 +569,7 @@ Run `examples/internal-composable.rb`:
275
569
 
276
570
  If you want verbose output results, call this method.
277
571
 
278
- `examples/external-verbosify.rb`:
572
+ `examples/class/external-verbosify.rb`:
279
573
  ```ruby
280
574
  ...
281
575
 
@@ -293,9 +587,9 @@ tree = CallableTree::Node::Root.new.append(
293
587
  ...
294
588
  ```
295
589
 
296
- Run `examples/external-verbosify.rb`:
590
+ Run `examples/class/external-verbosify.rb`:
297
591
  ```sh
298
- % ruby examples/external-verbosify.rb
592
+ % ruby examples/class/external-verbosify.rb
299
593
  #<struct CallableTree::Node::External::Output
300
594
  value={"Dog"=>"🐶", "Cat"=>"🐱"},
301
595
  options={:foo=>:bar},
@@ -325,7 +619,7 @@ You can work around it by overriding the `identity` method of the node.
325
619
 
326
620
  If you want to customize the node identity, override this method.
327
621
 
328
- `examples/identity.rb`:
622
+ `examples/class/identity.rb`:
329
623
  ```ruby
330
624
  module Node
331
625
  class Identity
@@ -381,9 +675,9 @@ end
381
675
  ...
382
676
  ```
383
677
 
384
- Run `examples/identity.rb`:
678
+ Run `examples/class/identity.rb`:
385
679
  ```sh
386
- % ruby examples/identity.rb
680
+ % ruby examples/class/identity.rb
387
681
  #<struct CallableTree::Node::External::Output
388
682
  value={"Dog"=>"🐶", "Cat"=>"🐱"},
389
683
  options={:foo=>:bar},
@@ -430,53 +724,23 @@ Run `examples/identity.rb`:
430
724
 
431
725
  This is an example of logging.
432
726
 
433
- `examples/logging.rb`:
727
+ `examples/class/logging.rb`:
434
728
  ```ruby
435
729
  module Node
436
- module Logging
437
- INDENT_SIZE = 2
438
- BLANK = ' '
439
-
440
- module Match
441
- LIST_STYLE = '*'
442
-
443
- def match?(_input, **_options)
444
- super.tap do |matched|
445
- prefix = LIST_STYLE.rjust(depth * INDENT_SIZE - INDENT_SIZE + LIST_STYLE.length, BLANK)
446
- puts "#{prefix} #{identity}: [matched: #{matched}]"
447
- end
448
- end
449
- end
450
-
451
- module Call
452
- INPUT_LABEL = 'Input :'
453
- OUTPUT_LABEL = 'Output:'
454
-
455
- def call(input, **_options)
456
- super.tap do |output|
457
- input_prefix = INPUT_LABEL.rjust(depth * INDENT_SIZE + INPUT_LABEL.length, BLANK)
458
- puts "#{input_prefix} #{input}"
459
- output_prefix = OUTPUT_LABEL.rjust(depth * INDENT_SIZE + OUTPUT_LABEL.length, BLANK)
460
- puts "#{output_prefix} #{output}"
461
- end
462
- end
463
- end
464
- end
465
-
466
730
  ...
467
731
 
468
732
  module JSON
469
733
  class Parser
470
734
  include CallableTree::Node::Internal
471
- prepend Logging::Match
735
+ prepend CallableTree::Node::Hooks::Matcher
472
736
 
473
737
  ...
474
738
  end
475
739
 
476
740
  class Scraper
477
741
  include CallableTree::Node::External
478
- prepend Logging::Match
479
- prepend Logging::Call
742
+ prepend CallableTree::Node::Hooks::Matcher
743
+ prepend CallableTree::Node::Hooks::Caller
480
744
 
481
745
  ...
482
746
  end
@@ -485,27 +749,72 @@ module Node
485
749
  module XML
486
750
  class Parser
487
751
  include CallableTree::Node::Internal
488
- prepend Logging::Match
752
+ prepend CallableTree::Node::Hooks::Matcher
489
753
 
490
754
  ...
491
755
  end
492
756
 
493
757
  class Scraper
494
758
  include CallableTree::Node::External
495
- prepend Logging::Match
496
- prepend Logging::Call
759
+ prepend CallableTree::Node::Hooks::Matcher
760
+ prepend CallableTree::Node::Hooks::Caller
497
761
 
498
762
  ...
499
763
  end
500
764
  end
501
765
  end
502
766
 
767
+ module Logging
768
+ INDENT_SIZE = 2
769
+ BLANK = ' '
770
+ LIST_STYLE = '*'
771
+ INPUT_LABEL = 'Input :'
772
+ OUTPUT_LABEL = 'Output:'
773
+
774
+ def self.loggable(node)
775
+ node.after_matcher! do |matched, _node_:, **|
776
+ prefix = LIST_STYLE.rjust(_node_.depth * INDENT_SIZE - INDENT_SIZE + LIST_STYLE.length, BLANK)
777
+ puts "#{prefix} #{_node_.identity}: [matched: #{matched}]"
778
+ matched
779
+ end
780
+
781
+ if node.external?
782
+ node
783
+ .before_caller! do |input, *, _node_:, **|
784
+ input_prefix = INPUT_LABEL.rjust(_node_.depth * INDENT_SIZE + INPUT_LABEL.length, BLANK)
785
+ puts "#{input_prefix} #{input}"
786
+ input
787
+ end
788
+ .after_caller! do |output, _node_:, **|
789
+ output_prefix = OUTPUT_LABEL.rjust(_node_.depth * INDENT_SIZE + OUTPUT_LABEL.length, BLANK)
790
+ puts "#{output_prefix} #{output}"
791
+ output
792
+ end
793
+ end
794
+ end
795
+ end
796
+
797
+ loggable = Logging.method(:loggable)
798
+
799
+ tree = CallableTree::Node::Root.new.append(
800
+ Node::JSON::Parser.new.tap(&loggable).append(
801
+ Node::JSON::Scraper.new(type: :animals).tap(&loggable).verbosify,
802
+ Node::JSON::Scraper.new(type: :fruits).tap(&loggable).verbosify
803
+ ),
804
+ Node::XML::Parser.new.tap(&loggable).append(
805
+ Node::XML::Scraper.new(type: :animals).tap(&loggable).verbosify,
806
+ Node::XML::Scraper.new(type: :fruits).tap(&loggable).verbosify
807
+ )
808
+ )
809
+
503
810
  ...
504
811
  ```
505
812
 
506
- Run `examples/logging.rb`:
813
+ Also, see `examples/class/hooks.rb` for detail about `CallableTree::Node::Hooks::*`.
814
+
815
+ Run `examples/class/logging.rb`:
507
816
  ```sh
508
- % ruby examples/logging.rb
817
+ % ruby examples/class/logging.rb
509
818
  * Node::JSON::Parser: [matched: true]
510
819
  * Node::JSON::Scraper(animals): [matched: true]
511
820
  Input : {"animals"=>[{"name"=>"Dog", "emoji"=>"🐶"}, {"name"=>"Cat", "emoji"=>"🐱"}]}
@@ -568,57 +877,6 @@ Run `examples/logging.rb`:
568
877
  ---
569
878
  ```
570
879
 
571
- #### `CallableTree::Node::Hooks::Call` (experimental)
572
-
573
- `examples/hooks-call.rb`:
574
- ```ruby
575
- module Node
576
- class HooksSample
577
- include CallableTree::Node::Internal
578
- prepend CallableTree::Node::Hooks::Call
579
- end
580
- end
581
-
582
- Node::HooksSample.new
583
- .before_call do |input, **_options|
584
- puts "before_call input: #{input}";
585
- input + 1
586
- end
587
- .append(
588
- # anonymous external node
589
- lambda do |input, **_options|
590
- puts "external input: #{input}"
591
- input * 2
592
- end
593
- )
594
- .around_call do |input, **_options, &block|
595
- puts "around_call input: #{input}"
596
- output = block.call
597
- puts "around_call output: #{output}"
598
- output * input
599
- end
600
- .after_call do |output, **_options|
601
- puts "after_call output: #{output}"
602
- output * 2
603
- end
604
- .tap do |tree|
605
- options = { foo: :bar }
606
- output = tree.call(1, **options)
607
- puts "result: #{output}"
608
- end
609
- ```
610
-
611
- Run `examples/hooks-call.rb`:
612
- ```sh
613
- % ruby examples/hooks-call.rb
614
- before_call input: 1
615
- external input: 2
616
- around_call input: 2
617
- around_call output: 4
618
- after_call output: 8
619
- result: 16
620
- ```
621
-
622
880
  ## Contributing
623
881
 
624
882
  Bug reports and pull requests are welcome on GitHub at https://github.com/jsmmr/ruby_callable_tree.
@@ -32,4 +32,5 @@ Gem::Specification.new do |spec|
32
32
 
33
33
  # For more information and examples about making a new gem, checkout our
34
34
  # guide at: https://bundler.io/guides/creating_gem.html
35
+ spec.metadata['rubygems_mfa_required'] = 'true'
35
36
  end