callable_tree 0.2.2 → 0.3.2
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 +2 -2
- data/.github/workflows/codeql-analysis.yml +70 -0
- data/.ruby-version +1 -1
- data/CHANGELOG.md +34 -0
- data/Gemfile.lock +7 -7
- data/README.md +30 -29
- data/examples/external-verbosify.rb +11 -9
- data/examples/hooks-call.rb +9 -6
- data/examples/identity.rb +11 -9
- data/examples/internal-broadcast.rb +6 -4
- data/examples/internal-compose.rb +2 -0
- data/examples/internal-seek.rb +11 -9
- data/examples/logging.rb +21 -19
- data/lib/callable_tree/node/external/verbose.rb +3 -2
- data/lib/callable_tree/node/external.rb +4 -0
- data/lib/callable_tree/node/hooks/call.rb +19 -5
- data/lib/callable_tree/node/internal/strategy/broadcast.rb +4 -2
- data/lib/callable_tree/node/internal/strategy/compose.rb +8 -4
- data/lib/callable_tree/node/internal/strategy/seek.rb +6 -4
- data/lib/callable_tree/node/internal/strategy.rb +29 -0
- data/lib/callable_tree/node/internal.rb +66 -21
- data/lib/callable_tree/node.rb +8 -4
- data/lib/callable_tree/version.rb +1 -1
- data/lib/callable_tree.rb +1 -0
- metadata +6 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5a506dec2678a69b014cff69b6cc4fd94e22b1f7f5027e9230727720c8dc049e
|
|
4
|
+
data.tar.gz: 3b7ee0419139ef24f40f8b0714cbd19551568967d0170a4b550a84f528811da4
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b84af5f3ae12941eabdb1cdbc159d9a3f424388bffab74c2704d5507a875c924ae637b2b868194244d2530bcbd8bf5895118e42f7a79c91f901854896d686eb5
|
|
7
|
+
data.tar.gz: 816f558c0118c57bda18c3b69fef45240c9de5e87a1acea0bcf1f9448e0c67e34a7de613292796635f8e5c16d1835c2ba4bdef959939c44a6358bce94197a82a
|
data/.github/workflows/build.yml
CHANGED
|
@@ -5,13 +5,13 @@ jobs:
|
|
|
5
5
|
runs-on: ubuntu-latest
|
|
6
6
|
strategy:
|
|
7
7
|
matrix:
|
|
8
|
-
ruby: ['2.4', '2.5', '2.6', '2.7', '3.0']
|
|
8
|
+
ruby: ['2.4', '2.5', '2.6', '2.7', '3.0', '3.1']
|
|
9
9
|
steps:
|
|
10
10
|
- uses: actions/checkout@v2
|
|
11
11
|
- uses: ruby/setup-ruby@v1
|
|
12
12
|
with:
|
|
13
13
|
ruby-version: ${{ matrix.ruby }}
|
|
14
|
-
- run: gem install bundler:2.
|
|
14
|
+
- run: gem install bundler:2.3.3
|
|
15
15
|
- uses: actions/cache@v2
|
|
16
16
|
with:
|
|
17
17
|
path: vendor/bundle
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# For most projects, this workflow file will not need changing; you simply need
|
|
2
|
+
# to commit it to your repository.
|
|
3
|
+
#
|
|
4
|
+
# You may wish to alter this file to override the set of languages analyzed,
|
|
5
|
+
# or to provide custom queries or build logic.
|
|
6
|
+
#
|
|
7
|
+
# ******** NOTE ********
|
|
8
|
+
# We have attempted to detect the languages in your repository. Please check
|
|
9
|
+
# the `language` matrix defined below to confirm you have the correct set of
|
|
10
|
+
# supported CodeQL languages.
|
|
11
|
+
#
|
|
12
|
+
name: "CodeQL"
|
|
13
|
+
|
|
14
|
+
on:
|
|
15
|
+
push:
|
|
16
|
+
branches: [ main, develop ]
|
|
17
|
+
pull_request:
|
|
18
|
+
# The branches below must be a subset of the branches above
|
|
19
|
+
branches: [ main, develop ]
|
|
20
|
+
schedule:
|
|
21
|
+
- cron: '35 15 * * 0'
|
|
22
|
+
|
|
23
|
+
jobs:
|
|
24
|
+
analyze:
|
|
25
|
+
name: Analyze
|
|
26
|
+
runs-on: ubuntu-latest
|
|
27
|
+
permissions:
|
|
28
|
+
actions: read
|
|
29
|
+
contents: read
|
|
30
|
+
security-events: write
|
|
31
|
+
|
|
32
|
+
strategy:
|
|
33
|
+
fail-fast: false
|
|
34
|
+
matrix:
|
|
35
|
+
language: [ 'ruby' ]
|
|
36
|
+
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
|
|
37
|
+
# Learn more about CodeQL language support at https://git.io/codeql-language-support
|
|
38
|
+
|
|
39
|
+
steps:
|
|
40
|
+
- name: Checkout repository
|
|
41
|
+
uses: actions/checkout@v2
|
|
42
|
+
|
|
43
|
+
# Initializes the CodeQL tools for scanning.
|
|
44
|
+
- name: Initialize CodeQL
|
|
45
|
+
uses: github/codeql-action/init@v1
|
|
46
|
+
with:
|
|
47
|
+
languages: ${{ matrix.language }}
|
|
48
|
+
# If you wish to specify custom queries, you can do so here or in a config file.
|
|
49
|
+
# By default, queries listed here will override any specified in a config file.
|
|
50
|
+
# Prefix the list here with "+" to use these queries and those in the config file.
|
|
51
|
+
# queries: ./path/to/local/query, your-org/your-repo/queries@main
|
|
52
|
+
|
|
53
|
+
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
|
54
|
+
# If this step fails, then you should remove it and run the build manually (see below)
|
|
55
|
+
- name: Autobuild
|
|
56
|
+
uses: github/codeql-action/autobuild@v1
|
|
57
|
+
|
|
58
|
+
# ℹ️ Command-line programs to run using the OS shell.
|
|
59
|
+
# 📚 https://git.io/JvXDl
|
|
60
|
+
|
|
61
|
+
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
|
|
62
|
+
# and modify them (or add more) to build your code if your project
|
|
63
|
+
# uses a compiled language
|
|
64
|
+
|
|
65
|
+
#- run: |
|
|
66
|
+
# make bootstrap
|
|
67
|
+
# make release
|
|
68
|
+
|
|
69
|
+
- name: Perform CodeQL Analysis
|
|
70
|
+
uses: github/codeql-action/analyze@v1
|
data/.ruby-version
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
3.0
|
|
1
|
+
3.1.0
|
data/CHANGELOG.md
CHANGED
|
@@ -1,16 +1,49 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
## [0.3.2] - 2022-02-05
|
|
4
|
+
|
|
5
|
+
- Change `CallableTree::Node::Hooks::Call#before_call` to return a new instance.
|
|
6
|
+
To keep the same behavior as the older version, use `CallableTree::Node::Hooks::Call#before_call!` that makes destructive change.
|
|
7
|
+
- Change `CallableTree::Node::Hooks::Call#around_call` to return a new instance.
|
|
8
|
+
To keep the same behavior as the older version, use `CallableTree::Node::Hooks::Call#around_call!` that makes destructive change.
|
|
9
|
+
- Change `CallableTree::Node::Hooks::Call#after_call` to return a new instance.
|
|
10
|
+
To keep the same behavior as the older version, use `CallableTree::Node::Hooks::Call#after_call!` that makes destructive change.
|
|
11
|
+
|
|
12
|
+
## [0.3.1] - 2022-01-10
|
|
13
|
+
|
|
14
|
+
- Add `CallableTree::Node::Internal#seek?` to check whether the node's strategy is `seek` or not.
|
|
15
|
+
- Add `CallableTree::Node::Internal#broadcast?` to check whether the node's strategy is `broadcast` or not.
|
|
16
|
+
- Add `CallableTree::Node::Internal#compose?` to check whether the node's strategy is `compose` or not.
|
|
17
|
+
|
|
18
|
+
## [0.3.0] - 2021-12-27
|
|
19
|
+
|
|
20
|
+
- Change `CallableTree::Node#match?` to accept inputs to the node as variable length arguments.
|
|
21
|
+
- Change `CallableTree::Node#call` to accept inputs to the node as variable length arguments.
|
|
22
|
+
- Change `CallableTree::Node#terminate?` to accept inputs to the node as variable length arguments, after the `output` argument.
|
|
23
|
+
- Add `CallableTree::Node::Internal#[]` to return the child node using `index`.
|
|
24
|
+
- Change `CallableTree::Node::Internal#children` to return a new array including child nodes of the node.
|
|
25
|
+
- Add `CallableTree::Node::Internal#children!` to return destructively changeable array including child nodes of the node.
|
|
26
|
+
|
|
27
|
+
## [0.2.3] - 2021-11-07
|
|
28
|
+
|
|
29
|
+
- Add `CallableTree::Node::Internal#shake` to recursively execute `CallableTree::Node::Internal#reject`, including child nodes. The child nodes that are empty because their children have been rejected will also be rejected.
|
|
30
|
+
- Add `CallableTree::Node::Internal#shake!` that make destructive change.
|
|
31
|
+
- Add `CallableTree::Node#outline` that may be useful for writing the specs.
|
|
32
|
+
|
|
3
33
|
## [0.2.2] - 2021-10-24
|
|
34
|
+
|
|
4
35
|
- Add `CallableTree::Node::Internal#reject` to return a new node instance without rejected child nodes.
|
|
5
36
|
- Add `CallableTree::Node::Internal#reject!` to destructively reject child nodes.
|
|
6
37
|
|
|
7
38
|
## [0.2.1] - 2021-07-24
|
|
39
|
+
|
|
8
40
|
- Add `CallableTree::Node#root?`.
|
|
9
41
|
- Add `CallableTree::Node::Internal#seek!` that make destructive change.
|
|
10
42
|
- Add `CallableTree::Node::Internal#broadcast!` that make destructive change.
|
|
11
43
|
- Add `CallableTree::Node::Internal#compose!` that make destructive change.
|
|
12
44
|
|
|
13
45
|
## [0.2.0] - 2021-06-15
|
|
46
|
+
|
|
14
47
|
- Change `CallableTree::Node::Internal#append` to return a new instance.
|
|
15
48
|
To keep the same behavior as the older version, use `CallableTree::Node::External#append!` that make destructive change.
|
|
16
49
|
- Remove `CallableTree::Node::Internal#<<`. Use `CallableTree::Node::External#append!` instead.
|
|
@@ -18,6 +51,7 @@
|
|
|
18
51
|
To keep the same behavior as the older version, use `CallableTree::Node::External#verbosify!` that make destructive change.
|
|
19
52
|
|
|
20
53
|
## [0.1.3] - 2021-06-12
|
|
54
|
+
|
|
21
55
|
- Minor improvements
|
|
22
56
|
|
|
23
57
|
## [0.1.2] - 2021-05-29
|
data/Gemfile.lock
CHANGED
|
@@ -1,26 +1,26 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
callable_tree (0.
|
|
4
|
+
callable_tree (0.3.2)
|
|
5
5
|
|
|
6
6
|
GEM
|
|
7
7
|
remote: https://rubygems.org/
|
|
8
8
|
specs:
|
|
9
|
-
diff-lcs (1.
|
|
9
|
+
diff-lcs (1.5.0)
|
|
10
10
|
rake (13.0.6)
|
|
11
11
|
rspec (3.10.0)
|
|
12
12
|
rspec-core (~> 3.10.0)
|
|
13
13
|
rspec-expectations (~> 3.10.0)
|
|
14
14
|
rspec-mocks (~> 3.10.0)
|
|
15
|
-
rspec-core (3.10.
|
|
15
|
+
rspec-core (3.10.2)
|
|
16
16
|
rspec-support (~> 3.10.0)
|
|
17
|
-
rspec-expectations (3.10.
|
|
17
|
+
rspec-expectations (3.10.2)
|
|
18
18
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
19
19
|
rspec-support (~> 3.10.0)
|
|
20
|
-
rspec-mocks (3.10.
|
|
20
|
+
rspec-mocks (3.10.3)
|
|
21
21
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
22
22
|
rspec-support (~> 3.10.0)
|
|
23
|
-
rspec-support (3.10.
|
|
23
|
+
rspec-support (3.10.3)
|
|
24
24
|
|
|
25
25
|
PLATFORMS
|
|
26
26
|
x86_64-darwin-19
|
|
@@ -32,4 +32,4 @@ DEPENDENCIES
|
|
|
32
32
|
rspec (~> 3.0)
|
|
33
33
|
|
|
34
34
|
BUNDLED WITH
|
|
35
|
-
2.
|
|
35
|
+
2.3.3
|
data/README.md
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# CallableTree
|
|
2
2
|
|
|
3
3
|
[](https://github.com/jsmmr/ruby_callable_tree/actions/workflows/build.yml)
|
|
4
|
+
[](https://github.com/jsmmr/ruby_callable_tree/actions/workflows/codeql-analysis.yml)
|
|
4
5
|
|
|
5
6
|
## Installation
|
|
6
7
|
|
|
@@ -42,11 +43,11 @@ module Node
|
|
|
42
43
|
class Parser
|
|
43
44
|
include CallableTree::Node::Internal
|
|
44
45
|
|
|
45
|
-
def match?(input, **
|
|
46
|
+
def match?(input, **_options)
|
|
46
47
|
File.extname(input) == '.json'
|
|
47
48
|
end
|
|
48
49
|
|
|
49
|
-
# If there is need to convert the input
|
|
50
|
+
# If there is need to convert the input values for
|
|
50
51
|
# child nodes, override the `call` method.
|
|
51
52
|
def call(input, **options)
|
|
52
53
|
File.open(input) do |file|
|
|
@@ -58,7 +59,7 @@ module Node
|
|
|
58
59
|
# If a returned value of the `call` method is `nil`,
|
|
59
60
|
# but there is no need to call the sibling nodes,
|
|
60
61
|
# override the `terminate?` method to return `true`.
|
|
61
|
-
def terminate?(
|
|
62
|
+
def terminate?(_output, *_inputs, **_options)
|
|
62
63
|
true
|
|
63
64
|
end
|
|
64
65
|
end
|
|
@@ -70,11 +71,11 @@ module Node
|
|
|
70
71
|
@type = type
|
|
71
72
|
end
|
|
72
73
|
|
|
73
|
-
def match?(input, **
|
|
74
|
+
def match?(input, **_options)
|
|
74
75
|
!!input[@type.to_s]
|
|
75
76
|
end
|
|
76
77
|
|
|
77
|
-
def call(input, **
|
|
78
|
+
def call(input, **_options)
|
|
78
79
|
input[@type.to_s]
|
|
79
80
|
.map { |element| [element['name'], element['emoji']] }
|
|
80
81
|
.to_h
|
|
@@ -86,11 +87,11 @@ module Node
|
|
|
86
87
|
class Parser
|
|
87
88
|
include CallableTree::Node::Internal
|
|
88
89
|
|
|
89
|
-
def match?(input, **
|
|
90
|
+
def match?(input, **_options)
|
|
90
91
|
File.extname(input) == '.xml'
|
|
91
92
|
end
|
|
92
93
|
|
|
93
|
-
# If there is need to convert the input
|
|
94
|
+
# If there is need to convert the input values for
|
|
94
95
|
# child nodes, override the `call` method.
|
|
95
96
|
def call(input, **options)
|
|
96
97
|
File.open(input) do |file|
|
|
@@ -101,7 +102,7 @@ module Node
|
|
|
101
102
|
# If a returned value of the `call` method is `nil`,
|
|
102
103
|
# but there is no need to call the sibling nodes,
|
|
103
104
|
# override the `terminate?` method to return `true`.
|
|
104
|
-
def terminate?(
|
|
105
|
+
def terminate?(_output, *_inputs, **_options)
|
|
105
106
|
true
|
|
106
107
|
end
|
|
107
108
|
end
|
|
@@ -113,11 +114,11 @@ module Node
|
|
|
113
114
|
@type = type
|
|
114
115
|
end
|
|
115
116
|
|
|
116
|
-
def match?(input, **
|
|
117
|
+
def match?(input, **_options)
|
|
117
118
|
!input.get_elements("//#{@type}").empty?
|
|
118
119
|
end
|
|
119
120
|
|
|
120
|
-
def call(input, **
|
|
121
|
+
def call(input, **_options)
|
|
121
122
|
input
|
|
122
123
|
.get_elements("//#{@type}")
|
|
123
124
|
.first
|
|
@@ -140,7 +141,7 @@ tree = CallableTree::Node::Root.new.append(
|
|
|
140
141
|
)#.seek
|
|
141
142
|
)#.seek
|
|
142
143
|
|
|
143
|
-
Dir.glob(__dir__
|
|
144
|
+
Dir.glob("#{__dir__}/docs/*") do |file|
|
|
144
145
|
options = { foo: :bar }
|
|
145
146
|
pp tree.call(file, **options)
|
|
146
147
|
puts '---'
|
|
@@ -182,12 +183,12 @@ end
|
|
|
182
183
|
|
|
183
184
|
tree = CallableTree::Node::Root.new.append(
|
|
184
185
|
Node::LessThan.new(5).append(
|
|
185
|
-
|
|
186
|
-
|
|
186
|
+
->(input) { input * 2 }, # anonymous external node
|
|
187
|
+
->(input) { input + 1 } # anonymous external node
|
|
187
188
|
).broadcast,
|
|
188
189
|
Node::LessThan.new(10).append(
|
|
189
|
-
|
|
190
|
-
|
|
190
|
+
->(input) { input * 3 }, # anonymous external node
|
|
191
|
+
->(input) { input - 1 } # anonymous external node
|
|
191
192
|
).broadcast
|
|
192
193
|
).broadcast
|
|
193
194
|
|
|
@@ -434,28 +435,28 @@ This is an example of logging.
|
|
|
434
435
|
module Node
|
|
435
436
|
module Logging
|
|
436
437
|
INDENT_SIZE = 2
|
|
437
|
-
BLANK = ' '
|
|
438
|
+
BLANK = ' '
|
|
438
439
|
|
|
439
440
|
module Match
|
|
440
|
-
LIST_STYLE = '*'
|
|
441
|
+
LIST_STYLE = '*'
|
|
441
442
|
|
|
442
|
-
def match?(_input, **)
|
|
443
|
+
def match?(_input, **_options)
|
|
443
444
|
super.tap do |matched|
|
|
444
|
-
prefix = LIST_STYLE.rjust(
|
|
445
|
-
puts "#{prefix} #{
|
|
445
|
+
prefix = LIST_STYLE.rjust(depth * INDENT_SIZE - INDENT_SIZE + LIST_STYLE.length, BLANK)
|
|
446
|
+
puts "#{prefix} #{identity}: [matched: #{matched}]"
|
|
446
447
|
end
|
|
447
448
|
end
|
|
448
449
|
end
|
|
449
450
|
|
|
450
451
|
module Call
|
|
451
|
-
INPUT_LABEL = 'Input :'
|
|
452
|
-
OUTPUT_LABEL = 'Output:'
|
|
452
|
+
INPUT_LABEL = 'Input :'
|
|
453
|
+
OUTPUT_LABEL = 'Output:'
|
|
453
454
|
|
|
454
|
-
def call(input, **)
|
|
455
|
+
def call(input, **_options)
|
|
455
456
|
super.tap do |output|
|
|
456
|
-
input_prefix = INPUT_LABEL.rjust(
|
|
457
|
+
input_prefix = INPUT_LABEL.rjust(depth * INDENT_SIZE + INPUT_LABEL.length, BLANK)
|
|
457
458
|
puts "#{input_prefix} #{input}"
|
|
458
|
-
output_prefix = OUTPUT_LABEL.rjust(
|
|
459
|
+
output_prefix = OUTPUT_LABEL.rjust(depth * INDENT_SIZE + OUTPUT_LABEL.length, BLANK)
|
|
459
460
|
puts "#{output_prefix} #{output}"
|
|
460
461
|
end
|
|
461
462
|
end
|
|
@@ -579,24 +580,24 @@ module Node
|
|
|
579
580
|
end
|
|
580
581
|
|
|
581
582
|
Node::HooksSample.new
|
|
582
|
-
.before_call do |input, **
|
|
583
|
+
.before_call do |input, **_options|
|
|
583
584
|
puts "before_call input: #{input}";
|
|
584
585
|
input + 1
|
|
585
586
|
end
|
|
586
587
|
.append(
|
|
587
588
|
# anonymous external node
|
|
588
|
-
lambda do |input, **
|
|
589
|
+
lambda do |input, **_options|
|
|
589
590
|
puts "external input: #{input}"
|
|
590
591
|
input * 2
|
|
591
592
|
end
|
|
592
593
|
)
|
|
593
|
-
.around_call do |input, **
|
|
594
|
+
.around_call do |input, **_options, &block|
|
|
594
595
|
puts "around_call input: #{input}"
|
|
595
596
|
output = block.call
|
|
596
597
|
puts "around_call output: #{output}"
|
|
597
598
|
output * input
|
|
598
599
|
end
|
|
599
|
-
.after_call do |output, **
|
|
600
|
+
.after_call do |output, **_options|
|
|
600
601
|
puts "after_call output: #{output}"
|
|
601
602
|
output * 2
|
|
602
603
|
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'callable_tree'
|
|
2
4
|
require 'json'
|
|
3
5
|
require 'rexml/document'
|
|
@@ -7,7 +9,7 @@ module Node
|
|
|
7
9
|
class Parser
|
|
8
10
|
include CallableTree::Node::Internal
|
|
9
11
|
|
|
10
|
-
def match?(input, **
|
|
12
|
+
def match?(input, **_options)
|
|
11
13
|
File.extname(input) == '.json'
|
|
12
14
|
end
|
|
13
15
|
|
|
@@ -18,7 +20,7 @@ module Node
|
|
|
18
20
|
end
|
|
19
21
|
end
|
|
20
22
|
|
|
21
|
-
def terminate?(_output, **)
|
|
23
|
+
def terminate?(_output, *_inputs, **_options)
|
|
22
24
|
true
|
|
23
25
|
end
|
|
24
26
|
end
|
|
@@ -30,11 +32,11 @@ module Node
|
|
|
30
32
|
@type = type
|
|
31
33
|
end
|
|
32
34
|
|
|
33
|
-
def match?(input, **
|
|
35
|
+
def match?(input, **_options)
|
|
34
36
|
!!input[@type.to_s]
|
|
35
37
|
end
|
|
36
38
|
|
|
37
|
-
def call(input, **
|
|
39
|
+
def call(input, **_options)
|
|
38
40
|
input[@type.to_s]
|
|
39
41
|
.map { |element| [element['name'], element['emoji']] }
|
|
40
42
|
.to_h
|
|
@@ -46,7 +48,7 @@ module Node
|
|
|
46
48
|
class Parser
|
|
47
49
|
include CallableTree::Node::Internal
|
|
48
50
|
|
|
49
|
-
def match?(input, **
|
|
51
|
+
def match?(input, **_options)
|
|
50
52
|
File.extname(input) == '.xml'
|
|
51
53
|
end
|
|
52
54
|
|
|
@@ -56,7 +58,7 @@ module Node
|
|
|
56
58
|
end
|
|
57
59
|
end
|
|
58
60
|
|
|
59
|
-
def terminate?(_output, **)
|
|
61
|
+
def terminate?(_output, *_inputs, **_options)
|
|
60
62
|
true
|
|
61
63
|
end
|
|
62
64
|
end
|
|
@@ -68,11 +70,11 @@ module Node
|
|
|
68
70
|
@type = type
|
|
69
71
|
end
|
|
70
72
|
|
|
71
|
-
def match?(input, **
|
|
73
|
+
def match?(input, **_options)
|
|
72
74
|
!input.get_elements("//#{@type}").empty?
|
|
73
75
|
end
|
|
74
76
|
|
|
75
|
-
def call(input, **
|
|
77
|
+
def call(input, **_options)
|
|
76
78
|
input
|
|
77
79
|
.get_elements("//#{@type}")
|
|
78
80
|
.first
|
|
@@ -94,7 +96,7 @@ tree = CallableTree::Node::Root.new.append(
|
|
|
94
96
|
)
|
|
95
97
|
)
|
|
96
98
|
|
|
97
|
-
Dir.glob(__dir__
|
|
99
|
+
Dir.glob("#{__dir__}/docs/*") do |file|
|
|
98
100
|
options = { foo: :bar }
|
|
99
101
|
pp tree.call(file, **options)
|
|
100
102
|
puts '---'
|
data/examples/hooks-call.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'callable_tree'
|
|
2
4
|
|
|
3
5
|
module Node
|
|
@@ -7,25 +9,26 @@ module Node
|
|
|
7
9
|
end
|
|
8
10
|
end
|
|
9
11
|
|
|
10
|
-
Node::HooksSample
|
|
11
|
-
.
|
|
12
|
-
|
|
12
|
+
Node::HooksSample
|
|
13
|
+
.new
|
|
14
|
+
.before_call do |input, **_options|
|
|
15
|
+
puts "before_call input: #{input}"
|
|
13
16
|
input + 1
|
|
14
17
|
end
|
|
15
18
|
.append(
|
|
16
19
|
# anonymous external node
|
|
17
|
-
lambda do |input, **
|
|
20
|
+
lambda do |input, **_options|
|
|
18
21
|
puts "external input: #{input}"
|
|
19
22
|
input * 2
|
|
20
23
|
end
|
|
21
24
|
)
|
|
22
|
-
.around_call do |input, **
|
|
25
|
+
.around_call do |input, **_options, &block|
|
|
23
26
|
puts "around_call input: #{input}"
|
|
24
27
|
output = block.call
|
|
25
28
|
puts "around_call output: #{output}"
|
|
26
29
|
output * input
|
|
27
30
|
end
|
|
28
|
-
.after_call do |output, **
|
|
31
|
+
.after_call do |output, **_options|
|
|
29
32
|
puts "after_call output: #{output}"
|
|
30
33
|
output * 2
|
|
31
34
|
end
|
data/examples/identity.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'callable_tree'
|
|
2
4
|
require 'json'
|
|
3
5
|
require 'rexml/document'
|
|
@@ -20,7 +22,7 @@ module Node
|
|
|
20
22
|
class Parser
|
|
21
23
|
include CallableTree::Node::Internal
|
|
22
24
|
|
|
23
|
-
def match?(input, **
|
|
25
|
+
def match?(input, **_options)
|
|
24
26
|
File.extname(input) == '.json'
|
|
25
27
|
end
|
|
26
28
|
|
|
@@ -31,7 +33,7 @@ module Node
|
|
|
31
33
|
end
|
|
32
34
|
end
|
|
33
35
|
|
|
34
|
-
def terminate?(_output, **)
|
|
36
|
+
def terminate?(_output, *_inputs, **_options)
|
|
35
37
|
true
|
|
36
38
|
end
|
|
37
39
|
end
|
|
@@ -47,11 +49,11 @@ module Node
|
|
|
47
49
|
Identity.new(klass: super, type: @type)
|
|
48
50
|
end
|
|
49
51
|
|
|
50
|
-
def match?(input, **
|
|
52
|
+
def match?(input, **_options)
|
|
51
53
|
!!input[@type.to_s]
|
|
52
54
|
end
|
|
53
55
|
|
|
54
|
-
def call(input, **
|
|
56
|
+
def call(input, **_options)
|
|
55
57
|
input[@type.to_s]
|
|
56
58
|
.map { |element| [element['name'], element['emoji']] }
|
|
57
59
|
.to_h
|
|
@@ -63,7 +65,7 @@ module Node
|
|
|
63
65
|
class Parser
|
|
64
66
|
include CallableTree::Node::Internal
|
|
65
67
|
|
|
66
|
-
def match?(input, **
|
|
68
|
+
def match?(input, **_options)
|
|
67
69
|
File.extname(input) == '.xml'
|
|
68
70
|
end
|
|
69
71
|
|
|
@@ -73,7 +75,7 @@ module Node
|
|
|
73
75
|
end
|
|
74
76
|
end
|
|
75
77
|
|
|
76
|
-
def terminate?(_output, **)
|
|
78
|
+
def terminate?(_output, *_inputs, **_options)
|
|
77
79
|
true
|
|
78
80
|
end
|
|
79
81
|
end
|
|
@@ -89,11 +91,11 @@ module Node
|
|
|
89
91
|
Identity.new(klass: super, type: @type)
|
|
90
92
|
end
|
|
91
93
|
|
|
92
|
-
def match?(input, **
|
|
94
|
+
def match?(input, **_options)
|
|
93
95
|
!input.get_elements("//#{@type}").empty?
|
|
94
96
|
end
|
|
95
97
|
|
|
96
|
-
def call(input, **
|
|
98
|
+
def call(input, **_options)
|
|
97
99
|
input
|
|
98
100
|
.get_elements("//#{@type}")
|
|
99
101
|
.first
|
|
@@ -115,7 +117,7 @@ tree = CallableTree::Node::Root.new.append(
|
|
|
115
117
|
)
|
|
116
118
|
)
|
|
117
119
|
|
|
118
|
-
Dir.glob(__dir__
|
|
120
|
+
Dir.glob("#{__dir__}/docs/*") do |file|
|
|
119
121
|
options = { foo: :bar }
|
|
120
122
|
pp tree.call(file, **options)
|
|
121
123
|
puts '---'
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'callable_tree'
|
|
2
4
|
|
|
3
5
|
module Node
|
|
@@ -16,12 +18,12 @@ end
|
|
|
16
18
|
|
|
17
19
|
tree = CallableTree::Node::Root.new.append(
|
|
18
20
|
Node::LessThan.new(5).append(
|
|
19
|
-
|
|
20
|
-
|
|
21
|
+
->(input) { input * 2 }, # anonymous external node
|
|
22
|
+
->(input) { input + 1 } # anonymous external node
|
|
21
23
|
).broadcast,
|
|
22
24
|
Node::LessThan.new(10).append(
|
|
23
|
-
|
|
24
|
-
|
|
25
|
+
->(input) { input * 3 }, # anonymous external node
|
|
26
|
+
->(input) { input - 1 } # anonymous external node
|
|
25
27
|
).broadcast
|
|
26
28
|
).broadcast
|
|
27
29
|
|
data/examples/internal-seek.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'callable_tree'
|
|
2
4
|
require 'json'
|
|
3
5
|
require 'rexml/document'
|
|
@@ -7,7 +9,7 @@ module Node
|
|
|
7
9
|
class Parser
|
|
8
10
|
include CallableTree::Node::Internal
|
|
9
11
|
|
|
10
|
-
def match?(input, **
|
|
12
|
+
def match?(input, **_options)
|
|
11
13
|
File.extname(input) == '.json'
|
|
12
14
|
end
|
|
13
15
|
|
|
@@ -18,7 +20,7 @@ module Node
|
|
|
18
20
|
end
|
|
19
21
|
end
|
|
20
22
|
|
|
21
|
-
def terminate?(_output, **)
|
|
23
|
+
def terminate?(_output, *_inputs, **_options)
|
|
22
24
|
true
|
|
23
25
|
end
|
|
24
26
|
end
|
|
@@ -30,11 +32,11 @@ module Node
|
|
|
30
32
|
@type = type
|
|
31
33
|
end
|
|
32
34
|
|
|
33
|
-
def match?(input, **
|
|
35
|
+
def match?(input, **_options)
|
|
34
36
|
!!input[@type.to_s]
|
|
35
37
|
end
|
|
36
38
|
|
|
37
|
-
def call(input, **
|
|
39
|
+
def call(input, **_options)
|
|
38
40
|
input[@type.to_s]
|
|
39
41
|
.map { |element| [element['name'], element['emoji']] }
|
|
40
42
|
.to_h
|
|
@@ -46,7 +48,7 @@ module Node
|
|
|
46
48
|
class Parser
|
|
47
49
|
include CallableTree::Node::Internal
|
|
48
50
|
|
|
49
|
-
def match?(input, **
|
|
51
|
+
def match?(input, **_options)
|
|
50
52
|
File.extname(input) == '.xml'
|
|
51
53
|
end
|
|
52
54
|
|
|
@@ -56,7 +58,7 @@ module Node
|
|
|
56
58
|
end
|
|
57
59
|
end
|
|
58
60
|
|
|
59
|
-
def terminate?(_output, **)
|
|
61
|
+
def terminate?(_output, *_inputs, **_options)
|
|
60
62
|
true
|
|
61
63
|
end
|
|
62
64
|
end
|
|
@@ -68,11 +70,11 @@ module Node
|
|
|
68
70
|
@type = type
|
|
69
71
|
end
|
|
70
72
|
|
|
71
|
-
def match?(input, **
|
|
73
|
+
def match?(input, **_options)
|
|
72
74
|
!input.get_elements("//#{@type}").empty?
|
|
73
75
|
end
|
|
74
76
|
|
|
75
|
-
def call(input, **
|
|
77
|
+
def call(input, **_options)
|
|
76
78
|
input
|
|
77
79
|
.get_elements("//#{@type}")
|
|
78
80
|
.first
|
|
@@ -94,7 +96,7 @@ tree = CallableTree::Node::Root.new.append(
|
|
|
94
96
|
)
|
|
95
97
|
)
|
|
96
98
|
|
|
97
|
-
Dir.glob(__dir__
|
|
99
|
+
Dir.glob("#{__dir__}/docs/*") do |file|
|
|
98
100
|
options = { foo: :bar }
|
|
99
101
|
pp tree.call(file, **options)
|
|
100
102
|
puts '---'
|
data/examples/logging.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'callable_tree'
|
|
2
4
|
require 'json'
|
|
3
5
|
require 'rexml/document'
|
|
@@ -5,28 +7,28 @@ require 'rexml/document'
|
|
|
5
7
|
module Node
|
|
6
8
|
module Logging
|
|
7
9
|
INDENT_SIZE = 2
|
|
8
|
-
BLANK = ' '
|
|
10
|
+
BLANK = ' '
|
|
9
11
|
|
|
10
12
|
module Match
|
|
11
|
-
LIST_STYLE = '*'
|
|
13
|
+
LIST_STYLE = '*'
|
|
12
14
|
|
|
13
|
-
def match?(_input, **)
|
|
15
|
+
def match?(_input, **_options)
|
|
14
16
|
super.tap do |matched|
|
|
15
|
-
prefix = LIST_STYLE.rjust(
|
|
16
|
-
puts "#{prefix} #{
|
|
17
|
+
prefix = LIST_STYLE.rjust(depth * INDENT_SIZE - INDENT_SIZE + LIST_STYLE.length, BLANK)
|
|
18
|
+
puts "#{prefix} #{identity}: [matched: #{matched}]"
|
|
17
19
|
end
|
|
18
20
|
end
|
|
19
21
|
end
|
|
20
22
|
|
|
21
23
|
module Call
|
|
22
|
-
INPUT_LABEL = 'Input :'
|
|
23
|
-
OUTPUT_LABEL = 'Output:'
|
|
24
|
+
INPUT_LABEL = 'Input :'
|
|
25
|
+
OUTPUT_LABEL = 'Output:'
|
|
24
26
|
|
|
25
|
-
def call(input, **)
|
|
27
|
+
def call(input, **_options)
|
|
26
28
|
super.tap do |output|
|
|
27
|
-
input_prefix = INPUT_LABEL.rjust(
|
|
29
|
+
input_prefix = INPUT_LABEL.rjust(depth * INDENT_SIZE + INPUT_LABEL.length, BLANK)
|
|
28
30
|
puts "#{input_prefix} #{input}"
|
|
29
|
-
output_prefix = OUTPUT_LABEL.rjust(
|
|
31
|
+
output_prefix = OUTPUT_LABEL.rjust(depth * INDENT_SIZE + OUTPUT_LABEL.length, BLANK)
|
|
30
32
|
puts "#{output_prefix} #{output}"
|
|
31
33
|
end
|
|
32
34
|
end
|
|
@@ -51,7 +53,7 @@ module Node
|
|
|
51
53
|
include CallableTree::Node::Internal
|
|
52
54
|
prepend Logging::Match
|
|
53
55
|
|
|
54
|
-
def match?(input, **
|
|
56
|
+
def match?(input, **_options)
|
|
55
57
|
File.extname(input) == '.json'
|
|
56
58
|
end
|
|
57
59
|
|
|
@@ -62,7 +64,7 @@ module Node
|
|
|
62
64
|
end
|
|
63
65
|
end
|
|
64
66
|
|
|
65
|
-
def terminate?(_output, **)
|
|
67
|
+
def terminate?(_output, *_inputs, **_options)
|
|
66
68
|
true
|
|
67
69
|
end
|
|
68
70
|
end
|
|
@@ -80,11 +82,11 @@ module Node
|
|
|
80
82
|
Identity.new(klass: super, type: @type)
|
|
81
83
|
end
|
|
82
84
|
|
|
83
|
-
def match?(input, **
|
|
85
|
+
def match?(input, **_options)
|
|
84
86
|
!!input[@type.to_s]
|
|
85
87
|
end
|
|
86
88
|
|
|
87
|
-
def call(input, **
|
|
89
|
+
def call(input, **_options)
|
|
88
90
|
input[@type.to_s]
|
|
89
91
|
.map { |element| [element['name'], element['emoji']] }
|
|
90
92
|
.to_h
|
|
@@ -97,7 +99,7 @@ module Node
|
|
|
97
99
|
include CallableTree::Node::Internal
|
|
98
100
|
prepend Logging::Match
|
|
99
101
|
|
|
100
|
-
def match?(input, **
|
|
102
|
+
def match?(input, **_options)
|
|
101
103
|
File.extname(input) == '.xml'
|
|
102
104
|
end
|
|
103
105
|
|
|
@@ -107,7 +109,7 @@ module Node
|
|
|
107
109
|
end
|
|
108
110
|
end
|
|
109
111
|
|
|
110
|
-
def terminate?(_output, **)
|
|
112
|
+
def terminate?(_output, *_inputs, **_options)
|
|
111
113
|
true
|
|
112
114
|
end
|
|
113
115
|
end
|
|
@@ -125,11 +127,11 @@ module Node
|
|
|
125
127
|
Identity.new(klass: super, type: @type)
|
|
126
128
|
end
|
|
127
129
|
|
|
128
|
-
def match?(input, **
|
|
130
|
+
def match?(input, **_options)
|
|
129
131
|
!input.get_elements("//#{@type}").empty?
|
|
130
132
|
end
|
|
131
133
|
|
|
132
|
-
def call(input, **
|
|
134
|
+
def call(input, **_options)
|
|
133
135
|
input
|
|
134
136
|
.get_elements("//#{@type}")
|
|
135
137
|
.first
|
|
@@ -151,7 +153,7 @@ tree = CallableTree::Node::Root.new.append(
|
|
|
151
153
|
)
|
|
152
154
|
)
|
|
153
155
|
|
|
154
|
-
Dir.glob(__dir__
|
|
156
|
+
Dir.glob("#{__dir__}/docs/*") do |file|
|
|
155
157
|
options = { foo: :bar }
|
|
156
158
|
pp tree.call(file, **options)
|
|
157
159
|
puts '---'
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
module CallableTree
|
|
4
4
|
module Node
|
|
5
5
|
module External
|
|
6
|
+
# TODO: Add :inputs
|
|
6
7
|
Output = Struct.new(:value, :options, :routes)
|
|
7
8
|
|
|
8
9
|
module Verbose
|
|
@@ -10,8 +11,8 @@ module CallableTree
|
|
|
10
11
|
true
|
|
11
12
|
end
|
|
12
13
|
|
|
13
|
-
def call(
|
|
14
|
-
output = super(
|
|
14
|
+
def call(*inputs, **options)
|
|
15
|
+
output = super(*inputs, **options)
|
|
15
16
|
routes = self.routes
|
|
16
17
|
|
|
17
18
|
Output.new(output, options, routes)
|
|
@@ -9,29 +9,43 @@ module CallableTree
|
|
|
9
9
|
end
|
|
10
10
|
|
|
11
11
|
def before_call(&block)
|
|
12
|
+
clone.before_call!(&block)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def before_call!(&block)
|
|
12
16
|
before_callbacks << block
|
|
13
17
|
self
|
|
14
18
|
end
|
|
15
19
|
|
|
16
20
|
def around_call(&block)
|
|
21
|
+
clone.around_call!(&block)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def around_call!(&block)
|
|
17
25
|
around_callbacks << block
|
|
18
26
|
self
|
|
19
27
|
end
|
|
20
28
|
|
|
21
29
|
def after_call(&block)
|
|
30
|
+
clone.after_call!(&block)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def after_call!(&block)
|
|
22
34
|
after_callbacks << block
|
|
23
35
|
self
|
|
24
36
|
end
|
|
25
37
|
|
|
26
|
-
def call(
|
|
27
|
-
|
|
28
|
-
|
|
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)
|
|
29
43
|
end
|
|
30
44
|
|
|
31
|
-
output = super(
|
|
45
|
+
output = super(input_head, *input_tail, **options)
|
|
32
46
|
|
|
33
47
|
output = around_callbacks.reduce(output) do |output, callable|
|
|
34
|
-
callable.call(
|
|
48
|
+
callable.call(input_head, *input_tail, self, **options) { output }
|
|
35
49
|
end
|
|
36
50
|
|
|
37
51
|
after_callbacks.reduce(output) do |output, callable|
|
|
@@ -5,9 +5,11 @@ module CallableTree
|
|
|
5
5
|
module Internal
|
|
6
6
|
module Strategy
|
|
7
7
|
class Broadcast
|
|
8
|
-
|
|
8
|
+
include Strategy
|
|
9
|
+
|
|
10
|
+
def call(nodes, *inputs, **options)
|
|
9
11
|
nodes.map do |node|
|
|
10
|
-
node.call(
|
|
12
|
+
node.call(*inputs, **options) if node.match?(*inputs, **options)
|
|
11
13
|
end
|
|
12
14
|
end
|
|
13
15
|
end
|
|
@@ -5,10 +5,14 @@ module CallableTree
|
|
|
5
5
|
module Internal
|
|
6
6
|
module Strategy
|
|
7
7
|
class Compose
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
include Strategy
|
|
9
|
+
|
|
10
|
+
def call(nodes, *inputs, **options)
|
|
11
|
+
head, *tail = inputs
|
|
12
|
+
nodes.reduce(head) do |input, node|
|
|
13
|
+
inputs = [input, *tail]
|
|
14
|
+
if node.match?(*inputs, **options)
|
|
15
|
+
node.call(*inputs, **options)
|
|
12
16
|
else
|
|
13
17
|
input
|
|
14
18
|
end
|
|
@@ -5,13 +5,15 @@ module CallableTree
|
|
|
5
5
|
module Internal
|
|
6
6
|
module Strategy
|
|
7
7
|
class Seek
|
|
8
|
-
|
|
8
|
+
include Strategy
|
|
9
|
+
|
|
10
|
+
def call(nodes, *inputs, **options)
|
|
9
11
|
nodes
|
|
10
12
|
.lazy
|
|
11
|
-
.select { |node| node.match?(
|
|
13
|
+
.select { |node| node.match?(*inputs, **options) }
|
|
12
14
|
.map do |node|
|
|
13
|
-
output = node.call(
|
|
14
|
-
terminated = node.terminate?(output, **options)
|
|
15
|
+
output = node.call(*inputs, **options)
|
|
16
|
+
terminated = node.terminate?(output, *inputs, **options)
|
|
15
17
|
[output, terminated]
|
|
16
18
|
end
|
|
17
19
|
.select { |_output, terminated| terminated }
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module CallableTree
|
|
4
|
+
module Node
|
|
5
|
+
module Internal
|
|
6
|
+
module Strategy
|
|
7
|
+
def call(_nodes, *_inputs, **_options)
|
|
8
|
+
raise ::CallableTree::Error, 'Not implemented'
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def name
|
|
12
|
+
@name ||= self.class.name.split('::').last.downcase.to_sym
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def ==(other)
|
|
16
|
+
name == other.name
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def eql?(other)
|
|
20
|
+
instance_of?(other.class) && self == other
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def hash
|
|
24
|
+
self.class.name.hash
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -3,10 +3,16 @@
|
|
|
3
3
|
module CallableTree
|
|
4
4
|
module Node
|
|
5
5
|
module Internal
|
|
6
|
+
extend ::Forwardable
|
|
6
7
|
include Node
|
|
7
8
|
|
|
9
|
+
def_delegators :child_nodes, :[], :at
|
|
10
|
+
|
|
8
11
|
def children
|
|
9
|
-
|
|
12
|
+
[*child_nodes]
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def children!
|
|
10
16
|
child_nodes
|
|
11
17
|
end
|
|
12
18
|
|
|
@@ -19,7 +25,7 @@ module CallableTree
|
|
|
19
25
|
def append!(*callables)
|
|
20
26
|
callables
|
|
21
27
|
.map { |callable| nodeify(callable) }
|
|
22
|
-
.tap { |nodes| child_nodes.push(*nodes) }
|
|
28
|
+
.tap { |nodes| child_nodes.push(*nodes) }
|
|
23
29
|
|
|
24
30
|
self
|
|
25
31
|
end
|
|
@@ -35,74 +41,113 @@ module CallableTree
|
|
|
35
41
|
self
|
|
36
42
|
end
|
|
37
43
|
|
|
38
|
-
def
|
|
44
|
+
def shake(&block)
|
|
45
|
+
clone.tap do |node|
|
|
46
|
+
node.shake!(&block)
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def shake!(&block)
|
|
51
|
+
reject!(&block) if block_given?
|
|
52
|
+
|
|
53
|
+
reject! do |node|
|
|
54
|
+
node.is_a?(Internal) && node.shake!(&block).child_nodes.empty?
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def match?(*, **)
|
|
39
59
|
!child_nodes.empty?
|
|
40
60
|
end
|
|
41
61
|
|
|
42
|
-
def call(
|
|
43
|
-
strategy.call(child_nodes,
|
|
62
|
+
def call(*inputs, **options)
|
|
63
|
+
strategy.call(child_nodes, *inputs, **options)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def seek?
|
|
67
|
+
strategy.is_a?(Strategy::Seek)
|
|
44
68
|
end
|
|
45
69
|
|
|
46
70
|
def seek
|
|
47
|
-
if
|
|
71
|
+
if seek?
|
|
48
72
|
self
|
|
49
73
|
else
|
|
50
74
|
clone.tap do |node|
|
|
51
|
-
node.
|
|
75
|
+
node.strategy = Strategy::Seek.new
|
|
52
76
|
end
|
|
53
77
|
end
|
|
54
78
|
end
|
|
55
79
|
|
|
56
80
|
def seek!
|
|
57
|
-
|
|
58
|
-
|
|
81
|
+
tap do |node|
|
|
82
|
+
node.strategy = Strategy::Seek.new unless seek?
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def broadcast?
|
|
87
|
+
strategy.is_a?(Strategy::Broadcast)
|
|
59
88
|
end
|
|
60
89
|
|
|
61
90
|
def broadcast
|
|
62
|
-
if
|
|
91
|
+
if broadcast?
|
|
63
92
|
self
|
|
64
93
|
else
|
|
65
94
|
clone.tap do |node|
|
|
66
|
-
node.
|
|
95
|
+
node.strategy = Strategy::Broadcast.new
|
|
67
96
|
end
|
|
68
97
|
end
|
|
69
98
|
end
|
|
70
99
|
|
|
71
100
|
def broadcast!
|
|
72
|
-
|
|
73
|
-
|
|
101
|
+
tap do |node|
|
|
102
|
+
node.strategy = Strategy::Broadcast.new unless broadcast?
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def compose?
|
|
107
|
+
strategy.is_a?(Strategy::Compose)
|
|
74
108
|
end
|
|
75
109
|
|
|
76
110
|
def compose
|
|
77
|
-
if
|
|
111
|
+
if compose?
|
|
78
112
|
self
|
|
79
113
|
else
|
|
80
114
|
clone.tap do |node|
|
|
81
|
-
node.
|
|
115
|
+
node.strategy = Strategy::Compose.new
|
|
82
116
|
end
|
|
83
117
|
end
|
|
84
118
|
end
|
|
85
119
|
|
|
86
120
|
def compose!
|
|
87
|
-
|
|
88
|
-
|
|
121
|
+
tap do |node|
|
|
122
|
+
node.strategy = Strategy::Compose.new unless compose?
|
|
123
|
+
end
|
|
89
124
|
end
|
|
90
125
|
|
|
91
|
-
|
|
126
|
+
def outline(&block)
|
|
127
|
+
key = block ? block.call(self) : identity
|
|
128
|
+
value = child_nodes.reduce({}) { |memo, node| memo.merge!(node.outline(&block)) }
|
|
129
|
+
{ key => value }
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
protected
|
|
92
133
|
|
|
93
|
-
attr_writer :
|
|
134
|
+
attr_writer :strategy
|
|
94
135
|
|
|
95
136
|
def child_nodes
|
|
96
137
|
@child_nodes ||= []
|
|
97
138
|
end
|
|
98
139
|
|
|
140
|
+
private
|
|
141
|
+
|
|
142
|
+
attr_writer :child_nodes
|
|
143
|
+
|
|
99
144
|
def nodeify(callable)
|
|
100
145
|
if callable.is_a?(Node)
|
|
101
146
|
callable.clone
|
|
102
147
|
else
|
|
103
148
|
External.proxify(callable)
|
|
104
149
|
end
|
|
105
|
-
|
|
150
|
+
.tap { |node| node.parent = self }
|
|
106
151
|
end
|
|
107
152
|
|
|
108
153
|
def strategy
|
|
@@ -113,7 +158,7 @@ module CallableTree
|
|
|
113
158
|
super
|
|
114
159
|
self.parent = nil
|
|
115
160
|
self.child_nodes = child_nodes.map do |node|
|
|
116
|
-
node.clone.tap { |new_node| new_node.
|
|
161
|
+
node.clone.tap { |new_node| new_node.parent = self }
|
|
117
162
|
end
|
|
118
163
|
end
|
|
119
164
|
end
|
data/lib/callable_tree/node.rb
CHANGED
|
@@ -30,19 +30,23 @@ module CallableTree
|
|
|
30
30
|
root? ? 0 : parent.depth + 1
|
|
31
31
|
end
|
|
32
32
|
|
|
33
|
-
def
|
|
33
|
+
def outline
|
|
34
|
+
raise ::CallableTree::Error, 'Not implemented'
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def match?(*_inputs, **_options)
|
|
34
38
|
true
|
|
35
39
|
end
|
|
36
40
|
|
|
37
|
-
def call(
|
|
41
|
+
def call(*_inputs, **_options)
|
|
38
42
|
raise ::CallableTree::Error, 'Not implemented'
|
|
39
43
|
end
|
|
40
44
|
|
|
41
|
-
def terminate?(output
|
|
45
|
+
def terminate?(output, *_inputs, **_options)
|
|
42
46
|
!output.nil?
|
|
43
47
|
end
|
|
44
48
|
|
|
45
|
-
|
|
49
|
+
protected
|
|
46
50
|
|
|
47
51
|
attr_writer :parent
|
|
48
52
|
end
|
data/lib/callable_tree.rb
CHANGED
|
@@ -8,6 +8,7 @@ require 'forwardable'
|
|
|
8
8
|
require_relative 'callable_tree/version'
|
|
9
9
|
require_relative 'callable_tree/node'
|
|
10
10
|
require_relative 'callable_tree/node/hooks/call'
|
|
11
|
+
require_relative 'callable_tree/node/internal/strategy'
|
|
11
12
|
require_relative 'callable_tree/node/internal/strategy/broadcast'
|
|
12
13
|
require_relative 'callable_tree/node/internal/strategy/seek'
|
|
13
14
|
require_relative 'callable_tree/node/internal/strategy/compose'
|
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.
|
|
4
|
+
version: 0.3.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- jsmmr
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2022-02-05 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
|
|
@@ -20,6 +20,7 @@ extensions: []
|
|
|
20
20
|
extra_rdoc_files: []
|
|
21
21
|
files:
|
|
22
22
|
- ".github/workflows/build.yml"
|
|
23
|
+
- ".github/workflows/codeql-analysis.yml"
|
|
23
24
|
- ".gitignore"
|
|
24
25
|
- ".rspec"
|
|
25
26
|
- ".ruby-version"
|
|
@@ -49,6 +50,7 @@ files:
|
|
|
49
50
|
- lib/callable_tree/node/external/verbose.rb
|
|
50
51
|
- lib/callable_tree/node/hooks/call.rb
|
|
51
52
|
- lib/callable_tree/node/internal.rb
|
|
53
|
+
- lib/callable_tree/node/internal/strategy.rb
|
|
52
54
|
- lib/callable_tree/node/internal/strategy/broadcast.rb
|
|
53
55
|
- lib/callable_tree/node/internal/strategy/compose.rb
|
|
54
56
|
- lib/callable_tree/node/internal/strategy/seek.rb
|
|
@@ -60,7 +62,7 @@ licenses:
|
|
|
60
62
|
metadata:
|
|
61
63
|
homepage_uri: https://github.com/jsmmr/ruby_callable_tree
|
|
62
64
|
source_code_uri: https://github.com/jsmmr/ruby_callable_tree
|
|
63
|
-
changelog_uri: https://github.com/jsmmr/ruby_callable_tree/blob/v0.
|
|
65
|
+
changelog_uri: https://github.com/jsmmr/ruby_callable_tree/blob/v0.3.2/CHANGELOG.md
|
|
64
66
|
post_install_message:
|
|
65
67
|
rdoc_options: []
|
|
66
68
|
require_paths:
|
|
@@ -76,7 +78,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
76
78
|
- !ruby/object:Gem::Version
|
|
77
79
|
version: '0'
|
|
78
80
|
requirements: []
|
|
79
|
-
rubygems_version: 3.
|
|
81
|
+
rubygems_version: 3.3.3
|
|
80
82
|
signing_key:
|
|
81
83
|
specification_version: 4
|
|
82
84
|
summary: Builds a tree by linking callable nodes. The nodes that match the conditions
|