callable_tree 0.3.5 → 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/CHANGELOG.md +5 -0
- data/Gemfile.lock +1 -1
- data/README.md +15 -15
- data/examples/builder/{hooks-call.rb → hooks-caller.rb} +7 -7
- data/examples/builder/internal-seekable.rb +69 -73
- data/examples/builder/logging.rb +126 -0
- data/examples/{hooks-call.rb → hooks-caller.rb} +8 -8
- data/lib/callable_tree/node/builder.rb +4 -1
- data/lib/callable_tree/node/external/builder.rb +1 -1
- 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.rb +9 -9
- data/lib/callable_tree/node/root.rb +2 -1
- data/lib/callable_tree/version.rb +1 -1
- data/lib/callable_tree.rb +2 -1
- metadata +8 -6
- data/lib/callable_tree/node/hooks/call.rb +0 -81
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2a83d353d4049c06aa0a0d5f18f56c5c6d0d909cd4a54f6bbcba7faf4e835c0f
|
4
|
+
data.tar.gz: ab803f4e8b613a0ceb5e4d3ca21d38e1a5cf2a238db61384c0ec85b437fd7d73
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 27dd59b36d4ebc99395df901a900d72510928f5f4a9603405b83f54d0566652fda2253bcda7bf6efee1ad0363919c5ec7bb63a1ec1e0efc488e656d6ff1bce3a
|
7
|
+
data.tar.gz: 3029f92901053688715cffce367d0e44f01402743413dfd38dc52c6c63221094fe2d3774cf2b1b98d66b84dd6837c8d6e6430c228ce3f196e60f9222286a3a56
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,10 @@
|
|
1
1
|
## [Unreleased]
|
2
2
|
|
3
|
+
## [0.3.6] - 2022-03-29
|
4
|
+
|
5
|
+
- (Experimental) Add `CallableTree::Node::Hooks::Matcher`.
|
6
|
+
Using this together with `CallableTree::Node::Hooks::Caller` helps to output logs. See `examples/builder/logging.rb` for details.
|
7
|
+
|
3
8
|
## [0.3.5] - 2022-03-20
|
4
9
|
|
5
10
|
- Add `CallableTree::Node::Internal#seekable?` as an alias for `CallableTree::Node::Internal#seek?`.
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -568,20 +568,20 @@ Run `examples/logging.rb`:
|
|
568
568
|
---
|
569
569
|
```
|
570
570
|
|
571
|
-
#### `CallableTree::Node::Hooks::
|
571
|
+
#### `CallableTree::Node::Hooks::Caller` (experimental)
|
572
572
|
|
573
573
|
`examples/hooks-call.rb`:
|
574
574
|
```ruby
|
575
575
|
module Node
|
576
576
|
class HooksSample
|
577
577
|
include CallableTree::Node::Internal
|
578
|
-
prepend CallableTree::Node::Hooks::
|
578
|
+
prepend CallableTree::Node::Hooks::Caller
|
579
579
|
end
|
580
580
|
end
|
581
581
|
|
582
582
|
Node::HooksSample.new
|
583
|
-
.
|
584
|
-
puts "
|
583
|
+
.before_caller do |input, **_options|
|
584
|
+
puts "before_caller input: #{input}";
|
585
585
|
input + 1
|
586
586
|
end
|
587
587
|
.append(
|
@@ -591,14 +591,14 @@ Node::HooksSample.new
|
|
591
591
|
input * 2
|
592
592
|
end
|
593
593
|
)
|
594
|
-
.
|
595
|
-
puts "
|
594
|
+
.around_caller do |input, **_options, &block|
|
595
|
+
puts "around_caller input: #{input}"
|
596
596
|
output = block.call
|
597
|
-
puts "
|
597
|
+
puts "around_caller output: #{output}"
|
598
598
|
output * input
|
599
599
|
end
|
600
|
-
.
|
601
|
-
puts "
|
600
|
+
.after_caller do |output, **_options|
|
601
|
+
puts "after_caller output: #{output}"
|
602
602
|
output * 2
|
603
603
|
end
|
604
604
|
.tap do |tree|
|
@@ -608,14 +608,14 @@ Node::HooksSample.new
|
|
608
608
|
end
|
609
609
|
```
|
610
610
|
|
611
|
-
Run `examples/hooks-
|
611
|
+
Run `examples/hooks-caller.rb`:
|
612
612
|
```sh
|
613
|
-
% ruby examples/hooks-
|
614
|
-
|
613
|
+
% ruby examples/hooks-caller.rb
|
614
|
+
before_caller input: 1
|
615
615
|
external input: 2
|
616
|
-
|
617
|
-
|
618
|
-
|
616
|
+
around_caller input: 2
|
617
|
+
around_caller output: 4
|
618
|
+
after_caller output: 8
|
619
619
|
result: 16
|
620
620
|
```
|
621
621
|
|
@@ -10,8 +10,8 @@ Root =
|
|
10
10
|
|
11
11
|
Root
|
12
12
|
.new
|
13
|
-
.
|
14
|
-
puts "
|
13
|
+
.before_caller do |input, **_options|
|
14
|
+
puts "before_caller input: #{input}"
|
15
15
|
input + 1
|
16
16
|
end
|
17
17
|
.append(
|
@@ -21,14 +21,14 @@ Root
|
|
21
21
|
input * 2
|
22
22
|
end
|
23
23
|
)
|
24
|
-
.
|
25
|
-
puts "
|
24
|
+
.around_caller do |input, **_options, &block|
|
25
|
+
puts "around_caller input: #{input}"
|
26
26
|
output = block.call
|
27
|
-
puts "
|
27
|
+
puts "around_caller output: #{output}"
|
28
28
|
output * input
|
29
29
|
end
|
30
|
-
.
|
31
|
-
puts "
|
30
|
+
.after_caller do |output, **_options|
|
31
|
+
puts "after_caller output: #{output}"
|
32
32
|
output * 2
|
33
33
|
end
|
34
34
|
.tap do |tree|
|
@@ -4,89 +4,85 @@ require 'callable_tree'
|
|
4
4
|
require 'json'
|
5
5
|
require 'rexml/document'
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
File.extname(input) == '.json'
|
13
|
-
end
|
14
|
-
.caller do |input, **options, &block|
|
15
|
-
File.open(input) do |file|
|
16
|
-
json = ::JSON.load(file)
|
17
|
-
# The following block call is equivalent to calling `super` in the class style.
|
18
|
-
block.call(json, **options)
|
19
|
-
end
|
20
|
-
end
|
21
|
-
.terminator do
|
22
|
-
true
|
23
|
-
end
|
24
|
-
.build
|
7
|
+
JSONParser =
|
8
|
+
CallableTree::Node::Internal::Builder
|
9
|
+
.new
|
10
|
+
.matcher do |input, **_options|
|
11
|
+
File.extname(input) == '.json'
|
25
12
|
end
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
.matcher do |input, **_options|
|
33
|
-
File.extname(input) == '.xml'
|
34
|
-
end
|
35
|
-
.caller do |input, **options, &block|
|
36
|
-
File.open(input) do |file|
|
37
|
-
# The following block call is equivalent to calling `super` in the class style.
|
38
|
-
block.call(REXML::Document.new(file), **options)
|
39
|
-
end
|
40
|
-
end
|
41
|
-
.terminator do
|
42
|
-
true
|
43
|
-
end
|
44
|
-
.build
|
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
|
45
19
|
end
|
46
|
-
|
20
|
+
.terminator do
|
21
|
+
true
|
22
|
+
end
|
23
|
+
.build
|
47
24
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
end
|
60
|
-
.build
|
25
|
+
XMLParser =
|
26
|
+
CallableTree::Node::Internal::Builder
|
27
|
+
.new
|
28
|
+
.matcher do |input, **_options|
|
29
|
+
File.extname(input) == '.xml'
|
30
|
+
end
|
31
|
+
.caller do |input, **options, &block|
|
32
|
+
File.open(input) do |file|
|
33
|
+
# The following block call is equivalent to calling `super` in the class style.
|
34
|
+
block.call(REXML::Document.new(file), **options)
|
35
|
+
end
|
61
36
|
end
|
37
|
+
.terminator do
|
38
|
+
true
|
39
|
+
end
|
40
|
+
.build
|
41
|
+
|
42
|
+
def build_json_scraper(type)
|
43
|
+
CallableTree::Node::External::Builder
|
44
|
+
.new
|
45
|
+
.matcher do |input, **_options|
|
46
|
+
!!input[type.to_s]
|
47
|
+
end
|
48
|
+
.caller do |input, **_options|
|
49
|
+
input[type.to_s]
|
50
|
+
.map { |element| [element['name'], element['emoji']] }
|
51
|
+
.to_h
|
52
|
+
end
|
53
|
+
.build
|
62
54
|
end
|
63
55
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
.
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
56
|
+
AnimalsJSONScraper = build_json_scraper(:animals)
|
57
|
+
FruitsJSONScraper = build_json_scraper(:fruits)
|
58
|
+
|
59
|
+
def build_xml_scraper(type)
|
60
|
+
CallableTree::Node::External::Builder
|
61
|
+
.new
|
62
|
+
.matcher do |input, **_options|
|
63
|
+
!input.get_elements("//#{type}").empty?
|
64
|
+
end
|
65
|
+
.caller do |input, **_options|
|
66
|
+
input
|
67
|
+
.get_elements("//#{type}")
|
68
|
+
.first
|
69
|
+
.map { |element| [element['name'], element['emoji']] }
|
70
|
+
.to_h
|
71
|
+
end
|
72
|
+
.build
|
80
73
|
end
|
81
74
|
|
75
|
+
AnimalsXMLScraper = build_xml_scraper(:animals)
|
76
|
+
FruitsXMLScraper = build_xml_scraper(:fruits)
|
77
|
+
|
82
78
|
tree = CallableTree::Node::Root.new.seekable.append(
|
83
|
-
JSONParser.
|
84
|
-
|
85
|
-
|
79
|
+
JSONParser.new.seekable.append(
|
80
|
+
AnimalsJSONScraper.new,
|
81
|
+
FruitsJSONScraper.new
|
86
82
|
),
|
87
|
-
XMLParser.
|
88
|
-
|
89
|
-
|
83
|
+
XMLParser.new.seekable.append(
|
84
|
+
AnimalsXMLScraper.new,
|
85
|
+
FruitsXMLScraper.new
|
90
86
|
)
|
91
87
|
)
|
92
88
|
|
@@ -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|
|
@@ -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
|
@@ -98,9 +98,9 @@ module CallableTree
|
|
98
98
|
end
|
99
99
|
end
|
100
100
|
|
101
|
-
|
102
|
-
|
103
|
-
|
101
|
+
alias seekable? seek?
|
102
|
+
alias seekable seek
|
103
|
+
alias seekable! seek!
|
104
104
|
|
105
105
|
def broadcast?
|
106
106
|
strategy.is_a?(Strategy::Broadcast)
|
@@ -122,9 +122,9 @@ module CallableTree
|
|
122
122
|
end
|
123
123
|
end
|
124
124
|
|
125
|
-
|
126
|
-
|
127
|
-
|
125
|
+
alias broadcastable? broadcast?
|
126
|
+
alias broadcastable broadcast
|
127
|
+
alias broadcastable! broadcast!
|
128
128
|
|
129
129
|
def compose?
|
130
130
|
strategy.is_a?(Strategy::Compose)
|
@@ -146,9 +146,9 @@ module CallableTree
|
|
146
146
|
end
|
147
147
|
end
|
148
148
|
|
149
|
-
|
150
|
-
|
151
|
-
|
149
|
+
alias composable? compose?
|
150
|
+
alias composable compose
|
151
|
+
alias composable! compose!
|
152
152
|
|
153
153
|
def outline(&block)
|
154
154
|
key = block ? block.call(self) : identity
|
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'
|
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.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- jsmmr
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-03-
|
11
|
+
date: 2022-03-29 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
|
@@ -33,16 +33,17 @@ files:
|
|
33
33
|
- bin/console
|
34
34
|
- bin/setup
|
35
35
|
- callable_tree.gemspec
|
36
|
-
- examples/builder/hooks-
|
36
|
+
- examples/builder/hooks-caller.rb
|
37
37
|
- examples/builder/internal-broadcastable.rb
|
38
38
|
- examples/builder/internal-composable.rb
|
39
39
|
- examples/builder/internal-seekable.rb
|
40
|
+
- examples/builder/logging.rb
|
40
41
|
- examples/docs/animals.json
|
41
42
|
- examples/docs/animals.xml
|
42
43
|
- examples/docs/fruits.json
|
43
44
|
- examples/docs/fruits.xml
|
44
45
|
- examples/external-verbosify.rb
|
45
|
-
- examples/hooks-
|
46
|
+
- examples/hooks-caller.rb
|
46
47
|
- examples/identity.rb
|
47
48
|
- examples/internal-broadcastable.rb
|
48
49
|
- examples/internal-composable.rb
|
@@ -54,7 +55,8 @@ files:
|
|
54
55
|
- lib/callable_tree/node/external.rb
|
55
56
|
- lib/callable_tree/node/external/builder.rb
|
56
57
|
- lib/callable_tree/node/external/verbose.rb
|
57
|
-
- lib/callable_tree/node/hooks/
|
58
|
+
- lib/callable_tree/node/hooks/caller.rb
|
59
|
+
- lib/callable_tree/node/hooks/matcher.rb
|
58
60
|
- lib/callable_tree/node/internal.rb
|
59
61
|
- lib/callable_tree/node/internal/builder.rb
|
60
62
|
- lib/callable_tree/node/internal/strategy.rb
|
@@ -69,7 +71,7 @@ licenses:
|
|
69
71
|
metadata:
|
70
72
|
homepage_uri: https://github.com/jsmmr/ruby_callable_tree
|
71
73
|
source_code_uri: https://github.com/jsmmr/ruby_callable_tree
|
72
|
-
changelog_uri: https://github.com/jsmmr/ruby_callable_tree/blob/v0.3.
|
74
|
+
changelog_uri: https://github.com/jsmmr/ruby_callable_tree/blob/v0.3.6/CHANGELOG.md
|
73
75
|
post_install_message:
|
74
76
|
rdoc_options: []
|
75
77
|
require_paths:
|
@@ -1,81 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module CallableTree
|
4
|
-
module Node
|
5
|
-
module Hooks
|
6
|
-
module Call
|
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_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_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_callbacks << block
|
35
|
-
self
|
36
|
-
end
|
37
|
-
|
38
|
-
def call(*inputs, **options)
|
39
|
-
input_head, *input_tail = inputs
|
40
|
-
|
41
|
-
input_head = before_callbacks.reduce(input_head) do |input_head, callable|
|
42
|
-
callable.call(input_head, *input_tail, self, **options)
|
43
|
-
end
|
44
|
-
|
45
|
-
output = super(input_head, *input_tail, **options)
|
46
|
-
|
47
|
-
output = around_callbacks.reduce(output) do |output, callable|
|
48
|
-
callable.call(input_head, *input_tail, self, **options) { output }
|
49
|
-
end
|
50
|
-
|
51
|
-
after_callbacks.reduce(output) do |output, callable|
|
52
|
-
callable.call(output, self, **options)
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
def before_callbacks
|
57
|
-
@before_callbacks ||= []
|
58
|
-
end
|
59
|
-
|
60
|
-
def around_callbacks
|
61
|
-
@around_callbacks ||= []
|
62
|
-
end
|
63
|
-
|
64
|
-
def after_callbacks
|
65
|
-
@after_callbacks ||= []
|
66
|
-
end
|
67
|
-
|
68
|
-
private
|
69
|
-
|
70
|
-
attr_writer :before_callbacks, :around_callbacks, :after_callbacks
|
71
|
-
|
72
|
-
def initialize_copy(_node)
|
73
|
-
super
|
74
|
-
self.before_callbacks = before_callbacks.map(&:itself)
|
75
|
-
self.around_callbacks = around_callbacks.map(&:itself)
|
76
|
-
self.after_callbacks = after_callbacks.map(&:itself)
|
77
|
-
end
|
78
|
-
end
|
79
|
-
end
|
80
|
-
end
|
81
|
-
end
|