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.
- checksums.yaml +4 -4
- data/.github/dependabot.yml +7 -0
- data/.github/workflows/build.yml +4 -6
- data/.github/workflows/codeql-analysis.yml +4 -4
- data/.ruby-version +1 -1
- data/CHANGELOG.md +12 -0
- data/Gemfile.lock +14 -14
- data/README.md +191 -265
- data/examples/builder/external-verbosify.rb +87 -0
- data/examples/builder/identity.rb +91 -0
- data/examples/builder/internal-broadcastable.rb +11 -11
- data/examples/builder/internal-composable.rb +11 -11
- data/examples/builder/internal-seekable.rb +10 -16
- data/examples/builder/logging.rb +21 -27
- data/examples/class/external-verbosify.rb +2 -4
- data/examples/class/identity.rb +2 -4
- data/examples/class/internal-seekable.rb +2 -4
- data/examples/class/logging.rb +15 -17
- data/lib/callable_tree/node/external.rb +4 -4
- data/lib/callable_tree/node/internal/strategy/broadcast.rb +12 -2
- data/lib/callable_tree/node/internal/strategy/compose.rb +10 -3
- data/lib/callable_tree/node/internal/strategy/seek.rb +7 -2
- data/lib/callable_tree/node/internal/strategy.rb +32 -2
- data/lib/callable_tree/node/internal/strategyable.rb +117 -0
- data/lib/callable_tree/node/internal.rb +13 -92
- data/lib/callable_tree/node.rb +1 -1
- data/lib/callable_tree/version.rb +1 -1
- data/lib/callable_tree.rb +1 -0
- metadata +8 -4
| @@ -0,0 +1,87 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'callable_tree'
         | 
| 4 | 
            +
            require 'json'
         | 
| 5 | 
            +
            require 'rexml/document'
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            JSONParser =
         | 
| 8 | 
            +
              CallableTree::Node::Internal::Builder
         | 
| 9 | 
            +
              .new
         | 
| 10 | 
            +
              .matcher do |input, **_options|
         | 
| 11 | 
            +
                File.extname(input) == '.json'
         | 
| 12 | 
            +
              end
         | 
| 13 | 
            +
              .caller do |input, **options, &block|
         | 
| 14 | 
            +
                File.open(input) do |file|
         | 
| 15 | 
            +
                  json = JSON.load(file)
         | 
| 16 | 
            +
                  # The following block call is equivalent to calling `super` in the class style.
         | 
| 17 | 
            +
                  block.call(json, **options)
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
              end
         | 
| 20 | 
            +
              .terminator { true }
         | 
| 21 | 
            +
              .build
         | 
| 22 | 
            +
             | 
| 23 | 
            +
            XMLParser =
         | 
| 24 | 
            +
              CallableTree::Node::Internal::Builder
         | 
| 25 | 
            +
              .new
         | 
| 26 | 
            +
              .matcher do |input, **_options|
         | 
| 27 | 
            +
                File.extname(input) == '.xml'
         | 
| 28 | 
            +
              end
         | 
| 29 | 
            +
              .caller do |input, **options, &block|
         | 
| 30 | 
            +
                File.open(input) do |file|
         | 
| 31 | 
            +
                  # The following block call is equivalent to calling `super` in the class style.
         | 
| 32 | 
            +
                  block.call(REXML::Document.new(file), **options)
         | 
| 33 | 
            +
                end
         | 
| 34 | 
            +
              end
         | 
| 35 | 
            +
              .terminator { true }
         | 
| 36 | 
            +
              .build
         | 
| 37 | 
            +
             | 
| 38 | 
            +
            def build_json_scraper(type)
         | 
| 39 | 
            +
              CallableTree::Node::External::Builder
         | 
| 40 | 
            +
                .new
         | 
| 41 | 
            +
                .matcher do |input, **_options|
         | 
| 42 | 
            +
                  !input[type.to_s].nil?
         | 
| 43 | 
            +
                end
         | 
| 44 | 
            +
                .caller do |input, **_options|
         | 
| 45 | 
            +
                  input[type.to_s]
         | 
| 46 | 
            +
                    .to_h { |element| [element['name'], element['emoji']] }
         | 
| 47 | 
            +
                end
         | 
| 48 | 
            +
                .build
         | 
| 49 | 
            +
            end
         | 
| 50 | 
            +
             | 
| 51 | 
            +
            AnimalsJSONScraper = build_json_scraper(:animals)
         | 
| 52 | 
            +
            FruitsJSONScraper = build_json_scraper(:fruits)
         | 
| 53 | 
            +
             | 
| 54 | 
            +
            def build_xml_scraper(type)
         | 
| 55 | 
            +
              CallableTree::Node::External::Builder
         | 
| 56 | 
            +
                .new
         | 
| 57 | 
            +
                .matcher do |input, **_options|
         | 
| 58 | 
            +
                  !input.get_elements("//#{type}").empty?
         | 
| 59 | 
            +
                end
         | 
| 60 | 
            +
                .caller do |input, **_options|
         | 
| 61 | 
            +
                  input
         | 
