callable_tree 0.3.8 → 0.3.10

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.
data/README.md CHANGED
@@ -24,7 +24,7 @@ Or install it yourself as:
24
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 (`seekable`, `broadcastable`, `composable`). 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. This node has several strategies (`seekable`, `broadcastable`, `composable`).
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,7 +32,7 @@ Builds a tree by linking `CallableTree` node instances. The `call` methods of th
32
32
 
33
33
  ### Basic
34
34
 
35
- There are two ways to define the nodes: class style and builder style (experimental).
35
+ There are two ways to define the nodes: class style and builder style.
36
36
 
37
37
  #### `CallableTree::Node::Internal#seekable` (default strategy)
38
38
 
@@ -81,8 +81,7 @@ module Node
81
81
 
82
82
  def call(input, **_options)
83
83
  input[@type.to_s]
84
- .map { |element| [element['name'], element['emoji']] }
85
- .to_h
84
+ .to_h { |element| [element['name'], element['emoji']] }
86
85
  end
87
86
  end
88
87
  end
@@ -126,8 +125,7 @@ module Node
126
125
  input
127
126
  .get_elements("//#{@type}")
128
127
  .first
129
- .map { |element| [element['name'], element['emoji']] }
130
- .to_h
128
+ .to_h { |element| [element['name'], element['emoji']] }
131
129
  end
132
130
  end
133
131
  end
@@ -165,7 +163,7 @@ Run `examples/class/internal-seekable.rb`:
165
163
  ---
166
164
  ```
167
165
 
168
- ##### Builder style (experimental)
166
+ ##### Builder style
169
167
 
170
168
  `examples/builder/internal-seekable.rb`:
171
169
  ```ruby
@@ -175,16 +173,14 @@ JSONParser =
175
173
  .matcher do |input, **_options|
176
174
  File.extname(input) == '.json'
177
175
  end
178
- .caller do |input, **options, &block|
176
+ .caller do |input, **options, &original|
179
177
  File.open(input) do |file|
180
178
  json = ::JSON.load(file)
181
179
  # The following block call is equivalent to calling `super` in the class style.
182
- block.call(json, **options)
180
+ original.call(json, **options)
183
181
  end
184
182
  end
185
- .terminator do
186
- true
187
- end
183
+ .terminator { true }
188
184
  .build
189
185
 
190
186
  XMLParser =
@@ -193,15 +189,13 @@ XMLParser =
193
189
  .matcher do |input, **_options|
194
190
  File.extname(input) == '.xml'
195
191
  end
196
- .caller do |input, **options, &block|
192
+ .caller do |input, **options, &original|
197
193
  File.open(input) do |file|
198
194
  # The following block call is equivalent to calling `super` in the class style.
199
- block.call(REXML::Document.new(file), **options)
195
+ original.call(REXML::Document.new(file), **options)
200
196
  end
201
197
  end
202
- .terminator do
203
- true
204
- end
198
+ .terminator { true }
205
199
  .build
206
200
 
207
201
  def build_json_scraper(type)
@@ -212,8 +206,7 @@ def build_json_scraper(type)
212
206
  end
213
207
  .caller do |input, **_options|
214
208
  input[type.to_s]
215
- .map { |element| [element['name'], element['emoji']] }
216
- .to_h
209
+ .to_h { |element| [element['name'], element['emoji']] }
217
210
  end
218
211
  .build
219
212
  end
@@ -231,8 +224,7 @@ def build_xml_scraper(type)
231
224
  input
232
225
  .get_elements("//#{type}")
233
226
  .first
234
- .map { |element| [element['name'], element['emoji']] }
235
- .to_h
227
+ .to_h { |element| [element['name'], element['emoji']] }
236
228
  end
237
229
  .build
238
230
  end
@@ -273,7 +265,7 @@ Run `examples/builder/internal-seekable.rb`:
273
265
 
274
266
  #### `CallableTree::Node::Internal#broadcastable`
275
267
 
