callable_tree 0.3.8 → 0.3.10

Sign up to get free protection for your applications and to get access to all the features.
@@ -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