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.
@@ -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
- if mod.include?(External)
11
- raise ::CallableTree::Error,
12
- "#{mod} cannot include #{self} together with #{External}"
13
- end
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
- if recursive
43
- child_nodes
44
- .lazy
45
- .select { |node| node.internal? }
46
- .map { |node| node.find(recursive: true, &block) }
47
- .reject(&:nil?)
48
- .first
49
- end
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
@@ -13,7 +13,7 @@ module CallableTree
13
13
  node = self
14
14
  loop do
15
15
  y << node
16
- break unless node = node.parent
16
+ break unless (node = node.parent)
17
17
  end
18
18
  end
19
19
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module CallableTree
4
- VERSION = '0.3.8'
4
+ VERSION = '0.3.10'
5
5
  end
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.8
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-05-05 00:00:00.000000000 Z
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.8/CHANGELOG.md
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.3.7
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