callable_tree 0.3.8 → 0.3.9

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,154 +562,46 @@ 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]>
612
- ---
613
- ```
614
-
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`
619
-
620
- If you want to customize the node identity, override this method.
621
-
622
- `examples/class/identity.rb`:
623
- ```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
632
-
633
- def to_s
634
- "#{klass}(#{type})"
635
- end
636
- end
637
-
638
- module JSON
639
- ...
640
-
641
- class Scraper
642
- include CallableTree::Node::External
643
-
644
- def initialize(type:)
645
- @type = type
646
- end
647
-
648
- def identity
649
- Identity.new(klass: super, type: @type)
650
- end
651
-
652
- ...
653
- end
654
- end
655
-
656
- module XML
657
- ...
658
-
659
- class Scraper
660
- include CallableTree::Node::External
661
-
662
- def initialize(type:)
663
- @type = type
664
- end
665
-
666
- def identity
667
- Identity.new(klass: super, type: @type)
668
- end
669
-
670
- ...
671
- end
672
- end
673
- end
674
-
675
- ...
676
- ```
677
-
678
- Run `examples/class/identity.rb`:
679
- ```sh
680
- % ruby examples/class/identity.rb
681
- #<struct CallableTree::Node::External::Output
682
- value={"Dog"=>"🐶", "Cat"=>"🐱"},
683
- 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]>
690
- ---
691
- #<struct CallableTree::Node::External::Output
692
- value={"Dog"=>"🐶", "Cat"=>"🐱"},
693
- 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]>
700
- ---
701
- #<struct CallableTree::Node::External::Output
702
- value={"Red Apple"=>"🍎", "Green Apple"=>"🍏"},
703
- 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]>
710
- ---
711
- #<struct CallableTree::Node::External::Output
712
- value={"Red Apple"=>"🍎", "Green Apple"=>"🍏"},
713
- 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]>
602
+ value={"Red Apple"=>"🍎", "Green Apple"=>"🍏"},
603
+ options={:foo=>:bar},
604
+ routes=[FruitsXMLScraper, XMLParser, CallableTree::Node::Root]>
720
605
  ---
721
606
  ```
722
607
 
@@ -724,46 +609,42 @@ Run `examples/class/identity.rb`:
724
609
 
725
610
  This is an example of logging.
726
611
 
