callable_tree 0.3.2 → 0.3.5
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/workflows/build.yml +1 -1
- data/.ruby-version +1 -1
- data/CHANGELOG.md +26 -0
- data/Gemfile.lock +14 -15
- data/README.md +32 -32
- data/examples/builder/hooks-call.rb +38 -0
- data/examples/builder/internal-broadcastable.rb +72 -0
- data/examples/builder/internal-composable.rb +72 -0
- data/examples/builder/internal-seekable.rb +97 -0
- data/examples/{internal-broadcast.rb → internal-broadcastable.rb} +6 -6
- data/examples/{internal-compose.rb → internal-composable.rb} +6 -6
- data/examples/{internal-seek.rb → internal-seekable.rb} +3 -3
- data/lib/callable_tree/node/builder.rb +82 -0
- data/lib/callable_tree/node/external/builder.rb +23 -0
- data/lib/callable_tree/node/internal/builder.rb +21 -0
- data/lib/callable_tree/node/internal.rb +37 -10
- data/lib/callable_tree/version.rb +1 -1
- data/lib/callable_tree.rb +3 -0
- metadata +14 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 83716fbdef2881db33e8f046f056a17d8a8866423951493902088bf1af53218f
|
4
|
+
data.tar.gz: 8906217b71482e1717798329d172640a50f7cc73613a2187beba0702bf8b8d74
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5e5ece858eb3347c41ea5f573e37c972d1a127d9fa234cd2512b18ef9e882b33d0da900b46c8f8e539fcee36fccb6643d21bb0945169019e7734232907c412c1
|
7
|
+
data.tar.gz: ce58af4b926c9201f4133f02da848dcfff7962f9fa08588c1d4b4b61765b9c5ffaf03f2cfb4367da7d14a80bc1dcd55ea4b53de39d4075be25ef6e2abaf9ae7e
|
data/.github/workflows/build.yml
CHANGED
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
3.1.
|
1
|
+
3.1.1
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,31 @@
|
|
1
1
|
## [Unreleased]
|
2
2
|
|
3
|
+
## [0.3.5] - 2022-03-20
|
4
|
+
|
5
|
+
- Add `CallableTree::Node::Internal#seekable?` as an alias for `CallableTree::Node::Internal#seek?`.
|
6
|
+
- Add `CallableTree::Node::Internal#seekable` as an alias for `CallableTree::Node::Internal#seek`.
|
7
|
+
- Add `CallableTree::Node::Internal#seekable!` as an alias for `CallableTree::Node::Internal#seek!`.
|
8
|
+
- Add `CallableTree::Node::Internal#broadcastable?` as an alias for `CallableTree::Node::Internal#broadcast?`.
|
9
|
+
- Add `CallableTree::Node::Internal#broadcastable` as an alias for `CallableTree::Node::Internal#broadcast`.
|
10
|
+
- Add `CallableTree::Node::Internal#broadcastable!` as an alias for `CallableTree::Node::Internal#broadcast!`.
|
11
|
+
- Add `CallableTree::Node::Internal#composable?` as an alias for `CallableTree::Node::Internal#compose?`.
|
12
|
+
- Add `CallableTree::Node::Internal#composable` as an alias for `CallableTree::Node::Internal#compose`.
|
13
|
+
- Add `CallableTree::Node::Internal#composable!` as an alias for `CallableTree::Node::Internal#compose!`.
|
14
|
+
- (Experimental) Add `CallableTree::Node::Internal::Builder#terminator` to use instead of `CallableTree::Node::Internal::Builder#terminater`.
|
15
|
+
See `examples/builder/*.rb` for details.
|
16
|
+
|
17
|
+
## [0.3.4] - 2022-03-13
|
18
|
+
|
19
|
+
- (Experimental) Add `CallableTree::Node::Internal::Builder`.
|
20
|
+
See `examples/builder/*.rb` for details.
|
21
|
+
- (Experimental) Add `CallableTree::Node::External::Builder`.
|
22
|
+
See `examples/builder/*.rb` for details.
|
23
|
+
|
24
|
+
## [0.3.3] - 2022-02-19
|
25
|
+
|
26
|
+
- Add `recursive` option to `CallableTree::Node::Internal#reject` and `CallableTree::Node::Internal#reject!`.
|
27
|
+
- Add `CallableTree::Node::Internal#find` to return the first node evaluated as `true` by block.
|
28
|
+
|
3
29
|
## [0.3.2] - 2022-02-05
|
4
30
|
|
5
31
|
- Change `CallableTree::Node::Hooks::Call#before_call` to return a new instance.
|
data/Gemfile.lock
CHANGED
@@ -1,30 +1,29 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
callable_tree (0.3.
|
4
|
+
callable_tree (0.3.5)
|
5
5
|
|
6
6
|
GEM
|
7
7
|
remote: https://rubygems.org/
|
8
8
|
specs:
|
9
9
|
diff-lcs (1.5.0)
|
10
10
|
rake (13.0.6)
|
11
|
-
rspec (3.
|
12
|
-
rspec-core (~> 3.
|
13
|
-
rspec-expectations (~> 3.
|
14
|
-
rspec-mocks (~> 3.
|
15
|
-
rspec-core (3.
|
16
|
-
rspec-support (~> 3.
|
17
|
-
rspec-expectations (3.
|
11
|
+
rspec (3.11.0)
|
12
|
+
rspec-core (~> 3.11.0)
|
13
|
+
rspec-expectations (~> 3.11.0)
|
14
|
+
rspec-mocks (~> 3.11.0)
|
15
|
+
rspec-core (3.11.0)
|
16
|
+
rspec-support (~> 3.11.0)
|
17
|
+
rspec-expectations (3.11.0)
|
18
18
|
diff-lcs (>= 1.2.0, < 2.0)
|
19
|
-
rspec-support (~> 3.
|
20
|
-
rspec-mocks (3.
|
19
|
+
rspec-support (~> 3.11.0)
|
20
|
+
rspec-mocks (3.11.0)
|
21
21
|
diff-lcs (>= 1.2.0, < 2.0)
|
22
|
-
rspec-support (~> 3.
|
23
|
-
rspec-support (3.
|
22
|
+
rspec-support (~> 3.11.0)
|
23
|
+
rspec-support (3.11.0)
|
24
24
|
|
25
25
|
PLATFORMS
|
26
|
-
x86_64-darwin-
|
27
|
-
x86_64-darwin-20
|
26
|
+
x86_64-darwin-21
|
28
27
|
|
29
28
|
DEPENDENCIES
|
30
29
|
callable_tree!
|
@@ -32,4 +31,4 @@ DEPENDENCIES
|
|
32
31
|
rspec (~> 3.0)
|
33
32
|
|
34
33
|
BUNDLED WITH
|
35
|
-
2.3.
|
34
|
+
2.3.7
|
data/README.md
CHANGED
@@ -32,11 +32,11 @@ Builds a tree by linking instances of the nodes. The `call` method of the node w
|
|
32
32
|
|
33
33
|
### Basic
|
34
34
|
|
35
|
-
#### `CallableTree::Node::Internal#
|
35
|
+
#### `CallableTree::Node::Internal#seekable` (default)
|
36
36
|
|
37
37
|
This strategy does not call the next sibling node if the `call` method of the current node returns a value other than `nil`. This behavior is changeable by overriding the `terminate?` method.
|
38
38
|
|
39
|
-
`examples/internal-
|
39
|
+
`examples/internal-seekable.rb`:
|
40
40
|
```ruby
|
41
41
|
module Node
|
42
42
|
module JSON
|
@@ -129,17 +129,17 @@ module Node
|
|
129
129
|
end
|
130
130
|
end
|
131
131
|
|
132
|
-
# The `
|
133
|
-
tree = CallableTree::Node::Root.new.append(
|
134
|
-
Node::JSON::Parser.new.append(
|
132
|
+
# The `seekable` method call can be omitted since it is the default strategy.
|
133
|
+
tree = CallableTree::Node::Root.new.seekable.append(
|
134
|
+
Node::JSON::Parser.new.seekable.append(
|
135
135
|
Node::JSON::Scraper.new(type: :animals),
|
136
136
|
Node::JSON::Scraper.new(type: :fruits)
|
137
|
-
)
|
138
|
-
Node::XML::Parser.new.append(
|
137
|
+
),
|
138
|
+
Node::XML::Parser.new.seekable.append(
|
139
139
|
Node::XML::Scraper.new(type: :animals),
|
140
140
|
Node::XML::Scraper.new(type: :fruits)
|
141
|
-
)
|
142
|
-
)
|
141
|
+
)
|
142
|
+
)
|
143
143
|
|
144
144
|
Dir.glob("#{__dir__}/docs/*") do |file|
|
145
145
|
options = { foo: :bar }
|
@@ -148,9 +148,9 @@ Dir.glob("#{__dir__}/docs/*") do |file|
|
|
148
148
|
end
|
149
149
|
```
|
150
150
|
|
151
|
-
Run `examples/internal-
|
151
|
+
Run `examples/internal-seekable.rb`:
|
152
152
|
```sh
|
153
|
-
% ruby examples/internal-
|
153
|
+
% ruby examples/internal-seekable.rb
|
154
154
|
{"Dog"=>"🐶", "Cat"=>"🐱"}
|
155
155
|
---
|
156
156
|
{"Dog"=>"🐶", "Cat"=>"🐱"}
|
@@ -161,11 +161,11 @@ Run `examples/internal-seek.rb`:
|
|
161
161
|
---
|
162
162
|
```
|
163
163
|
|
164
|
-
#### `CallableTree::Node::Internal#
|
164
|
+
#### `CallableTree::Node::Internal#broadcastable`
|
165
165
|
|
166
166
|
This strategy calls all child nodes of the internal node and ignores their `terminate?` methods, and then outputs their results as array.
|
167
167
|
|
168
|
-
`examples/internal-
|
168
|
+
`examples/internal-broadcastable.rb`:
|
169
169
|
```ruby
|
170
170
|
module Node
|
171
171
|
class LessThan
|
@@ -181,16 +181,16 @@ module Node
|
|
181
181
|
end
|
182
182
|
end
|
183
183
|
|
184
|
-
tree = CallableTree::Node::Root.new.append(
|
185
|
-
Node::LessThan.new(5).append(
|
184
|
+
tree = CallableTree::Node::Root.new.broadcastable.append(
|
185
|
+
Node::LessThan.new(5).broadcastable.append(
|
186
186
|
->(input) { input * 2 }, # anonymous external node
|
187
187
|
->(input) { input + 1 } # anonymous external node
|
188
|
-
)
|
189
|
-
Node::LessThan.new(10).append(
|
188
|
+
),
|
189
|
+
Node::LessThan.new(10).broadcastable.append(
|
190
190
|
->(input) { input * 3 }, # anonymous external node
|
191
191
|
->(input) { input - 1 } # anonymous external node
|
192
|
-
)
|
193
|
-
)
|
192
|
+
)
|
193
|
+
)
|
194
194
|
|
195
195
|
(0..10).each do |input|
|
196
196
|
output = tree.call(input)
|
@@ -199,9 +199,9 @@ end
|
|
199
199
|
|
200
200
|
```
|
201
201
|
|
202
|
-
Run `examples/internal-
|
202
|
+
Run `examples/internal-broadcastable.rb`:
|
203
203
|
```sh
|
204
|
-
% ruby examples/internal-
|
204
|
+
% ruby examples/internal-broadcastable.rb
|
205
205
|
0 -> [[0, 1], [0, -1]]
|
206
206
|
1 -> [[2, 2], [3, 0]]
|
207
207
|
2 -> [[4, 3], [6, 1]]
|
@@ -215,11 +215,11 @@ Run `examples/internal-broadcast.rb`:
|
|
215
215
|
10 -> [nil, nil]
|
216
216
|
```
|
217
217
|
|
218
|
-
#### `CallableTree::Node::Internal#
|
218
|
+
#### `CallableTree::Node::Internal#composable`
|
219
219
|
|
220
220
|
This strategy calls all child nodes of the internal node in order to input the output of the previous node to the next node and ignores their `terminate?` methods, and then outputs a single result.
|
221
221
|
|
222
|
-
`examples/internal-
|
222
|
+
`examples/internal-composable.rb`:
|
223
223
|
```ruby
|
224
224
|
module Node
|
225
225
|
class LessThan
|
@@ -235,16 +235,16 @@ module Node
|
|
235
235
|
end
|
236
236
|
end
|
237
237
|
|
238
|
-
tree = CallableTree::Node::Root.new.append(
|
239
|
-
Node::LessThan.new(5).append(
|
238
|
+
tree = CallableTree::Node::Root.new.composable.append(
|
239
|
+
Node::LessThan.new(5).composable.append(
|
240
240
|
proc { |input| input * 2 }, # anonymous external node
|
241
241
|
proc { |input| input + 1 } # anonymous external node
|
242
|
-
)
|
243
|
-
Node::LessThan.new(10).append(
|
242
|
+
),
|
243
|
+
Node::LessThan.new(10).composable.append(
|
244
244
|
proc { |input| input * 3 }, # anonymous external node
|
245
245
|
proc { |input| input - 1 } # anonymous external node
|
246
|
-
)
|
247
|
-
)
|
246
|
+
)
|
247
|
+
)
|
248
248
|
|
249
249
|
(0..10).each do |input|
|
250
250
|
output = tree.call(input)
|
@@ -253,9 +253,9 @@ end
|
|
253
253
|
|
254
254
|
```
|
255
255
|
|
256
|
-
Run `examples/internal-
|
256
|
+
Run `examples/internal-composable.rb`:
|
257
257
|
```sh
|
258
|
-
% ruby examples/internal-
|
258
|
+
% ruby examples/internal-composable.rb
|
259
259
|
0 -> 2
|
260
260
|
1 -> 8
|
261
261
|
2 -> 14
|
@@ -621,7 +621,7 @@ result: 16
|
|
621
621
|
|
622
622
|
## Contributing
|
623
623
|
|
624
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/jsmmr/
|
624
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/jsmmr/ruby_callable_tree.
|
625
625
|
|
626
626
|
## License
|
627
627
|
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'callable_tree'
|
4
|
+
|
5
|
+
Root =
|
6
|
+
CallableTree::Node::Internal::Builder
|
7
|
+
.new
|
8
|
+
.hookable
|
9
|
+
.build
|
10
|
+
|
11
|
+
Root
|
12
|
+
.new
|
13
|
+
.before_call do |input, **_options|
|
14
|
+
puts "before_call input: #{input}"
|
15
|
+
input + 1
|
16
|
+
end
|
17
|
+
.append(
|
18
|
+
# anonymous external node
|
19
|
+
lambda do |input, **_options|
|
20
|
+
puts "external input: #{input}"
|
21
|
+
input * 2
|
22
|
+
end
|
23
|
+
)
|
24
|
+
.around_call do |input, **_options, &block|
|
25
|
+
puts "around_call input: #{input}"
|
26
|
+
output = block.call
|
27
|
+
puts "around_call output: #{output}"
|
28
|
+
output * input
|
29
|
+
end
|
30
|
+
.after_call do |output, **_options|
|
31
|
+
puts "after_call output: #{output}"
|
32
|
+
output * 2
|
33
|
+
end
|
34
|
+
.tap do |tree|
|
35
|
+
options = { foo: :bar }
|
36
|
+
output = tree.call(1, **options)
|
37
|
+
puts "result: #{output}"
|
38
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'callable_tree'
|
4
|
+
|
5
|
+
less_than = proc do |num|
|
6
|
+
# The following block call is equivalent to calling `super` in the class style.
|
7
|
+
proc { |input, &block| block.call(input) && input < num }
|
8
|
+
end
|
9
|
+
|
10
|
+
LessThan5 =
|
11
|
+
CallableTree::Node::Internal::Builder
|
12
|
+
.new
|
13
|
+
.matcher(&less_than.call(5))
|
14
|
+
.build
|
15
|
+
|
16
|
+
LessThan10 =
|
17
|
+
CallableTree::Node::Internal::Builder
|
18
|
+
.new
|
19
|
+
.matcher(&less_than.call(10))
|
20
|
+
.build
|
21
|
+
|
22
|
+
add = proc do |num|
|
23
|
+
proc { |input| input + num }
|
24
|
+
end
|
25
|
+
|
26
|
+
Add1 =
|
27
|
+
CallableTree::Node::External::Builder
|
28
|
+
.new
|
29
|
+
.caller(&add.call(1))
|
30
|
+
.build
|
31
|
+
|
32
|
+
subtract = proc do |num|
|
33
|
+
proc { |input| input - num }
|
34
|
+
end
|
35
|
+
|
36
|
+
Subtract1 =
|
37
|
+
CallableTree::Node::External::Builder
|
38
|
+
.new
|
39
|
+
.caller(&subtract.call(1))
|
40
|
+
.build
|
41
|
+
|
42
|
+
multiply = proc do |num|
|
43
|
+
proc { |input| input * num }
|
44
|
+
end
|
45
|
+
|
46
|
+
Multiply2 =
|
47
|
+
CallableTree::Node::External::Builder
|
48
|
+
.new
|
49
|
+
.caller(&multiply.call(2))
|
50
|
+
.build
|
51
|
+
|
52
|
+
Multiply3 =
|
53
|
+
CallableTree::Node::External::Builder
|
54
|
+
.new
|
55
|
+
.caller(&multiply.call(3))
|
56
|
+
.build
|
57
|
+
|
58
|
+
tree = CallableTree::Node::Root.new.broadcastable.append(
|
59
|
+
LessThan5.new.broadcastable.append(
|
60
|
+
Multiply2.new,
|
61
|
+
Add1.new
|
62
|
+
),
|
63
|
+
LessThan10.new.broadcastable.append(
|
64
|
+
Multiply3.new,
|
65
|
+
Subtract1.new
|
66
|
+
)
|
67
|
+
)
|
68
|
+
|
69
|
+
(0..10).each do |input|
|
70
|
+
output = tree.call(input)
|
71
|
+
puts "#{input} -> #{output}"
|
72
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'callable_tree'
|
4
|
+
|
5
|
+
less_than = proc do |num|
|
6
|
+
# The following block call is equivalent to calling `super` in the class style.
|
7
|
+
proc { |input, &block| block.call(input) && input < num }
|
8
|
+
end
|
9
|
+
|
10
|
+
LessThan5 =
|
11
|
+
CallableTree::Node::Internal::Builder
|
12
|
+
.new
|
13
|
+
.matcher(&less_than.call(5))
|
14
|
+
.build
|
15
|
+
|
16
|
+
LessThan10 =
|
17
|
+
CallableTree::Node::Internal::Builder
|
18
|
+
.new
|
19
|
+
.matcher(&less_than.call(10))
|
20
|
+
.build
|
21
|
+
|
22
|
+
add = proc do |num|
|
23
|
+
proc { |input| input + num }
|
24
|
+
end
|
25
|
+
|
26
|
+
Add1 =
|
27
|
+
CallableTree::Node::External::Builder
|
28
|
+
.new
|
29
|
+
.caller(&add.call(1))
|
30
|
+
.build
|
31
|
+
|
32
|
+
subtract = proc do |num|
|
33
|
+
proc { |input| input - num }
|
34
|
+
end
|
35
|
+
|
36
|
+
Subtract1 =
|
37
|
+
CallableTree::Node::External::Builder
|
38
|
+
.new
|
39
|
+
.caller(&subtract.call(1))
|
40
|
+
.build
|
41
|
+
|
42
|
+
multiply = proc do |num|
|
43
|
+
proc { |input| input * num }
|
44
|
+
end
|
45
|
+
|
46
|
+
Multiply2 =
|
47
|
+
CallableTree::Node::External::Builder
|
48
|
+
.new
|
49
|
+
.caller(&multiply.call(2))
|
50
|
+
.build
|
51
|
+
|
52
|
+
Multiply3 =
|
53
|
+
CallableTree::Node::External::Builder
|
54
|
+
.new
|
55
|
+
.caller(&multiply.call(3))
|
56
|
+
.build
|
57
|
+
|
58
|
+
tree = CallableTree::Node::Root.new.composable.append(
|
59
|
+
LessThan5.new.composable.append(
|
60
|
+
Multiply2.new,
|
61
|
+
Add1.new
|
62
|
+
),
|
63
|
+
LessThan10.new.composable.append(
|
64
|
+
Multiply3.new,
|
65
|
+
Subtract1.new
|
66
|
+
)
|
67
|
+
)
|
68
|
+
|
69
|
+
(0..10).each do |input|
|
70
|
+
output = tree.call(input)
|
71
|
+
puts "#{input} -> #{output}"
|
72
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'callable_tree'
|
4
|
+
require 'json'
|
5
|
+
require 'rexml/document'
|
6
|
+
|
7
|
+
module JSONParser
|
8
|
+
def self.build
|
9
|
+
CallableTree::Node::Internal::Builder
|
10
|
+
.new
|
11
|
+
.matcher do |input, **_options|
|
12
|
+
File.extname(input) == '.json'
|
13
|
+
end
|
14
|
+
.caller do |input, **options, &block|
|
15
|
+
File.open(input) do |file|
|
16
|
+
json = ::JSON.load(file)
|
17
|
+
# The following block call is equivalent to calling `super` in the class style.
|
18
|
+
block.call(json, **options)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
.terminator do
|
22
|
+
true
|
23
|
+
end
|
24
|
+
.build
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
module XMLParser
|
29
|
+
def self.build
|
30
|
+
CallableTree::Node::Internal::Builder
|
31
|
+
.new
|
32
|
+
.matcher do |input, **_options|
|
33
|
+
File.extname(input) == '.xml'
|
34
|
+
end
|
35
|
+
.caller do |input, **options, &block|
|
36
|
+
File.open(input) do |file|
|
37
|
+
# The following block call is equivalent to calling `super` in the class style.
|
38
|
+
block.call(REXML::Document.new(file), **options)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
.terminator do
|
42
|
+
true
|
43
|
+
end
|
44
|
+
.build
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
module JSONScraper
|
49
|
+
def self.build(type)
|
50
|
+
CallableTree::Node::External::Builder
|
51
|
+
.new
|
52
|
+
.matcher do |input, **_options|
|
53
|
+
!!input[type.to_s]
|
54
|
+
end
|
55
|
+
.caller do |input, **_options|
|
56
|
+
input[type.to_s]
|
57
|
+
.map { |element| [element['name'], element['emoji']] }
|
58
|
+
.to_h
|
59
|
+
end
|
60
|
+
.build
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
module XMLScraper
|
65
|
+
def self.build(type)
|
66
|
+
CallableTree::Node::External::Builder
|
67
|
+
.new
|
68
|
+
.matcher do |input, **_options|
|
69
|
+
!input.get_elements("//#{type}").empty?
|
70
|
+
end
|
71
|
+
.caller do |input, **_options|
|
72
|
+
input
|
73
|
+
.get_elements("//#{type}")
|
74
|
+
.first
|
75
|
+
.map { |element| [element['name'], element['emoji']] }
|
76
|
+
.to_h
|
77
|
+
end
|
78
|
+
.build
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
tree = CallableTree::Node::Root.new.seekable.append(
|
83
|
+
JSONParser.build.new.seekable.append(
|
84
|
+
JSONScraper.build(:animals).new,
|
85
|
+
JSONScraper.build(:fruits).new
|
86
|
+
),
|
87
|
+
XMLParser.build.new.seekable.append(
|
88
|
+
XMLScraper.build(:animals).new,
|
89
|
+
XMLScraper.build(:fruits).new
|
90
|
+
)
|
91
|
+
)
|
92
|
+
|
93
|
+
Dir.glob("#{__dir__}/../docs/*") do |file|
|
94
|
+
options = { foo: :bar }
|
95
|
+
pp tree.call(file, **options)
|
96
|
+
puts '---'
|
97
|
+
end
|
@@ -16,16 +16,16 @@ module Node
|
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
|
-
tree = CallableTree::Node::Root.new.append(
|
20
|
-
Node::LessThan.new(5).append(
|
19
|
+
tree = CallableTree::Node::Root.new.broadcastable.append(
|
20
|
+
Node::LessThan.new(5).broadcastable.append(
|
21
21
|
->(input) { input * 2 }, # anonymous external node
|
22
22
|
->(input) { input + 1 } # anonymous external node
|
23
|
-
)
|
24
|
-
Node::LessThan.new(10).append(
|
23
|
+
),
|
24
|
+
Node::LessThan.new(10).broadcastable.append(
|
25
25
|
->(input) { input * 3 }, # anonymous external node
|
26
26
|
->(input) { input - 1 } # anonymous external node
|
27
|
-
)
|
28
|
-
)
|
27
|
+
)
|
28
|
+
)
|
29
29
|
|
30
30
|
(0..10).each do |input|
|
31
31
|
output = tree.call(input)
|
@@ -16,16 +16,16 @@ module Node
|
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
|
-
tree = CallableTree::Node::Root.new.append(
|
20
|
-
Node::LessThan.new(5).append(
|
19
|
+
tree = CallableTree::Node::Root.new.composable.append(
|
20
|
+
Node::LessThan.new(5).composable.append(
|
21
21
|
proc { |input| input * 2 }, # anonymous external node
|
22
22
|
proc { |input| input + 1 } # anonymous external node
|
23
|
-
)
|
24
|
-
Node::LessThan.new(10).append(
|
23
|
+
),
|
24
|
+
Node::LessThan.new(10).composable.append(
|
25
25
|
proc { |input| input * 3 }, # anonymous external node
|
26
26
|
proc { |input| input - 1 } # anonymous external node
|
27
|
-
)
|
28
|
-
)
|
27
|
+
)
|
28
|
+
)
|
29
29
|
|
30
30
|
(0..10).each do |input|
|
31
31
|
output = tree.call(input)
|
@@ -85,12 +85,12 @@ module Node
|
|
85
85
|
end
|
86
86
|
end
|
87
87
|
|
88
|
-
tree = CallableTree::Node::Root.new.append(
|
89
|
-
Node::JSON::Parser.new.append(
|
88
|
+
tree = CallableTree::Node::Root.new.seekable.append(
|
89
|
+
Node::JSON::Parser.new.seekable.append(
|
90
90
|
Node::JSON::Scraper.new(type: :animals),
|
91
91
|
Node::JSON::Scraper.new(type: :fruits)
|
92
92
|
),
|
93
|
-
Node::XML::Parser.new.append(
|
93
|
+
Node::XML::Parser.new.seekable.append(
|
94
94
|
Node::XML::Scraper.new(type: :animals),
|
95
95
|
Node::XML::Scraper.new(type: :fruits)
|
96
96
|
)
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CallableTree
|
4
|
+
module Node
|
5
|
+
module Builder
|
6
|
+
def matcher(&block)
|
7
|
+
@matcher = block
|
8
|
+
self
|
9
|
+
end
|
10
|
+
|
11
|
+
def caller(&block)
|
12
|
+
@caller = block
|
13
|
+
self
|
14
|
+
end
|
15
|
+
|
16
|
+
def terminater(&block)
|
17
|
+
warn 'Use CallableTree::Node::Internal::Builder#terminator instead.'
|
18
|
+
@terminator = block
|
19
|
+
self
|
20
|
+
end
|
21
|
+
|
22
|
+
def terminator(&block)
|
23
|
+
@terminator = block
|
24
|
+
self
|
25
|
+
end
|
26
|
+
|
27
|
+
def hookable(hookable = true)
|
28
|
+
@hookable = hookable
|
29
|
+
self
|
30
|
+
end
|
31
|
+
|
32
|
+
def build(node_type:)
|
33
|
+
matcher = @matcher
|
34
|
+
caller = @caller
|
35
|
+
terminator = @terminator
|
36
|
+
hookable = @hookable
|
37
|
+
|
38
|
+
validate(
|
39
|
+
matcher: matcher,
|
40
|
+
caller: caller,
|
41
|
+
terminator: terminator
|
42
|
+
)
|
43
|
+
|
44
|
+
::Class
|
45
|
+
.new do
|
46
|
+
include node_type
|
47
|
+
prepend Hooks::Call if hookable
|
48
|
+
|
49
|
+
if matcher
|
50
|
+
define_method(:match?) do |*inputs, **options|
|
51
|
+
matcher.call(*inputs, **options) do |*inputs, **options|
|
52
|
+
super(*inputs, **options)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
if caller
|
58
|
+
define_method(:call) do |*inputs, **options|
|
59
|
+
caller.call(*inputs, **options) do |*inputs, **options|
|
60
|
+
super(*inputs, **options)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
if terminator
|
66
|
+
define_method(:terminate?) do |output, *inputs, **options|
|
67
|
+
terminator.call(output, *inputs, **options) do |output, *inputs, **options|
|
68
|
+
super(output, *inputs, **options)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
private
|
76
|
+
|
77
|
+
def validate(matcher:, caller:, terminator:)
|
78
|
+
raise ::CallableTree::Error, 'Not implemented'
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CallableTree
|
4
|
+
module Node
|
5
|
+
module External
|
6
|
+
class Builder
|
7
|
+
include Node::Builder
|
8
|
+
|
9
|
+
class Error < StandardError; end
|
10
|
+
|
11
|
+
def build
|
12
|
+
super(node_type: External)
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def validate(matcher:, caller:, terminator:)
|
18
|
+
raise Error 'caller is required' unless caller
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CallableTree
|
4
|
+
module Node
|
5
|
+
module Internal
|
6
|
+
class Builder
|
7
|
+
include Node::Builder
|
8
|
+
|
9
|
+
def build
|
10
|
+
super(node_type: Internal)
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def validate(matcher:, caller:, terminator:)
|
16
|
+
# noop
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -17,9 +17,7 @@ module CallableTree
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def append(*callables)
|
20
|
-
clone.
|
21
|
-
node.append!(*callables)
|
22
|
-
end
|
20
|
+
clone.append!(*callables)
|
23
21
|
end
|
24
22
|
|
25
23
|
def append!(*callables)
|
@@ -30,21 +28,38 @@ module CallableTree
|
|
30
28
|
self
|
31
29
|
end
|
32
30
|
|
33
|
-
def
|
34
|
-
|
35
|
-
|
31
|
+
def find(recursive: false, &block)
|
32
|
+
node = child_nodes.find(&block)
|
33
|
+
return node if node
|
34
|
+
|
35
|
+
if recursive
|
36
|
+
child_nodes
|
37
|
+
.lazy
|
38
|
+
.select { |node| node.is_a?(Internal) }
|
39
|
+
.map { |node| node.find(recursive: true, &block) }
|
40
|
+
.reject(&:nil?)
|
41
|
+
.first
|
36
42
|
end
|
37
43
|
end
|
38
44
|
|
39
|
-
def reject
|
45
|
+
def reject(recursive: false, &block)
|
46
|
+
clone.reject!(recursive: recursive, &block)
|
47
|
+
end
|
48
|
+
|
49
|
+
def reject!(recursive: false, &block)
|
40
50
|
child_nodes.reject!(&block)
|
51
|
+
|
52
|
+
if recursive
|
53
|
+
child_nodes.each do |node|
|
54
|
+
node.reject!(recursive: true, &block) if node.is_a?(Internal)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
41
58
|
self
|
42
59
|
end
|
43
60
|
|
44
61
|
def shake(&block)
|
45
|
-
clone.
|
46
|
-
node.shake!(&block)
|
47
|
-
end
|
62
|
+
clone.shake!(&block)
|
48
63
|
end
|
49
64
|
|
50
65
|
def shake!(&block)
|
@@ -83,6 +98,10 @@ module CallableTree
|
|
83
98
|
end
|
84
99
|
end
|
85
100
|
|
101
|
+
alias_method :seekable?, :seek?
|
102
|
+
alias_method :seekable, :seek
|
103
|
+
alias_method :seekable!, :seek!
|
104
|
+
|
86
105
|
def broadcast?
|
87
106
|
strategy.is_a?(Strategy::Broadcast)
|
88
107
|
end
|
@@ -103,6 +122,10 @@ module CallableTree
|
|
103
122
|
end
|
104
123
|
end
|
105
124
|
|
125
|
+
alias_method :broadcastable?, :broadcast?
|
126
|
+
alias_method :broadcastable, :broadcast
|
127
|
+
alias_method :broadcastable!, :broadcast!
|
128
|
+
|
106
129
|
def compose?
|
107
130
|
strategy.is_a?(Strategy::Compose)
|
108
131
|
end
|
@@ -123,6 +146,10 @@ module CallableTree
|
|
123
146
|
end
|
124
147
|
end
|
125
148
|
|
149
|
+
alias_method :composable?, :compose?
|
150
|
+
alias_method :composable, :compose
|
151
|
+
alias_method :composable!, :compose!
|
152
|
+
|
126
153
|
def outline(&block)
|
127
154
|
key = block ? block.call(self) : identity
|
128
155
|
value = child_nodes.reduce({}) { |memo, node| memo.merge!(node.outline(&block)) }
|
data/lib/callable_tree.rb
CHANGED
@@ -15,4 +15,7 @@ require_relative 'callable_tree/node/internal/strategy/compose'
|
|
15
15
|
require_relative 'callable_tree/node/external/verbose'
|
16
16
|
require_relative 'callable_tree/node/external'
|
17
17
|
require_relative 'callable_tree/node/internal'
|
18
|
+
require_relative 'callable_tree/node/builder'
|
19
|
+
require_relative 'callable_tree/node/internal/builder'
|
20
|
+
require_relative 'callable_tree/node/external/builder'
|
18
21
|
require_relative 'callable_tree/node/root'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: callable_tree
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- jsmmr
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-03-20 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Builds a tree by linking callable nodes. The nodes that match the conditions
|
14
14
|
are called in a chain from the root node to the leaf node. These are like nested
|
@@ -33,6 +33,10 @@ files:
|
|
33
33
|
- bin/console
|
34
34
|
- bin/setup
|
35
35
|
- callable_tree.gemspec
|
36
|
+
- examples/builder/hooks-call.rb
|
37
|
+
- examples/builder/internal-broadcastable.rb
|
38
|
+
- examples/builder/internal-composable.rb
|
39
|
+
- examples/builder/internal-seekable.rb
|
36
40
|
- examples/docs/animals.json
|
37
41
|
- examples/docs/animals.xml
|
38
42
|
- examples/docs/fruits.json
|
@@ -40,16 +44,19 @@ files:
|
|
40
44
|
- examples/external-verbosify.rb
|
41
45
|
- examples/hooks-call.rb
|
42
46
|
- examples/identity.rb
|
43
|
-
- examples/internal-
|
44
|
-
- examples/internal-
|
45
|
-
- examples/internal-
|
47
|
+
- examples/internal-broadcastable.rb
|
48
|
+
- examples/internal-composable.rb
|
49
|
+
- examples/internal-seekable.rb
|
46
50
|
- examples/logging.rb
|
47
51
|
- lib/callable_tree.rb
|
48
52
|
- lib/callable_tree/node.rb
|
53
|
+
- lib/callable_tree/node/builder.rb
|
49
54
|
- lib/callable_tree/node/external.rb
|
55
|
+
- lib/callable_tree/node/external/builder.rb
|
50
56
|
- lib/callable_tree/node/external/verbose.rb
|
51
57
|
- lib/callable_tree/node/hooks/call.rb
|
52
58
|
- lib/callable_tree/node/internal.rb
|
59
|
+
- lib/callable_tree/node/internal/builder.rb
|
53
60
|
- lib/callable_tree/node/internal/strategy.rb
|
54
61
|
- lib/callable_tree/node/internal/strategy/broadcast.rb
|
55
62
|
- lib/callable_tree/node/internal/strategy/compose.rb
|
@@ -62,7 +69,7 @@ licenses:
|
|
62
69
|
metadata:
|
63
70
|
homepage_uri: https://github.com/jsmmr/ruby_callable_tree
|
64
71
|
source_code_uri: https://github.com/jsmmr/ruby_callable_tree
|
65
|
-
changelog_uri: https://github.com/jsmmr/ruby_callable_tree/blob/v0.3.
|
72
|
+
changelog_uri: https://github.com/jsmmr/ruby_callable_tree/blob/v0.3.5/CHANGELOG.md
|
66
73
|
post_install_message:
|
67
74
|
rdoc_options: []
|
68
75
|
require_paths:
|
@@ -78,7 +85,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
78
85
|
- !ruby/object:Gem::Version
|
79
86
|
version: '0'
|
80
87
|
requirements: []
|
81
|
-
rubygems_version: 3.3.
|
88
|
+
rubygems_version: 3.3.7
|
82
89
|
signing_key:
|
83
90
|
specification_version: 4
|
84
91
|
summary: Builds a tree by linking callable nodes. The nodes that match the conditions
|