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
@@ -13,7 +13,7 @@ module CallableTree
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def ==(other)
|
16
|
-
name == other.name
|
16
|
+
name == other.name && matchable? == other.matchable? && terminable? == other.terminable?
|
17
17
|
end
|
18
18
|
|
19
19
|
def eql?(other)
|
@@ -21,7 +21,37 @@ module CallableTree
|
|
21
21
|
end
|
22
22
|
|
23
23
|
def hash
|
24
|
-
self.class.name.hash
|
24
|
+
[self.class.name, matchable, terminable].join('-').hash
|
25
|
+
end
|
26
|
+
|
27
|
+
def matchable?
|
28
|
+
matchable
|
29
|
+
end
|
30
|
+
|
31
|
+
def terminable?
|
32
|
+
terminable
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
attr_accessor :matchable, :terminable
|
38
|
+
|
39
|
+
def matcher
|
40
|
+
@matcher ||=
|
41
|
+
if matchable
|
42
|
+
proc { |node, *inputs, **options| node.match?(*inputs, **options) }
|
43
|
+
else
|
44
|
+
proc { false }
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def terminator
|
49
|
+
@terminator ||=
|
50
|
+
if terminable
|
51
|
+
proc { |node, output, *inputs, **options| node.terminate?(output, *inputs, **options) }
|
52
|
+
else
|
53
|
+
proc { false }
|
54
|
+
end
|
25
55
|
end
|
26
56
|
end
|
27
57
|
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CallableTree
|
4
|
+
module Node
|
5
|
+
module Internal
|
6
|
+
module Strategyable
|
7
|
+
def self.included(mod)
|
8
|
+
mod.extend ClassMethods
|
9
|
+
end
|
10
|
+
|
11
|
+
DEFAUTL_FACTORY = proc do |klass, *_args, matchable:, terminable:, **_kwargs|
|
12
|
+
klass.new(matchable: matchable, terminable: terminable)
|
13
|
+
end
|
14
|
+
|
15
|
+
@@strategy_configs = {
|
16
|
+
seek: {
|
17
|
+
klass: Strategy::Seek,
|
18
|
+
alias: :seekable,
|
19
|
+
matchable: true,
|
20
|
+
terminable: true,
|
21
|
+
factory: DEFAUTL_FACTORY
|
22
|
+
},
|
23
|
+
broadcast: {
|
24
|
+
klass: Strategy::Broadcast,
|
25
|
+
alias: :broadcastable,
|
26
|
+
matchable: true,
|
27
|
+
terminable: false,
|
28
|
+
factory: DEFAUTL_FACTORY
|
29
|
+
},
|
30
|
+
compose: {
|
31
|
+
klass: Strategy::Compose,
|
32
|
+
alias: :composable,
|
33
|
+
matchable: true,
|
34
|
+
terminable: false,
|
35
|
+
factory: DEFAUTL_FACTORY
|
36
|
+
}
|
37
|
+
}
|
38
|
+
|
39
|
+
class << self
|
40
|
+
private
|
41
|
+
|
42
|
+
def strategy_configs
|
43
|
+
@@strategy_configs
|
44
|
+
end
|
45
|
+
|
46
|
+
def define_strategy_methods(key, config)
|
47
|
+
define_method(:"#{config[:alias]}?") { strategy.is_a?(config[:klass]) }
|
48
|
+
|
49
|
+
define_method(config[:alias]) do |*args, matchable: config[:matchable], terminable: config[:terminable], **kwargs|
|
50
|
+
# TODO: Modify to use strategize method
|
51
|
+
if strategy == config[:factory].call(
|
52
|
+
config[:klass], *args, matchable: matchable, terminable: terminable, **kwargs
|
53
|
+
)
|
54
|
+
self
|
55
|
+
else
|
56
|
+
clone.__send__(:"#{config[:alias]}!", *args, matchable: matchable, terminable: terminable, **kwargs)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
define_method(:"#{config[:alias]}!") do |*args, matchable: config[:matchable], terminable: config[:terminable], **kwargs|
|
61
|
+
strategize!(key, *args, matchable: matchable, terminable: terminable, **kwargs)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
module ClassMethods
|
67
|
+
def store_strategy(key, config)
|
68
|
+
raise ::CallableTree::Error, 'Strategy class is required. [:klass]' unless config[:klass]
|
69
|
+
|
70
|
+
key = key.to_sym
|
71
|
+
config[:alias] = key unless config[:alias]
|
72
|
+
config[:factory] = DEFAUTL_FACTORY unless config[:factory]
|
73
|
+
Strategyable.__send__(:strategy_configs)[key] = config
|
74
|
+
Strategyable.__send__(:define_strategy_methods, key, config)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
@@strategy_configs.each { |key, config| define_strategy_methods(key, config) }
|
79
|
+
|
80
|
+
# Backward compatibility
|
81
|
+
alias seek? seekable?
|
82
|
+
alias seek seekable
|
83
|
+
alias seek! seekable!
|
84
|
+
alias broadcast? broadcastable?
|
85
|
+
alias broadcast broadcastable
|
86
|
+
alias broadcast! broadcastable!
|
87
|
+
alias compose? composable?
|
88
|
+
alias compose composable
|
89
|
+
alias compose! composable!
|
90
|
+
|
91
|
+
protected
|
92
|
+
|
93
|
+
attr_writer :strategy
|
94
|
+
|
95
|
+
private
|
96
|
+
|
97
|
+
def strategize(name, *args, matchable:, terminable:, **kwargs)
|
98
|
+
clone.strategy!(name, *args, matchable: matchable, terminable: terminable, **kwargs)
|
99
|
+
end
|
100
|
+
|
101
|
+
def strategize!(name, *args, matchable:, terminable:, **kwargs)
|
102
|
+
config = @@strategy_configs[name.to_sym]
|
103
|
+
raise ::CallableTree::Error, "Strategy is not found. [#{name}]" unless config
|
104
|
+
|
105
|
+
self.strategy = config[:factory].call(
|
106
|
+
config[:klass], *args, matchable: matchable, terminable: terminable, **kwargs
|
107
|
+
)
|
108
|
+
self
|
109
|
+
end
|
110
|
+
|
111
|
+
def strategy
|
112
|
+
@strategy ||= @@strategy_configs[:seek][:klass].new
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
@@ -5,12 +5,13 @@ module CallableTree
|
|
5
5
|
module Internal
|
6
6
|
extend ::Forwardable
|
7
7
|
include Node
|
8
|
+
include Strategyable
|
8
9
|
|
9
10
|
def self.included(mod)
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
11
|
+
return unless mod.include?(External)
|
12
|
+
|
13
|
+
raise ::CallableTree::Error,
|
14
|
+
"#{mod} cannot include #{self} together with #{External}"
|
14
15
|
end
|
15
16
|
|
16
17
|
def_delegators :child_nodes, :[], :at
|
@@ -39,14 +40,14 @@ module CallableTree
|
|
39
40
|
node = child_nodes.find(&block)
|
40
41
|
return node if node
|
41
42
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
43
|
+
return unless recursive
|
44
|
+
|
45
|
+
child_nodes
|
46
|
+
.lazy
|
47
|
+
.select(&:internal?)
|
48
|
+
.map { |node| node.find(recursive: true, &block) }
|
49
|
+
.reject(&:nil?)
|
50
|
+
.first
|
50
51
|
end
|
51
52
|
|
52
53
|
def reject(recursive: false, &block)
|
@@ -85,78 +86,6 @@ module CallableTree
|
|
85
86
|
strategy.call(child_nodes, *inputs, **options)
|
86
87
|
end
|
87
88
|
|
88
|
-
def seek?
|
89
|
-
strategy.is_a?(Strategy::Seek)
|
90
|
-
end
|
91
|
-
|
92
|
-
def seek
|
93
|
-
if seek?
|
94
|
-
self
|
95
|
-
else
|
96
|
-
clone.tap do |node|
|
97
|
-
node.strategy = Strategy::Seek.new
|
98
|
-
end
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
|
-
def seek!
|
103
|
-
tap do |node|
|
104
|
-
node.strategy = Strategy::Seek.new unless seek?
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
alias seekable? seek?
|
109
|
-
alias seekable seek
|
110
|
-
alias seekable! seek!
|
111
|
-
|
112
|
-
def broadcast?
|
113
|
-
strategy.is_a?(Strategy::Broadcast)
|
114
|
-
end
|
115
|
-
|
116
|
-
def broadcast
|
117
|
-
if broadcast?
|
118
|
-
self
|
119
|
-
else
|
120
|
-
clone.tap do |node|
|
121
|
-
node.strategy = Strategy::Broadcast.new
|
122
|
-
end
|
123
|
-
end
|
124
|
-
end
|
125
|
-
|
126
|
-
def broadcast!
|
127
|
-
tap do |node|
|
128
|
-
node.strategy = Strategy::Broadcast.new unless broadcast?
|
129
|
-
end
|
130
|
-
end
|
131
|
-
|
132
|
-
alias broadcastable? broadcast?
|
133
|
-
alias broadcastable broadcast
|
134
|
-
alias broadcastable! broadcast!
|
135
|
-
|
136
|
-
def compose?
|
137
|
-
strategy.is_a?(Strategy::Compose)
|
138
|
-
end
|
139
|
-
|
140
|
-
def compose
|
141
|
-
if compose?
|
142
|
-
self
|
143
|
-
else
|
144
|
-
clone.tap do |node|
|
145
|
-
node.strategy = Strategy::Compose.new
|
146
|
-
end
|
147
|
-
end
|
148
|
-
end
|
149
|
-
|
150
|
-
def compose!
|
151
|
-
tap do |node|
|
152
|
-
node.strategy = Strategy::Compose.new unless compose?
|
153
|
-
end
|
154
|
-
end
|
155
|
-
|
156
|
-
alias composable? compose?
|
157
|
-
alias composable compose
|
158
|
-
alias composable! compose!
|
159
|
-
|
160
89
|
def outline(&block)
|
161
90
|
key = block ? block.call(self) : identity
|
162
91
|
value = child_nodes.reduce({}) { |memo, node| memo.merge!(node.outline(&block)) }
|
@@ -171,10 +100,6 @@ module CallableTree
|
|
171
100
|
false
|
172
101
|
end
|
173
102
|
|
174
|
-
protected
|
175
|
-
|
176
|
-
attr_writer :strategy
|
177
|
-
|
178
103
|
def child_nodes
|
179
104
|
@child_nodes ||= []
|
180
105
|
end
|
@@ -192,10 +117,6 @@ module CallableTree
|
|
192
117
|
.tap { |node| node.parent = self }
|
193
118
|
end
|
194
119
|
|
195
|
-
def strategy
|
196
|
-
@strategy ||= Strategy::Seek.new
|
197
|
-
end
|
198
|
-
|
199
120
|
def initialize_copy(_node)
|
200
121
|
super
|
201
122
|
self.parent = nil
|
data/lib/callable_tree/node.rb
CHANGED
data/lib/callable_tree.rb
CHANGED
@@ -14,6 +14,7 @@ require_relative 'callable_tree/node/internal/strategy'
|
|
14
14
|
require_relative 'callable_tree/node/internal/strategy/broadcast'
|
15
15
|
require_relative 'callable_tree/node/internal/strategy/seek'
|
16
16
|
require_relative 'callable_tree/node/internal/strategy/compose'
|
17
|
+
require_relative 'callable_tree/node/internal/strategyable'
|
17
18
|
require_relative 'callable_tree/node/external/verbose'
|
18
19
|
require_relative 'callable_tree/node/external'
|
19
20
|
require_relative 'callable_tree/node/internal'
|
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.10
|
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-12-30 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
|
@@ -19,6 +19,7 @@ executables: []
|
|
19
19
|
extensions: []
|
20
20
|
extra_rdoc_files: []
|
21
21
|
files:
|
22
|
+
- ".github/dependabot.yml"
|
22
23
|
- ".github/workflows/build.yml"
|
23
24
|
- ".github/workflows/codeql-analysis.yml"
|
24
25
|
- ".gitignore"
|
@@ -34,7 +35,9 @@ files:
|
|
34
35
|
- bin/console
|
35
36
|
- bin/setup
|
36
37
|
- callable_tree.gemspec
|
38
|
+
- examples/builder/external-verbosify.rb
|
37
39
|
- examples/builder/hooks.rb
|
40
|
+
- examples/builder/identity.rb
|
38
41
|
- examples/builder/internal-broadcastable.rb
|
39
42
|
- examples/builder/internal-composable.rb
|
40
43
|
- examples/builder/internal-seekable.rb
|
@@ -65,6 +68,7 @@ files:
|
|
65
68
|
- lib/callable_tree/node/internal/strategy/broadcast.rb
|
66
69
|
- lib/callable_tree/node/internal/strategy/compose.rb
|
67
70
|
- lib/callable_tree/node/internal/strategy/seek.rb
|
71
|
+
- lib/callable_tree/node/internal/strategyable.rb
|
68
72
|
- lib/callable_tree/node/root.rb
|
69
73
|
- lib/callable_tree/version.rb
|
70
74
|
homepage: https://github.com/jsmmr/ruby_callable_tree
|
@@ -73,7 +77,7 @@ licenses:
|
|
73
77
|
metadata:
|
74
78
|
homepage_uri: https://github.com/jsmmr/ruby_callable_tree
|
75
79
|
source_code_uri: https://github.com/jsmmr/ruby_callable_tree
|
76
|
-
changelog_uri: https://github.com/jsmmr/ruby_callable_tree/blob/v0.3.
|
80
|
+
changelog_uri: https://github.com/jsmmr/ruby_callable_tree/blob/v0.3.10/CHANGELOG.md
|
77
81
|
rubygems_mfa_required: 'true'
|
78
82
|
post_install_message:
|
79
83
|
rdoc_options: []
|
@@ -90,7 +94,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
90
94
|
- !ruby/object:Gem::Version
|
91
95
|
version: '0'
|
92
96
|
requirements: []
|
93
|
-
rubygems_version: 3.
|
97
|
+
rubygems_version: 3.4.1
|
94
98
|
signing_key:
|
95
99
|
specification_version: 4
|
96
100
|
summary: Builds a tree by linking callable nodes. The nodes that match the conditions
|