727
- `examples/class/logging.rb`:
612
+ `examples/builder/logging.rb`:
728
613
  ```ruby
729
- module Node
614
+ JSONParser =
615
+ CallableTree::Node::Internal::Builder
616
+ .new
730
617
  ...
618
+ .hookable
619
+ .build
731
620
 
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
621
+ XMLParser =
622
+ CallableTree::Node::Internal::Builder
623
+ .new
624
+ ...
625
+ .hookable
626
+ .build
753
627
 
754
- ...
755
- end
628
+ def build_json_scraper(type)
629
+ CallableTree::Node::External::Builder
630
+ .new
631
+ ...
632
+ .hookable
633
+ .build
634
+ end
756
635
 
757
- class Scraper
758
- include CallableTree::Node::External
759
- prepend CallableTree::Node::Hooks::Matcher
760
- prepend CallableTree::Node::Hooks::Caller
636
+ ...
761
637
 
762
- ...
763
- end
764
- end
638
+ def build_xml_scraper(type)
639
+ CallableTree::Node::External::Builder
640
+ .new
641
+ ...
642
+ .hookable
643
+ .build
765
644
  end
766
645
 
646
+ ...
647
+
767
648
  module Logging
768
649
  INDENT_SIZE = 2
769
650
  BLANK = ' '
@@ -773,7 +654,7 @@ module Logging
773
654
 
774
655
  def self.loggable(node)
775
656
  node.after_matcher! do |matched, _node_:, **|
776
- prefix = LIST_STYLE.rjust(_node_.depth * INDENT_SIZE - INDENT_SIZE + LIST_STYLE.length, BLANK)
657
+ prefix = LIST_STYLE.rjust((_node_.depth * INDENT_SIZE) - INDENT_SIZE + LIST_STYLE.length, BLANK)
777
658
  puts "#{prefix} #{_node_.identity}: [matched: #{matched}]"
778
659
  matched
779
660
  end
@@ -781,12 +662,12 @@ module Logging
781
662
  if node.external?
782
663
  node
783
664
  .before_caller! do |input, *, _node_:, **|
784
- input_prefix = INPUT_LABEL.rjust(_node_.depth * INDENT_SIZE + INPUT_LABEL.length, BLANK)
665
+ input_prefix = INPUT_LABEL.rjust((_node_.depth * INDENT_SIZE) + INPUT_LABEL.length, BLANK)
785
666
  puts "#{input_prefix} #{input}"
786
667
  input
787
668
  end
788
669
  .after_caller! do |output, _node_:, **|
789
- output_prefix = OUTPUT_LABEL.rjust(_node_.depth * INDENT_SIZE + OUTPUT_LABEL.length, BLANK)
670
+ output_prefix = OUTPUT_LABEL.rjust((_node_.depth * INDENT_SIZE) + OUTPUT_LABEL.length, BLANK)
790
671
  puts "#{output_prefix} #{output}"
791
672
  output
792
673
  end
@@ -796,84 +677,129 @@ end
796
677
 
797
678
  loggable = Logging.method(:loggable)
798
679
 
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
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
803
684
  ),
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
685
+ XMLParser.new.tap(&loggable).seekable.append(
686
+ AnimalsXMLScraper.new.tap(&loggable).verbosify,
687
+ FruitsXMLScraper.new.tap(&loggable).verbosify
807
688
  )
808
689
  )
809
690
 
810
691
  ...
811
692
  ```
812
693
 
813
- Also, see `examples/class/hooks.rb` for detail about `CallableTree::Node::Hooks::*`.
694
+ Also, see `examples/builder/hooks.rb` for detail about `CallableTree::Node::Hooks::*`.
814
695
 