| 62 | 
            +
                    .get_elements("//#{type}")
         | 
| 63 | 
            +
                    .first
         | 
| 64 | 
            +
                    .to_h { |element| [element['name'], element['emoji']] }
         | 
| 65 | 
            +
                end
         | 
| 66 | 
            +
                .build
         | 
| 67 | 
            +
            end
         | 
| 68 | 
            +
             | 
| 69 | 
            +
            AnimalsXMLScraper = build_xml_scraper(:animals)
         | 
| 70 | 
            +
            FruitsXMLScraper = build_xml_scraper(:fruits)
         | 
| 71 | 
            +
             | 
| 72 | 
            +
            tree = CallableTree::Node::Root.new.seekable.append(
         | 
| 73 | 
            +
              JSONParser.new.seekable.append(
         | 
| 74 | 
            +
                AnimalsJSONScraper.new.verbosify,
         | 
| 75 | 
            +
                FruitsJSONScraper.new.verbosify
         | 
| 76 | 
            +
              ),
         | 
| 77 | 
            +
              XMLParser.new.seekable.append(
         | 
| 78 | 
            +
                AnimalsXMLScraper.new.verbosify,
         | 
| 79 | 
            +
                FruitsXMLScraper.new.verbosify
         | 
| 80 | 
            +
              )
         | 
| 81 | 
            +
            )
         | 
| 82 | 
            +
             | 
| 83 | 
            +
            Dir.glob("#{__dir__}/../docs/*") do |file|
         | 
| 84 | 
            +
              options = { foo: :bar }
         | 
| 85 | 
            +
              pp tree.call(file, **options)
         | 
| 86 | 
            +
              puts '---'
         | 
| 87 | 
            +
            end
         | 
| @@ -0,0 +1,91 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'callable_tree'
         | 
| 4 | 
            +
            require 'json'
         | 
| 5 | 
            +
            require 'rexml/document'
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            JSONParser =
         | 
| 8 | 
            +
              CallableTree::Node::Internal::Builder
         | 
| 9 | 
            +
              .new
         | 
| 10 | 
            +
              .matcher do |input, **_options|
         | 
| 11 | 
            +
                File.extname(input) == '.json'
         | 
| 12 | 
            +
              end
         | 
| 13 | 
            +
              .caller do |input, **options, &block|
         | 
| 14 | 
            +
                File.open(input) do |file|
         | 
| 15 | 
            +
                  json = JSON.load(file)
         | 
| 16 | 
            +
                  # The following block call is equivalent to calling `super` in the class style.
         | 
| 17 | 
            +
                  block.call(json, **options)
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
              end
         | 
| 20 | 
            +
              .terminator { true }
         | 
| 21 | 
            +
              .identifier { |_node_:| _node_.object_id }
         | 
| 22 | 
            +
              .build
         | 
| 23 | 
            +
             | 
| 24 | 
            +
            XMLParser =
         | 
| 25 | 
            +
              CallableTree::Node::Internal::Builder
         | 
| 26 | 
            +
              .new
         | 
| 27 | 
            +
              .matcher do |input, **_options|
         | 
| 28 | 
            +
                File.extname(input) == '.xml'
         | 
| 29 | 
            +
              end
         | 
| 30 | 
            +
              .caller do |input, **options, &block|
         | 
| 31 | 
            +
                File.open(input) do |file|
         | 
| 32 | 
            +
                  # The following block call is equivalent to calling `super` in the class style.
         | 
| 33 | 
            +
                  block.call(REXML::Document.new(file), **options)
         | 
| 34 | 
            +
                end
         | 
| 35 | 
            +
              end
         | 
| 36 | 
            +
              .terminator { true }
         | 
| 37 | 
            +
              .identifier { |_node_:| _node_.object_id }
         | 
| 38 | 
            +
              .build
         | 
| 39 | 
            +
             | 
| 40 | 
            +
            def build_json_scraper(type)
         | 
| 41 | 
            +
              CallableTree::Node::External::Builder
         | 
| 42 | 
            +
                .new
         | 
| 43 | 
            +
                .matcher do |input, **_options|
         | 
| 44 | 
            +
                  !input[type.to_s].nil?
         | 
| 45 | 
            +
                end
         | 
| 46 | 
            +
                .caller do |input, **_options|
         | 
| 47 | 
            +
                  input[type.to_s]
         | 
| 48 | 
            +
                    .to_h { |element| [element['name'], element['emoji']] }
         | 
| 49 | 
            +
                end
         | 
| 50 | 
            +
                .identifier { |_node_:| _node_.object_id }
         | 
| 51 | 
            +
                .build
         | 
| 52 | 
            +
            end
         | 
| 53 | 
            +
             | 
| 54 | 
            +
            AnimalsJSONScraper = build_json_scraper(:animals)
         | 
| 55 | 
            +
            FruitsJSONScraper = build_json_scraper(:fruits)
         | 
| 56 | 
            +
             | 
| 57 | 
            +
            def build_xml_scraper(type)
         | 
| 58 | 
            +
              CallableTree::Node::External::Builder
         | 