276
- This strategy calls all child nodes of the internal node and ignores their `terminate?` methods, and then outputs their results as array.
268
+ This strategy broadcasts to output a result of the child nodes as array. It also ignores their `terminate?` methods by default.
277
269
 
278
270
  ##### Class style
279
271
 
@@ -327,61 +319,61 @@ Run `examples/class/internal-broadcastable.rb`:
327
319
  10 -> [nil, nil]
328
320
  ```
329
321
 
330
- ##### Builder style (experimental)
322
+ ##### Builder style
331
323
 
332
324
  `examples/builder/internal-broadcastable.rb`:
333
325
  ```ruby
334
- less_than = proc do |num|
326
+ def less_than(num)
335
327
  # The following block call is equivalent to calling `super` in the class style.
336
- proc { |input, &block| block.call(input) && input < num }
328
+ proc { |input, &original| original.call(input) && input < num }
337
329
  end
338
330
 
339
331
  LessThan5 =
340
332
  CallableTree::Node::Internal::Builder
341
333
  .new
342
- .matcher(&less_than.call(5))
334
+ .matcher(&method(:less_than).call(5))
343
335
  .build
344
336
 
345
337
  LessThan10 =
346
338
  CallableTree::Node::Internal::Builder
347
339
  .new
348
- .matcher(&less_than.call(10))
340
+ .matcher(&method(:less_than).call(10))
349
341
  .build
350
342
 
351
- add = proc do |num|
343
+ def add(num)
352
344
  proc { |input| input + num }
353
345
  end
354
346
 
355
347
  Add1 =
356
348
  CallableTree::Node::External::Builder
357
349
  .new
358
- .caller(&add.call(1))
350
+ .caller(&method(:add).call(1))
359
351
  .build
360
352
 
361
- subtract = proc do |num|
353
+ def subtract(num)
362
354
  proc { |input| input - num }
363
355
  end
364
356
 
365
357
  Subtract1 =
366
358
  CallableTree::Node::External::Builder
367
359
  .new
368
- .caller(&subtract.call(1))
360
+ .caller(&method(:subtract).call(1))
369
361
  .build
370
362
 
371
- multiply = proc do |num|
363
+ def multiply(num)
372
364
  proc { |input| input * num }
373
365
  end
374
366
 
375
367
  Multiply2 =
376
368
  CallableTree::Node::External::Builder
377
369
  .new
378
- .caller(&multiply.call(2))
370
+ .caller(&method(:multiply).call(2))
379
371
  .build
380
372
 
381
373
  Multiply3 =
382
374
  CallableTree::Node::External::Builder
383
375
  .new
384
- .caller(&multiply.call(3))
376
+ .caller(&method(:multiply).call(3))
385
377
  .build
386
378
 