815
- Run `examples/class/logging.rb`:
696
+ Run `examples/builder/logging.rb`:
816
697
  ```sh
817
- % ruby examples/class/logging.rb
818
- * Node::JSON::Parser: [matched: true]
819
- * Node::JSON::Scraper(animals): [matched: true]
698
+ % ruby examples/builder/logging.rb
699
+ * JSONParser: [matched: true]
700
+ * AnimalsJSONScraper: [matched: true]
820
701
  Input : {"animals"=>[{"name"=>"Dog", "emoji"=>"🐶"}, {"name"=>"Cat", "emoji"=>"🐱"}]}
821
702
  Output: {"Dog"=>"🐶", "Cat"=>"🐱"}
822
703
  #<struct CallableTree::Node::External::Output
823
704
  value={"Dog"=>"🐶", "Cat"=>"🐱"},
824
705
  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]>
706
+ routes=[AnimalsJSONScraper, JSONParser, CallableTree::Node::Root]>
831
707
  ---
832
- * Node::JSON::Parser: [matched: false]
833
- * Node::XML::Parser: [matched: true]
834
- * Node::XML::Scraper(animals): [matched: true]
708
+ * JSONParser: [matched: false]
709
+ * XMLParser: [matched: true]
710
+ * AnimalsXMLScraper: [matched: true]
835
711
  Input : <root><animals><animal emoji='🐶' name='Dog'/><animal emoji='🐱' name='Cat'/></animals></root>
836
712
  Output: {"Dog"=>"🐶", "Cat"=>"🐱"}
837
713
  #<struct CallableTree::Node::External::Output
838
714
  value={"Dog"=>"🐶", "Cat"=>"🐱"},
839
715
  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]>
716
+ routes=[AnimalsXMLScraper, XMLParser, CallableTree::Node::Root]>
846
717
  ---
847
- * Node::JSON::Parser: [matched: true]
848
- * Node::JSON::Scraper(animals): [matched: false]
849
- * Node::JSON::Scraper(fruits): [matched: true]
718
+ * JSONParser: [matched: true]
719
+ * AnimalsJSONScraper: [matched: false]
720
+ * FruitsJSONScraper: [matched: true]
850
721
  Input : {"fruits"=>[{"name"=>"Red Apple", "emoji"=>"🍎"}, {"name"=>"Green Apple", "emoji"=>"🍏"}]}
851
722
  Output: {"Red Apple"=>"🍎", "Green Apple"=>"🍏"}
852
723
  #<struct CallableTree::Node::External::Output
853
724
  value={"Red Apple"=>"🍎", "Green Apple"=>"🍏"},
854
725
  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]>
726
+ routes=[FruitsJSONScraper, JSONParser, CallableTree::Node::Root]>
861
727
  ---
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]
728
+ * JSONParser: [matched: false]
729
+ * XMLParser: [matched: true]
730
+ * AnimalsXMLScraper: [matched: false]
731
+ * FruitsXMLScraper: [matched: true]
866
732
  Input : <root><fruits><fruit emoji='🍎' name='Red Apple'/><fruit emoji='🍏' name='Green Apple'/></fruits></root>
867
733
  Output: {"Red Apple"=>"🍎", "Green Apple"=>"🍏"}
868
734
  #<struct CallableTree::Node::External::Output
869
735
  value={"Red Apple"=>"🍎", "Green Apple"=>"🍏"},
870
736
  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]>
737
+ routes=[FruitsXMLScraper, XMLParser, CallableTree::Node::Root]>
738
+ ```
739
+
740
+ #### `CallableTree::Node#identity`
741
+
742
+ If you want to customize the node identity, specify identifier.
743
+
744
+ `examples/builder/identity.rb`:
745
+ ```ruby
746
+ JSONParser =
747
+ CallableTree::Node::Internal::Builder
748
+ .new
749
+ ...
750
+ .identifier { |_node_:| _node_.object_id }
751
+ .build
752
+
753
+ XMLParser =
754
+ CallableTree::Node::Internal::Builder
755
+ .new
756
+ ...
757
+ .identifier { |_node_:| _node_.object_id }
758
+ .build
759
+
760
+ def build_json_scraper(type)
761
+ CallableTree::Node::External::Builder
762
+ .new
763
+ ...
764
+ .identifier { |_node_:| _node_.object_id }
765
+ .build
766
+ end
767
+
768
+ ...
769
+
770
+ def build_xml_scraper(type)
771
+ CallableTree::Node::External::Builder
772
+ .new
773
+ ...
774
+ .identifier { |_node_:| _node_.object_id }
775
+ .build
776
+ end
777
+
778
+ ...
779
+ ```
780
+
781
+ Run `examples/class/identity.rb`:
782
+ ```sh
783
+ % ruby examples/builder/identity.rb
784
+ #<struct CallableTree::Node::External::Output
785
+ value={"Dog"=>"🐶", "Cat"=>"🐱"},
786
+ options={:foo=>:bar},
787
+ routes=[60, 80, CallableTree::Node::Root]>
788
+ ---
789
+ #<struct CallableTree::Node::External::Output
790
+ value={"Dog"=>"🐶", "Cat"=>"🐱"},
791
+ options={:foo=>:bar},
792
+ routes=[220, 240, CallableTree::Node::Root]>
793
+ ---
794
+ #<struct CallableTree::Node::External::Output
795
+ value={"Red Apple"=>"🍎", "Green Apple"=>"🍏"},
796
+ options={:foo=>:bar},
797
+ routes=[260, 80, CallableTree::Node::Root]>
798
+ ---
799
+ #<struct CallableTree::Node::External::Output
800
+ value={"Red Apple"=>"🍎", "Green Apple"=>"🍏"},
801
+ options={:foo=>:bar},
802
+ routes=[400, 240, CallableTree::Node::Root]>
877
803
  ---
878
804
  ```
879
805