| 59 | 
            +
                .new
         | 
| 60 | 
            +
                .matcher do |input, **_options|
         | 
| 61 | 
            +
                  !input.get_elements("//#{type}").empty?
         | 
| 62 | 
            +
                end
         | 
| 63 | 
            +
                .caller do |input, **_options|
         | 
| 64 | 
            +
                  input
         | 
| 65 | 
            +
                    .get_elements("//#{type}")
         | 
| 66 | 
            +
                    .first
         | 
| 67 | 
            +
                    .to_h { |element| [element['name'], element['emoji']] }
         | 
| 68 | 
            +
                end
         | 
| 69 | 
            +
                .identifier { |_node_:| _node_.object_id }
         | 
| 70 | 
            +
                .build
         | 
| 71 | 
            +
            end
         | 
| 72 | 
            +
             | 
| 73 | 
            +
            AnimalsXMLScraper = build_xml_scraper(:animals)
         | 
| 74 | 
            +
            FruitsXMLScraper = build_xml_scraper(:fruits)
         | 
| 75 | 
            +
             | 
| 76 | 
            +
            tree = CallableTree::Node::Root.new.seekable.append(
         | 
| 77 | 
            +
              JSONParser.new.seekable.append(
         | 
| 78 | 
            +
                AnimalsJSONScraper.new.verbosify,
         | 
| 79 | 
            +
                FruitsJSONScraper.new.verbosify
         | 
| 80 | 
            +
              ),
         | 
| 81 | 
            +
              XMLParser.new.seekable.append(
         | 
| 82 | 
            +
                AnimalsXMLScraper.new.verbosify,
         | 
| 83 | 
            +
                FruitsXMLScraper.new.verbosify
         | 
| 84 | 
            +
              )
         | 
| 85 | 
            +
            )
         | 
| 86 | 
            +
             | 
| 87 | 
            +
            Dir.glob("#{__dir__}/../docs/*") do |file|
         | 
| 88 | 
            +
              options = { foo: :bar }
         | 
| 89 | 
            +
              pp tree.call(file, **options)
         | 
| 90 | 
            +
              puts '---'
         | 
| 91 | 
            +
            end
         | 
| @@ -2,57 +2,57 @@ | |
| 2 2 |  | 
| 3 3 | 
             
            require 'callable_tree'
         | 
| 4 4 |  | 
| 5 | 
            -
            less_than | 
| 5 | 
            +
            def less_than(num)
         | 
| 6 6 | 
             
              # The following block call is equivalent to calling `super` in the class style.
         | 