387
379
  tree = CallableTree::Node::Root.new.broadcastable.append(
@@ -419,7 +411,8 @@ Run `examples/builder/internal-broadcastable.rb`:
419
411
 
420
412
  #### `CallableTree::Node::Internal#composable`
421
413
 
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.
414
+ This strategy composes the child nodes to input the output of the previous node into the next node and to output a result.
415
+ It also ignores their `terminate?` methods by default.
423
416
 
424
417
  ##### Class style
425
418
 
@@ -473,61 +466,61 @@ Run `examples/class/internal-composable.rb`:
473
466
  10 -> 10
474
467
  ```
475
468
 
476
- ##### Builder style (experimental)
469
+ ##### Builder style
477
470
 
478
471
  `examples/builder/internal-composable.rb`:
479
472
  ```ruby
480
- less_than = proc do |num|
473
+ def less_than(num)
481
474
  # The following block call is equivalent to calling `super` in the class style.
482
- proc { |input, &block| block.call(input) && input < num }
475
+ proc { |input, &original| original.call(input) && input < num }
483
476
  end
484
477
 
485
478
  LessThan5 =
486
479
  CallableTree::Node::Internal::Builder
487
480
  .new
488
- .matcher(&less_than.call(5))
481
+ .matcher(&method(:less_than).call(5))
489
482
  .build
490
483
 
491
484
  LessThan10 =
492
485
  CallableTree::Node::Internal::Builder
493
486
  .new
494
- .matcher(&less_than.call(10))
487
+ .matcher(&method(:less_than).call(10))
495
488
  .build
496
489
 
497
- add = proc do |num|
490
+ def add(num)
498
491
  proc { |input| input + num }
499
492
  end
500
493
 
501
494
  Add1 =
502
495
  CallableTree::Node::External::Builder
503
496
  .new
504
- .caller(&add.call(1))
497
+ .caller(&method(:add).call(1))
505
498
  .build
506
499
 
507
- subtract = proc do |num|
500
+ def subtract(num)
508
501
  proc { |input| input - num }
509
502
  end
510
503
 
511
504
  Subtract1 =
512
505
  CallableTree::Node::External::Builder
513
506
  .new
514
- .caller(&subtract.call(1))
507
+ .caller(&method(:subtract).call(1))
515
508
  .build
516
509
 
517
- multiply = proc do |num|
510
+ def multiply(num)
518
511
  proc { |input| input * num }
519
512
  end
520
513
 
521
514
  Multiply2 =
522
515
  CallableTree::Node::External::Builder
523
516
  .new
524
- .caller(&multiply.call(2))
517
+ .caller(&method(:multiply).call(2))
525
518
  .build
526
519
 
527
520
  Multiply3 =
528
521
  CallableTree::Node::External::Builder
529
522
  .new
530
- .caller(&multiply.call(3))
523
+ .caller(&method(:multiply).call(3))
531
524
  .build
532
525
 
533
526
  tree = CallableTree::Node::Root.new.composable.append(
@@ -569,311 +562,244 @@ Run `examples/builder/internal-composable.rb`:
569
562
 
570
563
  If you want verbose output results, call this method.
571
564
 
572
- `examples/class/external-verbosify.rb`:
565
+ `examples/builder/external-verbosify.rb`:
573
566
  ```ruby
574
567
  ...
575
568
 
576
- tree = CallableTree::Node::Root.new.append(
577
- Node::JSON::Parser.new.append(
578
- Node::JSON::Scraper.new(type: :animals).verbosify,
579
- Node::JSON::Scraper.new(type: :fruits).verbosify
569
+ tree = CallableTree::Node::Root.new.seekable.append(
570
+ JSONParser.new.seekable.append(
571
+ AnimalsJSONScraper.new.verbosify,
572
+ FruitsJSONScraper.new.verbosify
580
573
  ),
581
- Node::XML::Parser.new.append(
582
- Node::XML::Scraper.new(type: :animals).verbosify,
583
- Node::XML::Scraper.new(type: :fruits).verbosify
574
+ XMLParser.new.seekable.append(
575
+ AnimalsXMLScraper.new.verbosify,
576
+ FruitsXMLScraper.new.verbosify
584
577
  )
585
578
  )
586
579
 
587
580
  ...
588
581
  ```
589
582
 
590
- Run `examples/class/external-verbosify.rb`:
583
+ Run `examples/builder/external-verbosify.rb`:
591
584
  ```sh
592
585
  % ruby examples/class/external-verbosify.rb
593
586
  #<struct CallableTree::Node::External::Output
594
- value={"Dog"=>"🐶", "Cat"=>"🐱"},
595
- options={:foo=>:bar},
596
- routes=[Node::JSON::Scraper, Node::JSON::Parser, CallableTree::Node::Root]>
587
+ value={"Dog"=>"🐶", "Cat"=>"🐱"},
588
+ options={:foo=>:bar},
589
+ routes=[AnimalsJSONScraper, JSONParser, CallableTree::Node::Root]>
597
590
  ---
598
591
  #<struct CallableTree::Node::External::Output
599
- value={"Dog"=>"🐶", "Cat"=>"🐱"},
600
- options={:foo=>:bar},
601
- routes=[Node::XML::Scraper, Node::XML::Parser, CallableTree::Node::Root]>
592
+ value={"Dog"=>"🐶", "Cat"=>"🐱"},
593
+ options={:foo=>:bar},
594
+ routes=[AnimalsXMLScraper, XMLParser, CallableTree::Node::Root]>
602
595
  ---
603
596
  #<struct CallableTree::Node::External::Output
604
- value={"Red Apple"=>"🍎", "Green Apple"=>"🍏"},
605
- options={:foo=>:bar},
606
- routes=[Node::JSON::Scraper, Node::JSON::Parser, CallableTree::Node::Root]>
597
+ value={"Red Apple"=>"🍎", "Green Apple"=>"🍏"},
598
+ options={:foo=>:bar},
599
+ routes=[FruitsJSONScraper, JSONParser, CallableTree::Node::Root]>
607
600
  ---
608
601
  #<struct CallableTree::Node::External::Output
609
- value={"Red Apple"=>"🍎", "Green Apple"=>"🍏"},
610
- options={:foo=>:bar},
611
- routes=[Node::XML::Scraper, Node::XML::Parser, CallableTree::Node::Root]>
602
+ value={"Red Apple"=>"🍎", "Green Apple"=>"🍏"},
603
+ options={:foo=>:bar},
604
+ routes=[FruitsXMLScraper, XMLParser, CallableTree::Node::Root]>
612
605
  ---
613
606
  ```
614
607
 
615
- At first glance, this looks good, but the `routes` are ambiguous when there are multiple nodes of the same class.
616
- You can work around it by overriding the `identity` method of the node.
617
-
618
- #### `CallableTree::Node#identity`
608
+ #### Logging
619
609
 
620
- If you want to customize the node identity, override this method.
610
+ This is an example of logging.
621
611
 
622
- `examples/class/identity.rb`:
612
+ `examples/builder/logging.rb`:
623
613
  ```ruby
624
- module Node
625
- class Identity
626
- attr_reader :klass, :type
627
-
628
- def initialize(klass:, type:)
629
- @klass = klass
630
- @type = type
631
- end
614
+ JSONParser =
615
+ CallableTree::Node::Internal::Builder
616
+ .new
617
+ ...
618
+ .hookable
619
+ .build
632
620
 
633
- def to_s
634
- "#{klass}(#{type})"
635
- end
636
- end
621
+ XMLParser =
622
+ CallableTree::Node::Internal::Builder
623
+ .new
624
+ ...
625
+ .hookable
626
+ .build
637
627
 
638
- module JSON
628
+ def build_json_scraper(type)
629
+ CallableTree::Node::External::Builder
630
+ .new
639
631
  ...
632
+ .hookable
633
+ .build
634
+ end
640
635
 
641
- class Scraper
642
- include CallableTree::Node::External
636
+ ...
643
637
 
644
- def initialize(type:)
645
- @type = type
646
- end
638
+ def build_xml_scraper(type)
639
+ CallableTree::Node::External::Builder
640
+ .new
641
+ ...
642
+ .hookable
643
+ .build
644
+ end
647
645
 
648
- def identity
649
- Identity.new(klass: super, type: @type)
650
- end
646
+ ...
651
647
 
652
- ...
653
- end
654
- end
648
+ module Logging
649
+ INDENT_SIZE = 2
650
+ BLANK = ' '
651
+ LIST_STYLE = '*'
652
+ INPUT_LABEL = 'Input :'
653
+ OUTPUT_LABEL = 'Output:'
655
654
 
656
- module XML
657
- ...
655
+ def self.loggable(node)
656
+ node.after_matcher! do |matched, _node_:, **|
657
+ prefix = LIST_STYLE.rjust((_node_.depth * INDENT_SIZE) - INDENT_SIZE + LIST_STYLE.length, BLANK)
658
+ puts "#{prefix} #{_node_.identity}: [matched: #{matched}]"
659
+ matched
660
+ end
658
661
 
659
- class Scraper
660
- include CallableTree::Node::External
662
+ return unless node.external?
661
663
 
662
- def initialize(type:)
663
- @type = type
664
+ node
665
+ .before_caller! do |input, *, _node_:, **|
666
+ input_prefix = INPUT_LABEL.rjust((_node_.depth * INDENT_SIZE) + INPUT_LABEL.length, BLANK)
667
+ puts "#{input_prefix} #{input}"
668
+ input
664
669
  end
665
-
666
- def identity
667
- Identity.new(klass: super, type: @type)
670
+ .after_caller! do |output, _node_:, **|
671
+ output_prefix = OUTPUT_LABEL.rjust((_node_.depth * INDENT_SIZE) + OUTPUT_LABEL.length, BLANK)
672
+ puts "#{output_prefix} #{output}"
673
+ output
668
674
  end
669
-
670
- ...
671
- end
672
675
  end
673
676
  end
674
677
 
678
+ loggable = Logging.method(:loggable)
679
+
680
+ tree = CallableTree::Node::Root.new.seekable.append(
681
+ JSONParser.new.tap(&loggable).seekable.append(
682
+ AnimalsJSONScraper.new.tap(&loggable).verbosify,
683
+ FruitsJSONScraper.new.tap(&loggable).verbosify
684
+ ),
685
+ XMLParser.new.tap(&loggable).seekable.append(
686
+ AnimalsXMLScraper.new.tap(&loggable).verbosify,
687
+ FruitsXMLScraper.new.tap(&loggable).verbosify
688
+ )
689
+ )
690
+
675
691
  ...
676
692
  ```
677
693
 
678
- Run `examples/class/identity.rb`:
694
+ Also, see `examples/builder/hooks.rb` for detail about `CallableTree::Node::Hooks::*`.
695
+
696
+ Run `examples/builder/logging.rb`:
679
697
  ```sh
680
- % ruby examples/class/identity.rb
698
+ % ruby examples/builder/logging.rb
699
+ * JSONParser: [matched: true]
700
+ * AnimalsJSONScraper: [matched: true]
701
+ Input : {"animals"=>[{"name"=>"Dog", "emoji"=>"🐶"}, {"name"=>"Cat", "emoji"=>"🐱"}]}
702
+ Output: {"Dog"=>"🐶", "Cat"=>"🐱"}
681
703
  #<struct CallableTree::Node::External::Output
682
704
  value={"Dog"=>"🐶", "Cat"=>"🐱"},
683
705
  options={:foo=>:bar},
684
- routes=
685
- [#<Node::Identity:0x00007fb4378a9718
686
- @klass=Node::JSON::Scraper,
687
- @type=:animals>,
688
- Node::JSON::Parser,
689
- CallableTree::Node::Root]>
706
+ routes=[AnimalsJSONScraper, JSONParser, CallableTree::Node::Root]>
690
707
  ---
708
+ * JSONParser: [matched: false]
709
+ * XMLParser: [matched: true]
710
+ * AnimalsXMLScraper: [matched: true]
711
+ Input : <root><animals><animal emoji='🐶' name='Dog'/><animal emoji='🐱' name='Cat'/></animals></root>
712
+ Output: {"Dog"=>"🐶", "Cat"=>"🐱"}
691
713
  #<struct CallableTree::Node::External::Output
692
714
  value={"Dog"=>"🐶", "Cat"=>"🐱"},
693
715
  options={:foo=>:bar},
694
- routes=
695
- [#<Node::Identity:0x00007fb41002b6d0
696
- @klass=Node::XML::Scraper,
697
- @type=:animals>,
698
- Node::XML::Parser,
699
- CallableTree::Node::Root]>
716
+ routes=[AnimalsXMLScraper, XMLParser, CallableTree::Node::Root]>
700
717
  ---
718
+ * JSONParser: [matched: true]
719
+ * AnimalsJSONScraper: [matched: false]
720
+ * FruitsJSONScraper: [matched: true]
721
+ Input : {"fruits"=>[{"name"=>"Red Apple", "emoji"=>"🍎"}, {"name"=>"Green Apple", "emoji"=>"🍏"}]}
722
+ Output: {"Red Apple"=>"🍎", "Green Apple"=>"🍏"}
701
723
  #<struct CallableTree::Node::External::Output
702
724
  value={"Red Apple"=>"🍎", "Green Apple"=>"🍏"},
703
725
  options={:foo=>:bar},
704
- routes=
705
- [#<Node::Identity:0x00007fb41001b3e8
706
- @klass=Node::JSON::Scraper,
707
- @type=:fruits>,
708
- Node::JSON::Parser,
709
- CallableTree::Node::Root]>
726
+ routes=[FruitsJSONScraper, JSONParser, CallableTree::Node::Root]>
710
727
  ---
728
+ * JSONParser: [matched: false]
729
+ * XMLParser: [matched: true]
730
+ * AnimalsXMLScraper: [matched: false]
731
+ * FruitsXMLScraper: [matched: true]
732
+ Input : <root><fruits><fruit emoji='🍎' name='Red Apple'/><fruit emoji='🍏' name='Green Apple'/></fruits></root>
733
+ Output: {"Red Apple"=>"🍎", "Green Apple"=>"🍏"}
711
734
  #<struct CallableTree::Node::External::Output
712
735
  value={"Red Apple"=>"🍎", "Green Apple"=>"🍏"},
713
736
  options={:foo=>:bar},
714
- routes=
715
- [#<Node::Identity:0x00007fb410049d38
716
- @klass=Node::XML::Scraper,
717
- @type=:fruits>,
718
- Node::XML::Parser,
719
- CallableTree::Node::Root]>
720
- ---
737
+ routes=[FruitsXMLScraper, XMLParser, CallableTree::Node::Root]>
721
738
  ```
722
739
 
723
- #### Logging
740
+ #### `CallableTree::Node#identity`
724
741
 
725
- This is an example of logging.
742
+ If you want to customize the node identity, specify identifier.
726
743
 
727
- `examples/class/logging.rb`:
744
+ `examples/builder/identity.rb`:
728
745
  ```ruby
729
- module Node
746
+ JSONParser =
747
+ CallableTree::Node::Internal::Builder
748
+ .new
730
749
  ...
750
+ .identifier { |_node_:| _node_.object_id }
751
+ .build
731
752
 
732
- module JSON
733
- class Parser
734
- include CallableTree::Node::Internal
735
- prepend CallableTree::Node::Hooks::Matcher
736
-
737
- ...
738
- end
739
-
740
- class Scraper
741
- include CallableTree::Node::External
742
- prepend CallableTree::Node::Hooks::Matcher
743
- prepend CallableTree::Node::Hooks::Caller
744
-
745
- ...
746
- end
747
- end
748
-
749
- module XML
750
- class Parser
751
- include CallableTree::Node::Internal
752
- prepend CallableTree::Node::Hooks::Matcher
753
-
754
- ...
755
- end
756
-
757
- class Scraper
758
- include CallableTree::Node::External
759
- prepend CallableTree::Node::Hooks::Matcher
760
- prepend CallableTree::Node::Hooks::Caller
753
+ XMLParser =
754
+ CallableTree::Node::Internal::Builder
755
+ .new
756
+ ...
757
+ .identifier { |_node_:| _node_.object_id }
758
+ .build
761
759
 
762
- ...
763
- end
764
- end
760
+ def build_json_scraper(type)
761
+ CallableTree::Node::External::Builder
762
+ .new
763
+ ...
764
+ .identifier { |_node_:| _node_.object_id }
765
+ .build
765
766
  end
766
767
 
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
768
+ ...
780
769
 
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
770
+ def build_xml_scraper(type)
771
+ CallableTree::Node::External::Builder
772
+ .new
773
+ ...
774
+ .identifier { |_node_:| _node_.object_id }
775
+ .build
795
776
  end
796
777
 
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
-
810
778
  ...
811
779
  ```
812
780
 
813
- Also, see `examples/class/hooks.rb` for detail about `CallableTree::Node::Hooks::*`.
814
-
815
- Run `examples/class/logging.rb`:
781
+ Run `examples/builder/identity.rb`:
816
782
  ```sh
817
- % ruby examples/class/logging.rb
818
- * Node::JSON::Parser: [matched: true]
819
- * Node::JSON::Scraper(animals): [matched: true]
820
- Input : {"animals"=>[{"name"=>"Dog", "emoji"=>"🐶"}, {"name"=>"Cat", "emoji"=>"🐱"}]}
821
- Output: {"Dog"=>"🐶", "Cat"=>"🐱"}
783
+ % ruby examples/builder/identity.rb
822
784
  #<struct CallableTree::Node::External::Output
823
- value={"Dog"=>"🐶", "Cat"=>"🐱"},
824
- options={:foo=>:bar},
825
- routes=
826
- [#<Node::Identity:0x00007ffd840347b8
827
- @klass=Node::JSON::Scraper,
828
- @type=:animals>,
829
- Node::JSON::Parser,
830
- CallableTree::Node::Root]>
785
+ value={"Dog"=>"🐶", "Cat"=>"🐱"},
786
+ options={:foo=>:bar},
787
+ routes=[60, 80, CallableTree::Node::Root]>
831
788
  ---
832
- * Node::JSON::Parser: [matched: false]
833
- * Node::XML::Parser: [matched: true]
834
- * Node::XML::Scraper(animals): [matched: true]
835
- Input : <root><animals><animal emoji='🐶' name='Dog'/><animal emoji='🐱' name='Cat'/></animals></root>
836
- Output: {"Dog"=>"🐶", "Cat"=>"🐱"}
837
789
  #<struct CallableTree::Node::External::Output
838
- value={"Dog"=>"🐶", "Cat"=>"🐱"},
839
- options={:foo=>:bar},
840
- routes=
841
- [#<Node::Identity:0x00007ffd7403f1f0
842
- @klass=Node::XML::Scraper,
843
- @type=:animals>,
844
- Node::XML::Parser,
845
- CallableTree::Node::Root]>
790
+ value={"Dog"=>"🐶", "Cat"=>"🐱"},
791
+ options={:foo=>:bar},
792
+ routes=[220, 240, CallableTree::Node::Root]>
846
793
  ---
847
- * Node::JSON::Parser: [matched: true]
848
- * Node::JSON::Scraper(animals): [matched: false]
849
- * Node::JSON::Scraper(fruits): [matched: true]
850
- Input : {"fruits"=>[{"name"=>"Red Apple", "emoji"=>"🍎"}, {"name"=>"Green Apple", "emoji"=>"🍏"}]}
851
- Output: {"Red Apple"=>"🍎", "Green Apple"=>"🍏"}
852
794
  #<struct CallableTree::Node::External::Output
853
795
  value={"Red Apple"=>"🍎", "Green Apple"=>"🍏"},
854
796
  options={:foo=>:bar},
855
- routes=
856
- [#<Node::Identity:0x00007ffd8512bdf0
857
- @klass=Node::JSON::Scraper,
858
- @type=:fruits>,
859
- Node::JSON::Parser,
860
- CallableTree::Node::Root]>
797
+ routes=[260, 80, CallableTree::Node::Root]>
861
798
  ---
862
- * Node::JSON::Parser: [matched: false]
863
- * Node::XML::Parser: [matched: true]
864
- * Node::XML::Scraper(animals): [matched: false]
865
- * Node::XML::Scraper(fruits): [matched: true]
866
- Input : <root><fruits><fruit emoji='🍎' name='Red Apple'/><fruit emoji='🍏' name='Green Apple'/></fruits></root>
867
- Output: {"Red Apple"=>"🍎", "Green Apple"=>"🍏"}
868
799
  #<struct CallableTree::Node::External::Output
869
800
  value={"Red Apple"=>"🍎", "Green Apple"=>"🍏"},
870
801
  options={:foo=>:bar},
871
- routes=
872
- [#<Node::Identity:0x00007ffd8407a740
873
- @klass=Node::XML::Scraper,
874
- @type=:fruits>,
875
- Node::XML::Parser,
876
- CallableTree::Node::Root]>
802
+ routes=[400, 240, CallableTree::Node::Root]>
877
803
  ---
878
804
  ```
879
805