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 }
|