callable_tree 0.1.3 → 0.2.3
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/.ruby-version +1 -1
- data/CHANGELOG.md +22 -0
- data/Gemfile.lock +4 -4
- data/LICENSE.txt +1 -1
- data/README.md +4 -2
- data/callable_tree.gemspec +1 -1
- data/lib/callable_tree/node/external.rb +17 -0
- data/lib/callable_tree/node/internal/strategy/broadcast.rb +17 -0
- data/lib/callable_tree/node/internal/strategy/compose.rb +21 -0
- data/lib/callable_tree/node/internal/strategy/seek.rb +25 -0
- data/lib/callable_tree/node/internal.rb +82 -22
- data/lib/callable_tree/node.rb +10 -2
- data/lib/callable_tree/version.rb +1 -1
- data/lib/callable_tree.rb +3 -3
- metadata +8 -8
- data/lib/callable_tree/node/internal/broadcast.rb +0 -15
- data/lib/callable_tree/node/internal/compose.rb +0 -19
- data/lib/callable_tree/node/internal/seek.rb +0 -23
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: df7b380d00c1a56530ddd6fc4ee7159ca4f1fc14d3418c2f567f43ff6d176553
|
4
|
+
data.tar.gz: 9e2d706c5d50ae1350dfdcf92951678e7284a83fba5a71e9f8f13ffcb58c4db7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9cd503091f5ba29c416120bdf5eca39535048c920721d0e4180cbfa95b3eb4d40ea77e2f28a9a8f4cb271adbd11050ad6a4a33313a80baf5cfa587a4e81365a1
|
7
|
+
data.tar.gz: 1948d9a3f5ec7a8ed17030436e513f253c2f1d1e24719f8813128bdb7e3db68f6a6d573cf2dc5e155177c4c1558b0aaf4cf9befbaf0d2a7c71b3ce6b92d3b668
|
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
3.0.
|
1
|
+
3.0.2
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,27 @@
|
|
1
1
|
## [Unreleased]
|
2
2
|
|
3
|
+
## [0.2.3] - 2021-11-07
|
4
|
+
- Add `CallableTree::Node::Internal#shake` to recursively execute `CallableTree::Node::Internal#reject`, including child nodes. The child nodes that are empty because their children have been rejected will also be rejected.
|
5
|
+
- Add `CallableTree::Node::Internal#shake!` that make destructive change.
|
6
|
+
- Add `CallableTree::Node#outline` that may be useful for writing the specs.
|
7
|
+
|
8
|
+
## [0.2.2] - 2021-10-24
|
9
|
+
- Add `CallableTree::Node::Internal#reject` to return a new node instance without rejected child nodes.
|
10
|
+
- Add `CallableTree::Node::Internal#reject!` to destructively reject child nodes.
|
11
|
+
|
12
|
+
## [0.2.1] - 2021-07-24
|
13
|
+
- Add `CallableTree::Node#root?`.
|
14
|
+
- Add `CallableTree::Node::Internal#seek!` that make destructive change.
|
15
|
+
- Add `CallableTree::Node::Internal#broadcast!` that make destructive change.
|
16
|
+
- Add `CallableTree::Node::Internal#compose!` that make destructive change.
|
17
|
+
|
18
|
+
## [0.2.0] - 2021-06-15
|
19
|
+
- Change `CallableTree::Node::Internal#append` to return a new instance.
|
20
|
+
To keep the same behavior as the older version, use `CallableTree::Node::External#append!` that make destructive change.
|
21
|
+
- Remove `CallableTree::Node::Internal#<<`. Use `CallableTree::Node::External#append!` instead.
|
22
|
+
- Change `CallableTree::Node::External#verbosify` to return a new instance.
|
23
|
+
To keep the same behavior as the older version, use `CallableTree::Node::External#verbosify!` that make destructive change.
|
24
|
+
|
3
25
|
## [0.1.3] - 2021-06-12
|
4
26
|
- Minor improvements
|
5
27
|
|
data/Gemfile.lock
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
callable_tree (0.
|
4
|
+
callable_tree (0.2.3)
|
5
5
|
|
6
6
|
GEM
|
7
7
|
remote: https://rubygems.org/
|
8
8
|
specs:
|
9
9
|
diff-lcs (1.4.4)
|
10
|
-
rake (13.0.
|
10
|
+
rake (13.0.6)
|
11
11
|
rspec (3.10.0)
|
12
12
|
rspec-core (~> 3.10.0)
|
13
13
|
rspec-expectations (~> 3.10.0)
|
@@ -20,7 +20,7 @@ GEM
|
|
20
20
|
rspec-mocks (3.10.2)
|
21
21
|
diff-lcs (>= 1.2.0, < 2.0)
|
22
22
|
rspec-support (~> 3.10.0)
|
23
|
-
rspec-support (3.10.
|
23
|
+
rspec-support (3.10.3)
|
24
24
|
|
25
25
|
PLATFORMS
|
26
26
|
x86_64-darwin-19
|
@@ -32,4 +32,4 @@ DEPENDENCIES
|
|
32
32
|
rspec (~> 3.0)
|
33
33
|
|
34
34
|
BUNDLED WITH
|
35
|
-
2.2.
|
35
|
+
2.2.22
|
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# CallableTree
|
2
2
|
|
3
|
+
[](https://github.com/jsmmr/ruby_callable_tree/actions/workflows/build.yml)
|
4
|
+
|
3
5
|
## Installation
|
4
6
|
|
5
7
|
Add this line to your application's Gemfile:
|
@@ -158,7 +160,7 @@ Run `examples/internal-seek.rb`:
|
|
158
160
|
---
|
159
161
|
```
|
160
162
|
|
161
|
-
#### `CallableTree::Node::Internal#broadcast`
|
163
|
+
#### `CallableTree::Node::Internal#broadcast`
|
162
164
|
|
163
165
|
This strategy calls all child nodes of the internal node and ignores their `terminate?` methods, and then outputs their results as array.
|
164
166
|
|
@@ -212,7 +214,7 @@ Run `examples/internal-broadcast.rb`:
|
|
212
214
|
10 -> [nil, nil]
|
213
215
|
```
|
214
216
|
|
215
|
-
#### `CallableTree::Node::Internal#compose`
|
217
|
+
#### `CallableTree::Node::Internal#compose`
|
216
218
|
|
217
219
|
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.
|
218
220
|
|
data/callable_tree.gemspec
CHANGED
@@ -9,7 +9,7 @@ Gem::Specification.new do |spec|
|
|
9
9
|
spec.email = ['jsmmr@icloud.com']
|
10
10
|
|
11
11
|
spec.summary = 'Builds a tree by linking callable nodes. The nodes that match the conditions are called in a chain from the root node to the leaf node. These are like nested `if` or `case` expressions.'
|
12
|
-
spec.description = 'Builds a tree by linking callable nodes. The nodes that match the
|
12
|
+
spec.description = 'Builds a tree by linking callable nodes. The nodes that match the conditions are called in a chain from the root node to the leaf node. These are like nested `if` or `case` expressions.'
|
13
13
|
spec.homepage = 'https://github.com/jsmmr/ruby_callable_tree'
|
14
14
|
spec.license = 'MIT'
|
15
15
|
spec.required_ruby_version = Gem::Requirement.new('>= 2.4.0')
|
@@ -18,6 +18,12 @@ module CallableTree
|
|
18
18
|
end
|
19
19
|
|
20
20
|
def verbosify
|
21
|
+
clone.tap do |node|
|
22
|
+
node.extend Verbose
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def verbosify!
|
21
27
|
extend Verbose
|
22
28
|
self
|
23
29
|
end
|
@@ -31,6 +37,17 @@ module CallableTree
|
|
31
37
|
.class
|
32
38
|
end
|
33
39
|
|
40
|
+
def outline
|
41
|
+
{ identity => nil }
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def initialize_copy(_node)
|
47
|
+
super
|
48
|
+
self.parent = nil
|
49
|
+
end
|
50
|
+
|
34
51
|
class Proxy
|
35
52
|
extend ::Forwardable
|
36
53
|
include External
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CallableTree
|
4
|
+
module Node
|
5
|
+
module Internal
|
6
|
+
module Strategy
|
7
|
+
class Broadcast
|
8
|
+
def call(nodes, input:, options:)
|
9
|
+
nodes.map do |node|
|
10
|
+
node.call(input, **options) if node.match?(input, **options)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CallableTree
|
4
|
+
module Node
|
5
|
+
module Internal
|
6
|
+
module Strategy
|
7
|
+
class Compose
|
8
|
+
def call(nodes, input:, options:)
|
9
|
+
nodes.reduce(input) do |input, node|
|
10
|
+
if node.match?(input, **options)
|
11
|
+
node.call(input, **options)
|
12
|
+
else
|
13
|
+
input
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CallableTree
|
4
|
+
module Node
|
5
|
+
module Internal
|
6
|
+
module Strategy
|
7
|
+
class Seek
|
8
|
+
def call(nodes, input:, options:)
|
9
|
+
nodes
|
10
|
+
.lazy
|
11
|
+
.select { |node| node.match?(input, **options) }
|
12
|
+
.map do |node|
|
13
|
+
output = node.call(input, **options)
|
14
|
+
terminated = node.terminate?(output, **options)
|
15
|
+
[output, terminated]
|
16
|
+
end
|
17
|
+
.select { |_output, terminated| terminated }
|
18
|
+
.map { |output, _terminated| output }
|
19
|
+
.first
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -6,75 +6,135 @@ module CallableTree
|
|
6
6
|
include Node
|
7
7
|
|
8
8
|
def children
|
9
|
-
|
9
|
+
# TODO: Change to return a new array instance.
|
10
|
+
child_nodes
|
10
11
|
end
|
11
12
|
|
12
|
-
def
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
13
|
+
def append(*callables)
|
14
|
+
clone.tap do |node|
|
15
|
+
node.append!(*callables)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def append!(*callables)
|
20
|
+
callables
|
21
|
+
.map { |callable| nodeify(callable) }
|
22
|
+
.tap { |nodes| child_nodes.push(*nodes) } # Use Array#push for Ruby 2.4
|
20
23
|
|
21
24
|
self
|
22
25
|
end
|
23
26
|
|
24
|
-
def
|
25
|
-
|
27
|
+
def reject(&block)
|
28
|
+
clone.tap do |node|
|
29
|
+
node.reject!(&block)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def reject!(&block)
|
34
|
+
child_nodes.reject!(&block)
|
26
35
|
self
|
27
36
|
end
|
28
37
|
|
38
|
+
def shake(&block)
|
39
|
+
clone.tap do |node|
|
40
|
+
node.shake!(&block)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def shake!(&block)
|
45
|
+
reject!(&block) if block_given?
|
46
|
+
|
47
|
+
reject! do |node|
|
48
|
+
node.is_a?(Internal) && node.shake!(&block).child_nodes.empty?
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
29
52
|
def match?(_input = nil, **_options)
|
30
|
-
!
|
53
|
+
!child_nodes.empty?
|
31
54
|
end
|
32
55
|
|
33
56
|
def call(input = nil, **options)
|
34
|
-
strategy.call(
|
57
|
+
strategy.call(child_nodes, input: input, options: options)
|
35
58
|
end
|
36
59
|
|
37
60
|
def seek
|
38
|
-
if strategy.is_a?(Seek)
|
61
|
+
if strategy.is_a?(Strategy::Seek)
|
39
62
|
self
|
40
63
|
else
|
41
64
|
clone.tap do |node|
|
42
|
-
node.send(:strategy=, Seek.new)
|
65
|
+
node.send(:strategy=, Strategy::Seek.new)
|
43
66
|
end
|
44
67
|
end
|
45
68
|
end
|
46
69
|
|
70
|
+
def seek!
|
71
|
+
self.strategy = Strategy::Seek.new unless strategy.is_a?(Strategy::Seek)
|
72
|
+
self
|
73
|
+
end
|
74
|
+
|
47
75
|
def broadcast
|
48
|
-
if strategy.is_a?(Broadcast)
|
76
|
+
if strategy.is_a?(Strategy::Broadcast)
|
49
77
|
self
|
50
78
|
else
|
51
79
|
clone.tap do |node|
|
52
|
-
node.send(:strategy=, Broadcast.new)
|
80
|
+
node.send(:strategy=, Strategy::Broadcast.new)
|
53
81
|
end
|
54
82
|
end
|
55
83
|
end
|
56
84
|
|
85
|
+
def broadcast!
|
86
|
+
self.strategy = Strategy::Broadcast.new unless strategy.is_a?(Strategy::Broadcast)
|
87
|
+
self
|
88
|
+
end
|
89
|
+
|
57
90
|
def compose
|
58
|
-
if strategy.is_a?(Compose)
|
91
|
+
if strategy.is_a?(Strategy::Compose)
|
59
92
|
self
|
60
93
|
else
|
61
94
|
clone.tap do |node|
|
62
|
-
node.send(:strategy=, Compose.new)
|
95
|
+
node.send(:strategy=, Strategy::Compose.new)
|
63
96
|
end
|
64
97
|
end
|
65
98
|
end
|
66
99
|
|
100
|
+
def compose!
|
101
|
+
self.strategy = Strategy::Compose.new unless strategy.is_a?(Strategy::Compose)
|
102
|
+
self
|
103
|
+
end
|
104
|
+
|
105
|
+
def outline(&block)
|
106
|
+
key = block ? block.call(self) : identity
|
107
|
+
value = child_nodes.reduce({}) { |memo, node| memo.merge!(node.outline(&block)) }
|
108
|
+
{ key => value }
|
109
|
+
end
|
110
|
+
|
111
|
+
protected
|
112
|
+
|
113
|
+
def child_nodes
|
114
|
+
@child_nodes ||= []
|
115
|
+
end
|
116
|
+
|
67
117
|
private
|
68
118
|
|
69
|
-
attr_writer :
|
119
|
+
attr_writer :child_nodes, :strategy
|
120
|
+
|
121
|
+
def nodeify(callable)
|
122
|
+
if callable.is_a?(Node)
|
123
|
+
callable.clone
|
124
|
+
else
|
125
|
+
External.proxify(callable)
|
126
|
+
end
|
127
|
+
.tap { |node| node.send(:parent=, self) }
|
128
|
+
end
|
70
129
|
|
71
130
|
def strategy
|
72
|
-
@strategy ||= Seek.new
|
131
|
+
@strategy ||= Strategy::Seek.new
|
73
132
|
end
|
74
133
|
|
75
134
|
def initialize_copy(_node)
|
76
135
|
super
|
77
|
-
self.
|
136
|
+
self.parent = nil
|
137
|
+
self.child_nodes = child_nodes.map do |node|
|
78
138
|
node.clone.tap { |new_node| new_node.send(:parent=, self) }
|
79
139
|
end
|
80
140
|
end
|
data/lib/callable_tree/node.rb
CHANGED
@@ -4,12 +4,16 @@ module CallableTree
|
|
4
4
|
module Node
|
5
5
|
attr_reader :parent
|
6
6
|
|
7
|
+
def root?
|
8
|
+
parent.nil?
|
9
|
+
end
|
10
|
+
|
7
11
|
def ancestors
|
8
12
|
::Enumerator.new do |y|
|
9
13
|
node = self
|
10
14
|
loop do
|
11
15
|
y << node
|
12
|
-
break unless node = node
|
16
|
+
break unless node = node.parent
|
13
17
|
end
|
14
18
|
end
|
15
19
|
end
|
@@ -23,7 +27,11 @@ module CallableTree
|
|
23
27
|
end
|
24
28
|
|
25
29
|
def depth
|
26
|
-
|
30
|
+
root? ? 0 : parent.depth + 1
|
31
|
+
end
|
32
|
+
|
33
|
+
def outline
|
34
|
+
raise ::CallableTree::Error, 'Not implemented'
|
27
35
|
end
|
28
36
|
|
29
37
|
def match?(_input = nil, **_options)
|
data/lib/callable_tree.rb
CHANGED
@@ -8,9 +8,9 @@ require 'forwardable'
|
|
8
8
|
require_relative 'callable_tree/version'
|
9
9
|
require_relative 'callable_tree/node'
|
10
10
|
require_relative 'callable_tree/node/hooks/call'
|
11
|
-
require_relative 'callable_tree/node/internal/broadcast'
|
12
|
-
require_relative 'callable_tree/node/internal/seek'
|
13
|
-
require_relative 'callable_tree/node/internal/compose'
|
11
|
+
require_relative 'callable_tree/node/internal/strategy/broadcast'
|
12
|
+
require_relative 'callable_tree/node/internal/strategy/seek'
|
13
|
+
require_relative 'callable_tree/node/internal/strategy/compose'
|
14
14
|
require_relative 'callable_tree/node/external/verbose'
|
15
15
|
require_relative 'callable_tree/node/external'
|
16
16
|
require_relative 'callable_tree/node/internal'
|
metadata
CHANGED
@@ -1,16 +1,16 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: callable_tree
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- jsmmr
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-11-07 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
|
-
description: Builds a tree by linking callable nodes. The nodes that match the
|
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
|
15
15
|
`if` or `case` expressions.
|
16
16
|
email:
|
@@ -49,9 +49,9 @@ files:
|
|
49
49
|
- lib/callable_tree/node/external/verbose.rb
|
50
50
|
- lib/callable_tree/node/hooks/call.rb
|
51
51
|
- lib/callable_tree/node/internal.rb
|
52
|
-
- lib/callable_tree/node/internal/broadcast.rb
|
53
|
-
- lib/callable_tree/node/internal/compose.rb
|
54
|
-
- lib/callable_tree/node/internal/seek.rb
|
52
|
+
- lib/callable_tree/node/internal/strategy/broadcast.rb
|
53
|
+
- lib/callable_tree/node/internal/strategy/compose.rb
|
54
|
+
- lib/callable_tree/node/internal/strategy/seek.rb
|
55
55
|
- lib/callable_tree/node/root.rb
|
56
56
|
- lib/callable_tree/version.rb
|
57
57
|
homepage: https://github.com/jsmmr/ruby_callable_tree
|
@@ -60,7 +60,7 @@ licenses:
|
|
60
60
|
metadata:
|
61
61
|
homepage_uri: https://github.com/jsmmr/ruby_callable_tree
|
62
62
|
source_code_uri: https://github.com/jsmmr/ruby_callable_tree
|
63
|
-
changelog_uri: https://github.com/jsmmr/ruby_callable_tree/blob/v0.
|
63
|
+
changelog_uri: https://github.com/jsmmr/ruby_callable_tree/blob/v0.2.3/CHANGELOG.md
|
64
64
|
post_install_message:
|
65
65
|
rdoc_options: []
|
66
66
|
require_paths:
|
@@ -76,7 +76,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
76
76
|
- !ruby/object:Gem::Version
|
77
77
|
version: '0'
|
78
78
|
requirements: []
|
79
|
-
rubygems_version: 3.2.
|
79
|
+
rubygems_version: 3.2.22
|
80
80
|
signing_key:
|
81
81
|
specification_version: 4
|
82
82
|
summary: Builds a tree by linking callable nodes. The nodes that match the conditions
|
@@ -1,15 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module CallableTree
|
4
|
-
module Node
|
5
|
-
module Internal
|
6
|
-
class Broadcast
|
7
|
-
def call(nodes, input:, options:)
|
8
|
-
nodes.map do |node|
|
9
|
-
node.call(input, **options) if node.match?(input, **options)
|
10
|
-
end
|
11
|
-
end
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
@@ -1,19 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module CallableTree
|
4
|
-
module Node
|
5
|
-
module Internal
|
6
|
-
class Compose
|
7
|
-
def call(nodes, input:, options:)
|
8
|
-
nodes.reduce(input) do |input, node|
|
9
|
-
if node.match?(input, **options)
|
10
|
-
node.call(input, **options)
|
11
|
-
else
|
12
|
-
input
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
@@ -1,23 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module CallableTree
|
4
|
-
module Node
|
5
|
-
module Internal
|
6
|
-
class Seek
|
7
|
-
def call(nodes, input:, options:)
|
8
|
-
nodes
|
9
|
-
.lazy
|
10
|
-
.select { |node| node.match?(input, **options) }
|
11
|
-
.map do |node|
|
12
|
-
output = node.call(input, **options)
|
13
|
-
terminated = node.terminate?(output, **options)
|
14
|
-
[output, terminated]
|
15
|
-
end
|
16
|
-
.select { |_output, terminated| terminated }
|
17
|
-
.map { |output, _terminated| output }
|
18
|
-
.first
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|