| 7 | 
            -
              proc { |input, & | 
| 7 | 
            +
              proc { |input, &original| original.call(input) && input < num }
         | 
| 8 8 | 
             
            end
         | 
| 9 9 |  | 
| 10 10 | 
             
            LessThan5 =
         | 
| 11 11 | 
             
              CallableTree::Node::Internal::Builder
         | 
| 12 12 | 
             
              .new
         | 
| 13 | 
            -
              .matcher(&less_than.call(5))
         | 
| 13 | 
            +
              .matcher(&method(:less_than).call(5))
         | 
| 14 14 | 
             
              .build
         | 
| 15 15 |  | 
| 16 16 | 
             
            LessThan10 =
         | 
| 17 17 | 
             
              CallableTree::Node::Internal::Builder
         | 
| 18 18 | 
             
              .new
         | 
| 19 | 
            -
              .matcher(&less_than.call(10))
         | 
| 19 | 
            +
              .matcher(&method(:less_than).call(10))
         | 
| 20 20 | 
             
              .build
         | 
| 21 21 |  | 
| 22 | 
            -
            add | 
| 22 | 
            +
            def add(num)
         | 
| 23 23 | 
             
              proc { |input| input + num }
         | 
| 24 24 | 
             
            end
         | 
| 25 25 |  | 
| 26 26 | 
             
            Add1 =
         | 
| 27 27 | 
             
              CallableTree::Node::External::Builder
         | 
| 28 28 | 
             
              .new
         | 
| 29 | 
            -
              .caller(&add.call(1))
         | 
| 29 | 
            +
              .caller(&method(:add).call(1))
         | 
| 30 30 | 
             
              .build
         | 
| 31 31 |  | 
| 32 | 
            -
            subtract | 
| 32 | 
            +
            def subtract(num)
         | 
| 33 33 | 
             
              proc { |input| input - num }
         | 
| 34 34 | 
             
            end
         | 
| 35 35 |  | 
| 36 36 | 
             
            Subtract1 =
         | 
| 37 37 | 
             
              CallableTree::Node::External::Builder
         | 
| 38 38 | 
             
              .new
         | 
| 39 | 
            -
              .caller(&subtract.call(1))
         | 
| 39 | 
            +
              .caller(&method(:subtract).call(1))
         | 
| 40 40 | 
             
              .build
         | 
| 41 41 |  | 
| 42 | 
            -
            multiply | 
| 42 | 
            +
            def multiply(num)
         | 
| 43 43 | 
             
              proc { |input| input * num }
         | 
| 44 44 | 
             
            end
         | 
| 45 45 |  | 
| 46 46 | 
             
            Multiply2 =
         | 
| 47 47 | 
             
              CallableTree::Node::External::Builder
         | 
| 48 48 | 
             
              .new
         | 
| 49 | 
            -
              .caller(&multiply.call(2))
         | 
| 49 | 
            +
              .caller(&method(:multiply).call(2))
         | 
| 50 50 | 
             
              .build
         | 
| 51 51 |  | 
| 52 52 | 
             
            Multiply3 =
         | 
| 53 53 | 
             
              CallableTree::Node::External::Builder
         | 
| 54 54 | 
             
              .new
         | 
| 55 | 
            -
              .caller(&multiply.call(3))
         | 
| 55 | 
            +
              .caller(&method(:multiply).call(3))
         | 
| 56 56 | 
             
              .build
         | 
| 57 57 |  | 
| 58 58 | 
             
            tree = CallableTree::Node::Root.new.broadcastable.append(
         | 
| @@ -2,57 +2,57 @@ | |
| 2 2 |  | 
| 3 3 | 
             
            require 'callable_tree'
         | 
| 4 4 |  | 
| 5 | 
            -
            less_than | 
| 5 | 
            +
            def less_than(num)
         | 
| 6 6 | 
             
              # The following block call is equivalent to calling `super` in the class style.
         | 
| 7 | 
            -
              proc { |input, & | 
| 7 | 
            +
              proc { |input, &original| original.call(input) && input < num }
         | 
| 8 8 | 
             
            end
         | 
| 9 9 |  | 
| 10 10 | 
             
            LessThan5 =
         | 
| 11 11 | 
             
              CallableTree::Node::Internal::Builder
         | 
| 12 12 | 
             
              .new
         | 
| 13 | 
            -
              .matcher(&less_than.call(5))
         | 
| 13 | 
            +
              .matcher(&method(:less_than).call(5))
         | 
| 14 14 | 
             
              .build
         | 
| 15 15 |  | 
| 16 16 | 
             
            LessThan10 =
         | 
| 17 17 | 
             
              CallableTree::Node::Internal::Builder
         | 
| 18 18 | 
             
              .new
         | 
| 19 | 
            -
              .matcher(&less_than.call(10))
         | 
| 19 | 
            +
              .matcher(&method(:less_than).call(10))
         | 
| 20 20 | 
             
              .build
         | 
| 21 21 |  | 
| 22 | 
            -
            add | 
| 22 | 
            +
            def add(num)
         | 
| 23 23 | 
             
              proc { |input| input + num }
         | 
| 24 24 | 
             
            end
         | 
| 25 25 |  | 
| 26 26 | 
             
            Add1 =
         | 
| 27 27 | 
             
              CallableTree::Node::External::Builder
         | 
| 28 28 | 
             
              .new
         | 
| 29 | 
            -
              .caller(&add.call(1))
         | 
| 29 | 
            +
              .caller(&method(:add).call(1))
         | 
| 30 30 | 
             
              .build
         | 
| 31 31 |  | 
| 32 | 
            -
            subtract | 
| 32 | 
            +
            def subtract(num)
         | 
| 33 33 | 
             
              proc { |input| input - num }
         | 
| 34 34 | 
             
            end
         | 
| 35 35 |  | 
| 36 36 | 
             
            Subtract1 =
         | 
| 37 37 | 
             
              CallableTree::Node::External::Builder
         | 
| 38 38 | 
             
              .new
         | 
| 39 | 
            -
              .caller(&subtract.call(1))
         | 
| 39 | 
            +
              .caller(&method(:subtract).call(1))
         | 
| 40 40 | 
             
              .build
         | 
| 41 41 |  | 
| 42 | 
            -
            multiply | 
| 42 | 
            +
            def multiply(num)
         | 
| 43 43 | 
             
              proc { |input| input * num }
         | 
| 44 44 | 
             
            end
         | 
| 45 45 |  | 
| 46 46 | 
             
            Multiply2 =
         | 
| 47 47 | 
             
              CallableTree::Node::External::Builder
         | 
| 48 48 | 
             
              .new
         | 
| 49 | 
            -
              .caller(&multiply.call(2))
         | 
| 49 | 
            +
              .caller(&method(:multiply).call(2))
         | 
| 50 50 | 
             
              .build
         | 
| 51 51 |  | 
| 52 52 | 
             
            Multiply3 =
         | 
| 53 53 | 
             
              CallableTree::Node::External::Builder
         | 
| 54 54 | 
             
              .new
         | 
| 55 | 
            -
              .caller(&multiply.call(3))
         | 
| 55 | 
            +
              .caller(&method(:multiply).call(3))
         | 
| 56 56 | 
             
              .build
         | 
| 57 57 |  | 
| 58 58 | 
             
            tree = CallableTree::Node::Root.new.composable.append(
         | 
| @@ -10,16 +10,14 @@ JSONParser = | |
| 10 10 | 
             
              .matcher do |input, **_options|
         | 
| 11 11 | 
             
                File.extname(input) == '.json'
         | 
| 12 12 | 
             
              end
         | 
| 13 | 
            -
              .caller do |input, **options, & | 
| 13 | 
            +
              .caller do |input, **options, &original|
         | 
| 14 14 | 
             
                File.open(input) do |file|
         | 
| 15 | 
            -
                  json =  | 
| 15 | 
            +
                  json = JSON.load(file)
         | 
| 16 16 | 
             
                  # The following block call is equivalent to calling `super` in the class style.
         | 
| 17 | 
            -
                   | 
| 17 | 
            +
                  original.call(json, **options)
         | 
| 18 18 | 
             
                end
         | 
| 19 19 | 
             
              end
         | 
| 20 | 
            -
              .terminator  | 
| 21 | 
            -
                true
         | 
| 22 | 
            -
              end
         | 
| 20 | 
            +
              .terminator { true }
         | 
| 23 21 | 
             
              .build
         | 
| 24 22 |  | 
| 25 23 | 
             
            XMLParser =
         | 
| @@ -28,27 +26,24 @@ XMLParser = | |
| 28 26 | 
             
              .matcher do |input, **_options|
         | 
| 29 27 | 
             
                File.extname(input) == '.xml'
         | 
| 30 28 | 
             
              end
         | 
| 31 | 
            -
              .caller do |input, **options, & | 
| 29 | 
            +
              .caller do |input, **options, &original|
         | 
| 32 30 | 
             
                File.open(input) do |file|
         | 
| 33 31 | 
             
                  # The following block call is equivalent to calling `super` in the class style.
         | 
| 34 | 
            -
                   | 
| 32 | 
            +
                  original.call(REXML::Document.new(file), **options)
         | 
| 35 33 | 
             
                end
         | 
| 36 34 | 
             
              end
         | 
| 37 | 
            -
              .terminator  | 
| 38 | 
            -
                true
         | 
| 39 | 
            -
              end
         | 
| 35 | 
            +
              .terminator { true }
         | 
| 40 36 | 
             
              .build
         | 
| 41 37 |  | 
| 42 38 | 
             
            def build_json_scraper(type)
         | 
| 43 39 | 
             
              CallableTree::Node::External::Builder
         | 
| 44 40 | 
             
                .new
         | 
| 45 41 | 
             
                .matcher do |input, **_options|
         | 
| 46 | 
            -
                   | 
| 42 | 
            +
                  !input[type.to_s].nil?
         | 
| 47 43 | 
             
                end
         | 
| 48 44 | 
             
                .caller do |input, **_options|
         | 
| 49 45 | 
             
                  input[type.to_s]
         | 
| 50 | 
            -
                    . | 
| 51 | 
            -
                    .to_h
         | 
| 46 | 
            +
                    .to_h { |element| [element['name'], element['emoji']] }
         | 
| 52 47 | 
             
                end
         | 
| 53 48 | 
             
                .build
         | 
| 54 49 | 
             
            end
         | 
| @@ -66,8 +61,7 @@ def build_xml_scraper(type) | |
| 66 61 | 
             
                  input
         | 
| 67 62 | 
             
                    .get_elements("//#{type}")
         | 
| 68 63 | 
             
                    .first
         | 
| 69 | 
            -
                    . | 
| 70 | 
            -
                    .to_h
         | 
| 64 | 
            +
                    .to_h { |element| [element['name'], element['emoji']] }
         | 
| 71 65 | 
             
                end
         | 
| 72 66 | 
             
                .build
         | 
| 73 67 | 
             
            end
         | 
    
        data/examples/builder/logging.rb
    CHANGED
    
    | @@ -10,15 +10,14 @@ JSONParser = | |
| 10 10 | 
             
              .matcher do |input, **_options|
         | 
| 11 11 | 
             
                File.extname(input) == '.json'
         | 
| 12 12 | 
             
              end
         | 
| 13 | 
            -
              .caller do |input, **options, & | 
| 13 | 
            +
              .caller do |input, **options, &original|
         | 
| 14 14 | 
             
                File.open(input) do |file|
         | 
| 15 | 
            -
                  json =  | 
| 15 | 
            +
                  json = JSON.load(file)
         | 
| 16 16 | 
             
                  # The following block call is equivalent to calling `super` in the class style.
         | 
| 17 | 
            -
                   | 
| 17 | 
            +
                  original.call(json, **options)
         | 
| 18 18 | 
             
                end
         | 
| 19 19 | 
             
              end
         | 
| 20 20 | 
             
              .terminator { true }
         | 
| 21 | 
            -
              # .identifier { |_node_:| :as_you_like } # optional
         | 
| 22 21 | 
             
              .hookable
         | 
| 23 22 | 
             
              .build
         | 
| 24 23 |  | 
| @@ -28,14 +27,13 @@ XMLParser = | |
| 28 27 | 
             
              .matcher do |input, **_options|
         | 
| 29 28 | 
             
                File.extname(input) == '.xml'
         | 
| 30 29 | 
             
              end
         | 
| 31 | 
            -
              .caller do |input, **options, & | 
| 30 | 
            +
              .caller do |input, **options, &original|
         | 
| 32 31 | 
             
                File.open(input) do |file|
         | 
| 33 32 | 
             
                  # The following block call is equivalent to calling `super` in the class style.
         | 
| 34 | 
            -
                   | 
| 33 | 
            +
                  original.call(REXML::Document.new(file), **options)
         | 
| 35 34 | 
             
                end
         | 
| 36 35 | 
             
              end
         | 
| 37 36 | 
             
              .terminator { true }
         | 
| 38 | 
            -
              # .identifier { |_node_:| :as_you_like } # optional
         | 
| 39 37 | 
             
              .hookable
         | 
| 40 38 | 
             
              .build
         | 
| 41 39 |  | 
| @@ -43,14 +41,12 @@ def build_json_scraper(type) | |
| 43 41 | 
             
              CallableTree::Node::External::Builder
         | 
| 44 42 | 
             
                .new
         | 
| 45 43 | 
             
                .matcher do |input, **_options|
         | 
| 46 | 
            -
                   | 
| 44 | 
            +
                  !input[type.to_s].nil?
         | 
| 47 45 | 
             
                end
         | 
| 48 46 | 
             
                .caller do |input, **_options|
         | 
| 49 47 | 
             
                  input[type.to_s]
         | 
| 50 | 
            -
                    . | 
| 51 | 
            -
                    .to_h
         | 
| 48 | 
            +
                    .to_h { |element| [element['name'], element['emoji']] }
         | 
| 52 49 | 
             
                end
         | 
| 53 | 
            -
                # .identifier { |_node_:| :as_you_like } # optional
         | 
| 54 50 | 
             
                .hookable
         | 
| 55 51 | 
             
                .build
         | 
| 56 52 | 
             
            end
         | 
| @@ -68,10 +64,8 @@ def build_xml_scraper(type) | |
| 68 64 | 
             
                  input
         | 
| 69 65 | 
             
                    .get_elements("//#{type}")
         | 
| 70 66 | 
             
                    .first
         | 
| 71 | 
            -
                    . | 
| 72 | 
            -
                    .to_h
         | 
| 67 | 
            +
                    .to_h { |element| [element['name'], element['emoji']] }
         | 
| 73 68 | 
             
                end
         | 
| 74 | 
            -
                # .identifier { |_node_:| :as_you_like } # optional
         | 
| 75 69 | 
             
                .hookable
         | 
| 76 70 | 
             
                .build
         | 
| 77 71 | 
             
            end
         | 
| @@ -93,19 +87,19 @@ module Logging | |
| 93 87 | 
             
                  matched
         | 
| 94 88 | 
             
                end
         | 
| 95 89 |  | 
| 96 | 
            -
                 | 
| 97 | 
            -
             | 
| 98 | 
            -
             | 
| 99 | 
            -
             | 
| 100 | 
            -
             | 
| 101 | 
            -
             | 
| 102 | 
            -
                     | 
| 103 | 
            -
             | 
| 104 | 
            -
             | 
| 105 | 
            -
             | 
| 106 | 
            -
             | 
| 107 | 
            -
                     | 
| 108 | 
            -
             | 
| 90 | 
            +
                return unless node.external?
         | 
| 91 | 
            +
             | 
| 92 | 
            +
                node
         | 
| 93 | 
            +
                  .before_caller! do |input, *, _node_:, **|
         | 
| 94 | 
            +
                    input_prefix = INPUT_LABEL.rjust((_node_.depth * INDENT_SIZE) + INPUT_LABEL.length, BLANK)
         | 
| 95 | 
            +
                    puts "#{input_prefix} #{input}"
         | 
| 96 | 
            +
                    input
         | 
| 97 | 
            +
                  end
         | 
| 98 | 
            +
                  .after_caller! do |output, _node_:, **|
         | 
| 99 | 
            +
                    output_prefix = OUTPUT_LABEL.rjust((_node_.depth * INDENT_SIZE) + OUTPUT_LABEL.length, BLANK)
         | 
| 100 | 
            +
                    puts "#{output_prefix} #{output}"
         | 
| 101 | 
            +
                    output
         | 
| 102 | 
            +
                  end
         | 
| 109 103 | 
             
              end
         | 
| 110 104 | 
             
            end
         | 
| 111 105 |  | 
| @@ -38,8 +38,7 @@ module Node | |
| 38 38 |  | 
| 39 39 | 
             
                  def call(input, **_options)
         | 
| 40 40 | 
             
                    input[@type.to_s]
         | 
| 41 | 
            -
                      . | 
| 42 | 
            -
                      .to_h
         | 
| 41 | 
            +
                      .to_h { |element| [element['name'], element['emoji']] }
         | 
| 43 42 | 
             
                  end
         | 
| 44 43 | 
             
                end
         | 
| 45 44 | 
             
              end
         | 
| @@ -78,8 +77,7 @@ module Node | |
| 78 77 | 
             
                    input
         | 
| 79 78 | 
             
                      .get_elements("//#{@type}")
         | 
| 80 79 | 
             
                      .first
         | 
| 81 | 
            -
                      . | 
| 82 | 
            -
                      .to_h
         | 
| 80 | 
            +
                      .to_h { |element| [element['name'], element['emoji']] }
         | 
| 83 81 | 
             
                  end
         | 
| 84 82 | 
             
                end
         | 
| 85 83 | 
             
              end
         | 
    
        data/examples/class/identity.rb
    CHANGED
    
    | @@ -55,8 +55,7 @@ module Node | |
| 55 55 |  | 
| 56 56 | 
             
                  def call(input, **_options)
         | 
| 57 57 | 
             
                    input[@type.to_s]
         | 
| 58 | 
            -
                      . | 
| 59 | 
            -
                      .to_h
         | 
| 58 | 
            +
                      .to_h { |element| [element['name'], element['emoji']] }
         | 
| 60 59 | 
             
                  end
         | 
| 61 60 | 
             
                end
         | 
| 62 61 | 
             
              end
         | 
| @@ -99,8 +98,7 @@ module Node | |
| 99 98 | 
             
                    input
         | 
| 100 99 | 
             
                      .get_elements("//#{@type}")
         | 
| 101 100 | 
             
                      .first
         | 
| 102 | 
            -
                      . | 
| 103 | 
            -
                      .to_h
         | 
| 101 | 
            +
                      .to_h { |element| [element['name'], element['emoji']] }
         | 
| 104 102 | 
             
                  end
         | 
| 105 103 | 
             
                end
         | 
| 106 104 | 
             
              end
         | 
| @@ -38,8 +38,7 @@ module Node | |
| 38 38 |  | 
| 39 39 | 
             
                  def call(input, **_options)
         | 
| 40 40 | 
             
                    input[@type.to_s]
         | 
| 41 | 
            -
                      . | 
| 42 | 
            -
                      .to_h
         | 
| 41 | 
            +
                      .to_h { |element| [element['name'], element['emoji']] }
         | 
| 43 42 | 
             
                  end
         | 
| 44 43 | 
             
                end
         | 
| 45 44 | 
             
              end
         | 
| @@ -78,8 +77,7 @@ module Node | |
| 78 77 | 
             
                    input
         | 
| 79 78 | 
             
                      .get_elements("//#{@type}")
         | 
| 80 79 | 
             
                      .first
         | 
| 81 | 
            -
                      . | 
| 82 | 
            -
                      .to_h
         | 
| 80 | 
            +
                      .to_h { |element| [element['name'], element['emoji']] }
         | 
| 83 81 | 
             
                  end
         | 
| 84 82 | 
             
                end
         | 
| 85 83 | 
             
              end
         | 
    
        data/examples/class/logging.rb
    CHANGED
    
    | @@ -58,8 +58,7 @@ module Node | |
| 58 58 |  | 
| 59 59 | 
             
                  def call(input, **_options)
         | 
| 60 60 | 
             
                    input[@type.to_s]
         | 
| 61 | 
            -
                      . | 
| 62 | 
            -
                      .to_h
         | 
| 61 | 
            +
                      .to_h { |element| [element['name'], element['emoji']] }
         | 
| 63 62 | 
             
                  end
         | 
| 64 63 | 
             
                end
         | 
| 65 64 | 
             
              end
         | 
| @@ -105,8 +104,7 @@ module Node | |
| 105 104 | 
             
                    input
         | 
| 106 105 | 
             
                      .get_elements("//#{@type}")
         | 
| 107 106 | 
             
                      .first
         | 
| 108 | 
            -
                      . | 
| 109 | 
            -
                      .to_h
         | 
| 107 | 
            +
                      .to_h { |element| [element['name'], element['emoji']] }
         | 
| 110 108 | 
             
                  end
         | 
| 111 109 | 
             
                end
         | 
| 112 110 | 
             
              end
         | 
| @@ -126,19 +124,19 @@ module Logging | |
| 126 124 | 
             
                  matched
         | 
| 127 125 | 
             
                end
         | 
| 128 126 |  | 
| 129 | 
            -
                 | 
| 130 | 
            -
             | 
| 131 | 
            -
             | 
| 132 | 
            -
             | 
| 133 | 
            -
             | 
| 134 | 
            -
             | 
| 135 | 
            -
                     | 
| 136 | 
            -
             | 
| 137 | 
            -
             | 
| 138 | 
            -
             | 
| 139 | 
            -
             | 
| 140 | 
            -
                     | 
| 141 | 
            -
             | 
| 127 | 
            +
                return unless node.external?
         | 
| 128 | 
            +
             | 
| 129 | 
            +
                node
         | 
| 130 | 
            +
                  .before_caller! do |input, *, _node_:, **|
         | 
| 131 | 
            +
                    input_prefix = INPUT_LABEL.rjust((_node_.depth * INDENT_SIZE) + INPUT_LABEL.length, BLANK)
         | 
| 132 | 
            +
                    puts "#{input_prefix} #{input}"
         | 
| 133 | 
            +
                    input
         | 
| 134 | 
            +
                  end
         | 
| 135 | 
            +
                  .after_caller! do |output, _node_:, **|
         | 
| 136 | 
            +
                    output_prefix = OUTPUT_LABEL.rjust((_node_.depth * INDENT_SIZE) + OUTPUT_LABEL.length, BLANK)
         | 
| 137 | 
            +
                    puts "#{output_prefix} #{output}"
         | 
| 138 | 
            +
                    output
         | 
| 139 | 
            +
                  end
         | 
| 142 140 | 
             
              end
         | 
| 143 141 | 
             
            end
         | 
| 144 142 |  | 
| @@ -6,10 +6,10 @@ module CallableTree | |
| 6 6 | 
             
                  include Node
         | 
| 7 7 |  | 
| 8 8 | 
             
                  def self.included(mod)
         | 
| 9 | 
            -
                     | 
| 10 | 
            -
             | 
| 11 | 
            -
             | 
| 12 | 
            -
             | 
| 9 | 
            +
                    return unless mod.include?(Internal)
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                    raise ::CallableTree::Error,
         | 
| 12 | 
            +
                          "#{mod} cannot include #{self} together with #{Internal}"
         | 
| 13 13 | 
             
                  end
         | 
| 14 14 |  | 
| 15 15 | 
             
                  def self.proxify(callable)
         | 
| @@ -7,9 +7,19 @@ module CallableTree | |
| 7 7 | 
             
                    class Broadcast
         | 
| 8 8 | 
             
                      include Strategy
         | 
| 9 9 |  | 
| 10 | 
            +
                      def initialize(matchable: true, terminable: false)
         | 
| 11 | 
            +
                        self.matchable = matchable
         | 
| 12 | 
            +
                        self.terminable = terminable
         | 
| 13 | 
            +
                      end
         | 
| 14 | 
            +
             | 
| 10 15 | 
             
                      def call(nodes, *inputs, **options)
         | 
| 11 | 
            -
                        nodes. | 
| 12 | 
            -
                          node.call(*inputs, **options) if  | 
| 16 | 
            +
                        nodes.each_with_object([]) do |node, outputs|
         | 
| 17 | 
            +
                          output = (node.call(*inputs, **options) if matcher.call(node, *inputs, **options))
         | 
| 18 | 
            +
                          outputs << output
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                          break outputs if terminator.call(node, output, *inputs, **options)
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                          outputs
         | 
| 13 23 | 
             
                        end
         | 
| 14 24 | 
             
                      end
         | 
| 15 25 | 
             
                    end
         | 
| @@ -7,12 +7,19 @@ module CallableTree | |
| 7 7 | 
             
                    class Compose
         | 
| 8 8 | 
             
                      include Strategy
         | 
| 9 9 |  | 
| 10 | 
            +
                      def initialize(matchable: true, terminable: false)
         | 
| 11 | 
            +
                        self.matchable = matchable
         | 
| 12 | 
            +
                        self.terminable = terminable
         | 
| 13 | 
            +
                      end
         | 
| 14 | 
            +
             | 
| 10 15 | 
             
                      def call(nodes, *inputs, **options)
         | 
| 11 16 | 
             
                        head, *tail = inputs
         | 
| 12 17 | 
             
                        nodes.reduce(head) do |input, node|
         | 
| 13 | 
            -
                           | 
| 14 | 
            -
             | 
| 15 | 
            -
                             | 
| 18 | 
            +
                          if matcher.call(node, input, *tail, **options)
         | 
| 19 | 
            +
                            output = node.call(input, *tail, **options)
         | 
| 20 | 
            +
                            break output if terminator.call(node, output, input, *tail, **options)
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                            output
         | 
| 16 23 | 
             
                          else
         | 
| 17 24 | 
             
                            input
         | 
| 18 25 | 
             
                          end
         | 
| @@ -7,13 +7,18 @@ module CallableTree | |
| 7 7 | 
             
                    class Seek
         | 
| 8 8 | 
             
                      include Strategy
         | 
| 9 9 |  | 
| 10 | 
            +
                      def initialize(matchable: true, terminable: true)
         | 
| 11 | 
            +
                        self.matchable = matchable
         | 
| 12 | 
            +
                        self.terminable = terminable
         | 
| 13 | 
            +
                      end
         | 
| 14 | 
            +
             | 
| 10 15 | 
             
                      def call(nodes, *inputs, **options)
         | 
| 11 16 | 
             
                        nodes
         | 
| 12 17 | 
             
                          .lazy
         | 
| 13 | 
            -
                          .select { |node|  | 
| 18 | 
            +
                          .select { |node| matcher.call(node, *inputs, **options) }
         | 
| 14 19 | 
             
                          .map do |node|
         | 
| 15 20 | 
             
                            output = node.call(*inputs, **options)
         | 
| 16 | 
            -
                            terminated =  | 
| 21 | 
            +
                            terminated = terminator.call(node, output, *inputs, **options)
         | 
| 17 22 | 
             
                            [output, terminated]
         | 
| 18 23 | 
             
                          end
         | 
| 19 24 | 
             
                          .select { |_output, terminated| terminated }
         |