callable_tree 0.3.2 → 0.3.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5a506dec2678a69b014cff69b6cc4fd94e22b1f7f5027e9230727720c8dc049e
4
- data.tar.gz: 3b7ee0419139ef24f40f8b0714cbd19551568967d0170a4b550a84f528811da4
3
+ metadata.gz: 83716fbdef2881db33e8f046f056a17d8a8866423951493902088bf1af53218f
4
+ data.tar.gz: 8906217b71482e1717798329d172640a50f7cc73613a2187beba0702bf8b8d74
5
5
  SHA512:
6
- metadata.gz: b84af5f3ae12941eabdb1cdbc159d9a3f424388bffab74c2704d5507a875c924ae637b2b868194244d2530bcbd8bf5895118e42f7a79c91f901854896d686eb5
7
- data.tar.gz: 816f558c0118c57bda18c3b69fef45240c9de5e87a1acea0bcf1f9448e0c67e34a7de613292796635f8e5c16d1835c2ba4bdef959939c44a6358bce94197a82a
6
+ metadata.gz: 5e5ece858eb3347c41ea5f573e37c972d1a127d9fa234cd2512b18ef9e882b33d0da900b46c8f8e539fcee36fccb6643d21bb0945169019e7734232907c412c1
7
+ data.tar.gz: ce58af4b926c9201f4133f02da848dcfff7962f9fa08588c1d4b4b61765b9c5ffaf03f2cfb4367da7d14a80bc1dcd55ea4b53de39d4075be25ef6e2abaf9ae7e
@@ -11,7 +11,7 @@ jobs:
11
11
  - uses: ruby/setup-ruby@v1
12
12
  with:
13
13
  ruby-version: ${{ matrix.ruby }}
14
- - run: gem install bundler:2.3.3
14
+ - run: gem install bundler:2.3.7
15
15
  - uses: actions/cache@v2
16
16
  with:
17
17
  path: vendor/bundle
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 3.1.0
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.2)
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.10.0)
12
- rspec-core (~> 3.10.0)
13
- rspec-expectations (~> 3.10.0)
14
- rspec-mocks (~> 3.10.0)
15
- rspec-core (3.10.2)
16
- rspec-support (~> 3.10.0)
17
- rspec-expectations (3.10.2)
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.10.0)
20
- rspec-mocks (3.10.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.10.0)
23
- rspec-support (3.10.3)
22
+ rspec-support (~> 3.11.0)
23
+ rspec-support (3.11.0)
24
24
 
25
25
  PLATFORMS
26
- x86_64-darwin-19
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.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#seek` (default)
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-seek.rb`:
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 `seek` method call can be omitted since it is the default strategy.
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
- ),#.seek,
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
- )#.seek
142
- )#.seek
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-seek.rb`:
151
+ Run `examples/internal-seekable.rb`:
152
152
  ```sh
153
- % ruby examples/internal-seek.rb
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#broadcast`
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-broadcast.rb`:
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
- ).broadcast,
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
- ).broadcast
193
- ).broadcast
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-broadcast.rb`:
202
+ Run `examples/internal-broadcastable.rb`:
203
203
  ```sh
204
- % ruby examples/internal-broadcast.rb
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#compose`
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-compose.rb`:
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
- ).compose,
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
- ).compose
247
- ).compose
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-compose.rb`:
256
+ Run `examples/internal-composable.rb`:
257
257
  ```sh
258
- % ruby examples/internal-compose.rb
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/callable_tree.
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
- ).broadcast,
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
- ).broadcast
28
- ).broadcast
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
- ).compose,
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
- ).compose
28
- ).compose
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.tap do |node|
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 reject(&block)
34
- clone.tap do |node|
35
- node.reject!(&block)
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!(&block)
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.tap do |node|
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)) }
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module CallableTree
4
- VERSION = '0.3.2'
4
+ VERSION = '0.3.5'
5
5
  end
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.2
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-02-05 00:00:00.000000000 Z
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-broadcast.rb
44
- - examples/internal-compose.rb
45
- - examples/internal-seek.rb
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.2/CHANGELOG.md
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.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