callable_tree 0.3.3 → 0.3.6
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/workflows/build.yml +1 -1
- data/.ruby-version +1 -1
- data/CHANGELOG.md +26 -0
- data/Gemfile.lock +3 -4
- data/README.md +47 -47
- data/examples/builder/hooks-caller.rb +38 -0
- data/examples/builder/internal-broadcastable.rb +72 -0
- data/examples/builder/internal-composable.rb +72 -0
- data/examples/builder/internal-seekable.rb +93 -0
- data/examples/builder/logging.rb +126 -0
- data/examples/{hooks-call.rb → hooks-caller.rb} +8 -8
- data/examples/{internal-broadcast.rb → internal-broadcastable.rb} +6 -6
- data/examples/{internal-compose.rb → internal-composable.rb} +6 -6
- data/examples/{internal-seek.rb → internal-seekable.rb} +3 -3
- data/lib/callable_tree/node/builder.rb +85 -0
- data/lib/callable_tree/node/external/builder.rb +23 -0
- data/lib/callable_tree/node/external/verbose.rb +0 -1
- data/lib/callable_tree/node/hooks/caller.rb +110 -0
- data/lib/callable_tree/node/hooks/matcher.rb +101 -0
- data/lib/callable_tree/node/internal/builder.rb +21 -0
- data/lib/callable_tree/node/internal.rb +12 -0
- data/lib/callable_tree/node/root.rb +2 -1
- data/lib/callable_tree/version.rb +1 -1
- data/lib/callable_tree.rb +5 -1
- metadata +18 -9
- data/lib/callable_tree/node/hooks/call.rb +0 -81
@@ -0,0 +1,126 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'callable_tree'
|
4
|
+
require 'json'
|
5
|
+
require 'rexml/document'
|
6
|
+
|
7
|
+
JSONParser =
|
8
|
+
CallableTree::Node::Internal::Builder
|
9
|
+
.new
|
10
|
+
.matcher do |input, **_options|
|
11
|
+
File.extname(input) == '.json'
|
12
|
+
end
|
13
|
+
.caller do |input, **options, &block|
|
14
|
+
File.open(input) do |file|
|
15
|
+
json = ::JSON.load(file)
|
16
|
+
# The following block call is equivalent to calling `super` in the class style.
|
17
|
+
block.call(json, **options)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
.terminator do
|
21
|
+
true
|
22
|
+
end
|
23
|
+
.hookable
|
24
|
+
.build
|
25
|
+
|
26
|
+
XMLParser =
|
27
|
+
CallableTree::Node::Internal::Builder
|
28
|
+
.new
|
29
|
+
.matcher do |input, **_options|
|
30
|
+
File.extname(input) == '.xml'
|
31
|
+
end
|
32
|
+
.caller do |input, **options, &block|
|
33
|
+
File.open(input) do |file|
|
34
|
+
# The following block call is equivalent to calling `super` in the class style.
|
35
|
+
block.call(REXML::Document.new(file), **options)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
.terminator do
|
39
|
+
true
|
40
|
+
end
|
41
|
+
.hookable
|
42
|
+
.build
|
43
|
+
|
44
|
+
def build_json_scraper(type)
|
45
|
+
CallableTree::Node::External::Builder
|
46
|
+
.new
|
47
|
+
.matcher do |input, **_options|
|
48
|
+
!!input[type.to_s]
|
49
|
+
end
|
50
|
+
.caller do |input, **_options|
|
51
|
+
input[type.to_s]
|
52
|
+
.map { |element| [element['name'], element['emoji']] }
|
53
|
+
.to_h
|
54
|
+
end
|
55
|
+
.hookable
|
56
|
+
.build
|
57
|
+
end
|
58
|
+
|
59
|
+
AnimalsJSONScraper = build_json_scraper(:animals)
|
60
|
+
FruitsJSONScraper = build_json_scraper(:fruits)
|
61
|
+
|
62
|
+
def build_xml_scraper(type)
|
63
|
+
CallableTree::Node::External::Builder
|
64
|
+
.new
|
65
|
+
.matcher do |input, **_options|
|
66
|
+
!input.get_elements("//#{type}").empty?
|
67
|
+
end
|
68
|
+
.caller do |input, **_options|
|
69
|
+
input
|
70
|
+
.get_elements("//#{type}")
|
71
|
+
.first
|
72
|
+
.map { |element| [element['name'], element['emoji']] }
|
73
|
+
.to_h
|
74
|
+
end
|
75
|
+
.hookable
|
76
|
+
.build
|
77
|
+
end
|
78
|
+
|
79
|
+
AnimalsXMLScraper = build_xml_scraper(:animals)
|
80
|
+
FruitsXMLScraper = build_xml_scraper(:fruits)
|
81
|
+
|
82
|
+
loggable = proc do |node|
|
83
|
+
indent_size = 2
|
84
|
+
blank = ' '
|
85
|
+
list_style = '*'
|
86
|
+
|
87
|
+
node.after_matcher! do |matched, _node_:, **|
|
88
|
+
prefix = list_style.rjust(_node_.depth * indent_size - indent_size + list_style.length, blank)
|
89
|
+
puts "#{prefix} #{_node_.identity}: [matched: #{matched}]"
|
90
|
+
matched
|
91
|
+
end
|
92
|
+
|
93
|
+
if node.is_a?(CallableTree::Node::External)
|
94
|
+
input_label = 'Input :'
|
95
|
+
output_label = 'Output:'
|
96
|
+
|
97
|
+
node
|
98
|
+
.before_caller! do |input, *, _node_:, **|
|
99
|
+
input_prefix = input_label.rjust(_node_.depth * indent_size + input_label.length, blank)
|
100
|
+
puts "#{input_prefix} #{input}"
|
101
|
+
input
|
102
|
+
end
|
103
|
+
.after_caller! do |output, _node_:, **|
|
104
|
+
output_prefix = output_label.rjust(_node_.depth * indent_size + output_label.length, blank)
|
105
|
+
puts "#{output_prefix} #{output}"
|
106
|
+
output
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
tree = CallableTree::Node::Root.new.seekable.append(
|
112
|
+
JSONParser.new.tap(&loggable).seekable.append(
|
113
|
+
AnimalsJSONScraper.new.tap(&loggable).verbosify,
|
114
|
+
FruitsJSONScraper.new.tap(&loggable).verbosify
|
115
|
+
),
|
116
|
+
XMLParser.new.tap(&loggable).seekable.append(
|
117
|
+
AnimalsXMLScraper.new.tap(&loggable).verbosify,
|
118
|
+
FruitsXMLScraper.new.tap(&loggable).verbosify
|
119
|
+
)
|
120
|
+
)
|
121
|
+
|
122
|
+
Dir.glob("#{__dir__}/../docs/*") do |file|
|
123
|
+
options = { foo: :bar }
|
124
|
+
pp tree.call(file, **options)
|
125
|
+
puts '---'
|
126
|
+
end
|
@@ -5,14 +5,14 @@ require 'callable_tree'
|
|
5
5
|
module Node
|
6
6
|
class HooksSample
|
7
7
|
include CallableTree::Node::Internal
|
8
|
-
prepend CallableTree::Node::Hooks::
|
8
|
+
prepend CallableTree::Node::Hooks::Caller
|
9
9
|
end
|
10
10
|
end
|
11
11
|
|
12
12
|
Node::HooksSample
|
13
13
|
.new
|
14
|
-
.
|
15
|
-
puts "
|
14
|
+
.before_caller do |input, **_options|
|
15
|
+
puts "before_caller input: #{input}"
|
16
16
|
input + 1
|
17
17
|
end
|
18
18
|
.append(
|
@@ -22,14 +22,14 @@ Node::HooksSample
|
|
22
22
|
input * 2
|
23
23
|
end
|
24
24
|
)
|
25
|
-
.
|
26
|
-
puts "
|
25
|
+
.around_caller do |input, **_options, &block|
|
26
|
+
puts "around_caller input: #{input}"
|
27
27
|
output = block.call
|
28
|
-
puts "
|
28
|
+
puts "around_caller output: #{output}"
|
29
29
|
output * input
|
30
30
|
end
|
31
|
-
.
|
32
|
-
puts "
|
31
|
+
.after_caller do |output, **_options|
|
32
|
+
puts "after_caller output: #{output}"
|
33
33
|
output * 2
|
34
34
|
end
|
35
35
|
.tap do |tree|
|
@@ -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
|
-
)
|
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
|
-
)
|
28
|
-
)
|
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
|
-
)
|
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
|
-
)
|
28
|
-
)
|
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,85 @@
|
|
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
|
+
if hookable
|
48
|
+
prepend Hooks::Matcher
|
49
|
+
prepend Hooks::Caller
|
50
|
+
end
|
51
|
+
|
52
|
+
if matcher
|
53
|
+
define_method(:match?) do |*inputs, **options|
|
54
|
+
matcher.call(*inputs, **options) do |*inputs, **options|
|
55
|
+
super(*inputs, **options)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
if caller
|
61
|
+
define_method(:call) do |*inputs, **options|
|
62
|
+
caller.call(*inputs, **options) do |*inputs, **options|
|
63
|
+
super(*inputs, **options)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
if terminator
|
69
|
+
define_method(:terminate?) do |output, *inputs, **options|
|
70
|
+
terminator.call(output, *inputs, **options) do |output, *inputs, **options|
|
71
|
+
super(output, *inputs, **options)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
|
80
|
+
def validate(matcher:, caller:, terminator:)
|
81
|
+
raise ::CallableTree::Error, 'Not implemented'
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
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,110 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CallableTree
|
4
|
+
module Node
|
5
|
+
module Hooks
|
6
|
+
module Caller
|
7
|
+
def self.included(_subclass)
|
8
|
+
raise ::CallableTree::Error, "#{self} must be prepended"
|
9
|
+
end
|
10
|
+
|
11
|
+
def before_call(&block)
|
12
|
+
clone.before_call!(&block)
|
13
|
+
end
|
14
|
+
|
15
|
+
def before_call!(&block)
|
16
|
+
before_caller_callbacks << block
|
17
|
+
self
|
18
|
+
end
|
19
|
+
|
20
|
+
def around_call(&block)
|
21
|
+
clone.around_call!(&block)
|
22
|
+
end
|
23
|
+
|
24
|
+
def around_call!(&block)
|
25
|
+
around_caller_callbacks << block
|
26
|
+
self
|
27
|
+
end
|
28
|
+
|
29
|
+
def after_call(&block)
|
30
|
+
clone.after_call!(&block)
|
31
|
+
end
|
32
|
+
|
33
|
+
def after_call!(&block)
|
34
|
+
after_caller_callbacks << block
|
35
|
+
self
|
36
|
+
end
|
37
|
+
|
38
|
+
alias before_caller before_call
|
39
|
+
alias before_caller! before_call!
|
40
|
+
alias around_caller around_call
|
41
|
+
alias around_caller! around_call!
|
42
|
+
alias after_caller after_call
|
43
|
+
alias after_caller! after_call!
|
44
|
+
|
45
|
+
def call(*inputs, **options)
|
46
|
+
input_head, *input_tail = inputs
|
47
|
+
|
48
|
+
input_head = before_caller_callbacks.reduce(input_head) do |input_head, callable|
|
49
|
+
callable.call(input_head, *input_tail, **options, _node_: self)
|
50
|
+
end
|
51
|
+
|
52
|
+
output =
|
53
|
+
if around_caller_callbacks.empty?
|
54
|
+
super(input_head, *input_tail, **options)
|
55
|
+
else
|
56
|
+
around_caller_callbacks_head, *around_caller_callbacks_tail = around_caller_callbacks
|
57
|
+
caller = proc { super(input_head, *input_tail, **options) }
|
58
|
+
|
59
|
+
output =
|
60
|
+
around_caller_callbacks_head
|
61
|
+
.call(
|
62
|
+
input_head,
|
63
|
+
*input_tail,
|
64
|
+
**options,
|
65
|
+
_node_: self
|
66
|
+
) { caller.call }
|
67
|
+
|
68
|
+
around_caller_callbacks_tail.reduce(output) do |output, callable|
|
69
|
+
callable.call(
|
70
|
+
input_head,
|
71
|
+
*input_tail,
|
72
|
+
**options,
|
73
|
+
_node_: self
|
74
|
+
) { output }
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
after_caller_callbacks.reduce(output) do |output, callable|
|
79
|
+
callable.call(output, **options, _node_: self)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def before_caller_callbacks
|
84
|
+
@before_caller_callbacks ||= []
|
85
|
+
end
|
86
|
+
|
87
|
+
def around_caller_callbacks
|
88
|
+
@around_caller_callbacks ||= []
|
89
|
+
end
|
90
|
+
|
91
|
+
def after_caller_callbacks
|
92
|
+
@after_caller_callbacks ||= []
|
93
|
+
end
|
94
|
+
|
95
|
+
private
|
96
|
+
|
97
|
+
attr_writer :before_caller_callbacks, :around_caller_callbacks, :after_caller_callbacks
|
98
|
+
|
99
|
+
def initialize_copy(_node)
|
100
|
+
super
|
101
|
+
self.before_caller_callbacks = before_caller_callbacks.map(&:itself)
|
102
|
+
self.around_caller_callbacks = around_caller_callbacks.map(&:itself)
|
103
|
+
self.after_caller_callbacks = after_caller_callbacks.map(&:itself)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
Call = Caller # backward compatibility
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CallableTree
|
4
|
+
module Node
|
5
|
+
module Hooks
|
6
|
+
module Matcher
|
7
|
+
def self.included(_subclass)
|
8
|
+
raise ::CallableTree::Error, "#{self} must be prepended"
|
9
|
+
end
|
10
|
+
|
11
|
+
def before_matcher(&block)
|
12
|
+
clone.before_matcher!(&block)
|
13
|
+
end
|
14
|
+
|
15
|
+
def before_matcher!(&block)
|
16
|
+
before_matcher_callbacks << block
|
17
|
+
self
|
18
|
+
end
|
19
|
+
|
20
|
+
def around_matcher(&block)
|
21
|
+
clone.around_matcher!(&block)
|
22
|
+
end
|
23
|
+
|
24
|
+
def around_matcher!(&block)
|
25
|
+
around_matcher_callbacks << block
|
26
|
+
self
|
27
|
+
end
|
28
|
+
|
29
|
+
def after_matcher(&block)
|
30
|
+
clone.after_matcher!(&block)
|
31
|
+
end
|
32
|
+
|
33
|
+
def after_matcher!(&block)
|
34
|
+
after_matcher_callbacks << block
|
35
|
+
self
|
36
|
+
end
|
37
|
+
|
38
|
+
def match?(*inputs, **options)
|
39
|
+
input_head, *input_tail = inputs
|
40
|
+
|
41
|
+
input_head = before_matcher_callbacks.reduce(input_head) do |input_head, callable|
|
42
|
+
callable.call(input_head, *input_tail, **options, _node_: self)
|
43
|
+
end
|
44
|
+
|
45
|
+
matched =
|
46
|
+
if around_matcher_callbacks.empty?
|
47
|
+
super(input_head, *input_tail, **options)
|
48
|
+
else
|
49
|
+
around_matcher_callbacks_head, *around_matcher_callbacks_tail = around_matcher_callbacks
|
50
|
+
matcher = proc { super(input_head, *input_tail, **options) }
|
51
|
+
|
52
|
+
matched =
|
53
|
+
around_matcher_callbacks_head
|
54
|
+
.call(
|
55
|
+
input_head,
|
56
|
+
*input_tail,
|
57
|
+
**options,
|
58
|
+
_node_: self
|
59
|
+
) { matcher.call }
|
60
|
+
|
61
|
+
around_matcher_callbacks_tail.reduce(matched) do |matched, callable|
|
62
|
+
callable.call(
|
63
|
+
input_head,
|
64
|
+
*input_tail,
|
65
|
+
**options,
|
66
|
+
_node_: self
|
67
|
+
) { matched }
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
after_matcher_callbacks.reduce(matched) do |matched, callable|
|
72
|
+
callable.call(matched, **options, _node_: self)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def before_matcher_callbacks
|
77
|
+
@before_matcher_callbacks ||= []
|
78
|
+
end
|
79
|
+
|
80
|
+
def around_matcher_callbacks
|
81
|
+
@around_matcher_callbacks ||= []
|
82
|
+
end
|
83
|
+
|
84
|
+
def after_matcher_callbacks
|
85
|
+
@after_matcher_callbacks ||= []
|
86
|
+
end
|
87
|
+
|
88
|
+
private
|
89
|
+
|
90
|
+
attr_writer :before_matcher_callbacks, :around_matcher_callbacks, :after_matcher_callbacks
|
91
|
+
|
92
|
+
def initialize_copy(_node)
|
93
|
+
super
|
94
|
+
self.before_matcher_callbacks = before_matcher_callbacks.map(&:itself)
|
95
|
+
self.around_matcher_callbacks = around_matcher_callbacks.map(&:itself)
|
96
|
+
self.after_matcher_callbacks = after_matcher_callbacks.map(&:itself)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
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
|
@@ -98,6 +98,10 @@ module CallableTree
|
|
98
98
|
end
|
99
99
|
end
|
100
100
|
|
101
|
+
alias seekable? seek?
|
102
|
+
alias seekable seek
|
103
|
+
alias seekable! seek!
|
104
|
+
|
101
105
|
def broadcast?
|
102
106
|
strategy.is_a?(Strategy::Broadcast)
|
103
107
|
end
|
@@ -118,6 +122,10 @@ module CallableTree
|
|
118
122
|
end
|
119
123
|
end
|
120
124
|
|
125
|
+
alias broadcastable? broadcast?
|
126
|
+
alias broadcastable broadcast
|
127
|
+
alias broadcastable! broadcast!
|
128
|
+
|
121
129
|
def compose?
|
122
130
|
strategy.is_a?(Strategy::Compose)
|
123
131
|
end
|
@@ -138,6 +146,10 @@ module CallableTree
|
|
138
146
|
end
|
139
147
|
end
|
140
148
|
|
149
|
+
alias composable? compose?
|
150
|
+
alias composable compose
|
151
|
+
alias composable! compose!
|
152
|
+
|
141
153
|
def outline(&block)
|
142
154
|
key = block ? block.call(self) : identity
|
143
155
|
value = child_nodes.reduce({}) { |memo, node| memo.merge!(node.outline(&block)) }
|
data/lib/callable_tree.rb
CHANGED
@@ -7,7 +7,8 @@ end
|
|
7
7
|
require 'forwardable'
|
8
8
|
require_relative 'callable_tree/version'
|
9
9
|
require_relative 'callable_tree/node'
|
10
|
-
require_relative 'callable_tree/node/hooks/
|
10
|
+
require_relative 'callable_tree/node/hooks/matcher'
|
11
|
+
require_relative 'callable_tree/node/hooks/caller'
|
11
12
|
require_relative 'callable_tree/node/internal/strategy'
|
12
13
|
require_relative 'callable_tree/node/internal/strategy/broadcast'
|
13
14
|
require_relative 'callable_tree/node/internal/strategy/seek'
|
@@ -15,4 +16,7 @@ require_relative 'callable_tree/node/internal/strategy/compose'
|
|
15
16
|
require_relative 'callable_tree/node/external/verbose'
|
16
17
|
require_relative 'callable_tree/node/external'
|
17
18
|
require_relative 'callable_tree/node/internal'
|
19
|
+
require_relative 'callable_tree/node/builder'
|
20
|
+
require_relative 'callable_tree/node/internal/builder'
|
21
|
+
require_relative 'callable_tree/node/external/builder'
|
18
22
|
require_relative 'callable_tree/node/root'
|