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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8e5f087271cbaf840a0cb6557126331b67487c4f87e5843e3bcf900c54dc6e84
4
- data.tar.gz: d1d1e0ac4a085dc26d1a2f6bec141ea92ea80efbfb43c8738e34d9ae9280836c
3
+ metadata.gz: 5a506dec2678a69b014cff69b6cc4fd94e22b1f7f5027e9230727720c8dc049e
4
+ data.tar.gz: 3b7ee0419139ef24f40f8b0714cbd19551568967d0170a4b550a84f528811da4
5
5
  SHA512:
6
- metadata.gz: 0a342b5fff3ce51c36bd4e4e1977f2023db7045bab0f19e794bc8a1c48442c184cedfcadad5a0b9956fe146a0904aaca584a6d23c5ac23c063dc53d8d260978a
7
- data.tar.gz: 6fd3e33d25e549774488967d600ef236bff9e74bc750741eff9e5c6d3e5c59b15f2c956c1f25b97f5e9cd16becb7004e6df298adf04c01844aa300dc1e2e42b3
6
+ metadata.gz: b84af5f3ae12941eabdb1cdbc159d9a3f424388bffab74c2704d5507a875c924ae637b2b868194244d2530bcbd8bf5895118e42f7a79c91f901854896d686eb5
7
+ data.tar.gz: 816f558c0118c57bda18c3b69fef45240c9de5e87a1acea0bcf1f9448e0c67e34a7de613292796635f8e5c16d1835c2ba4bdef959939c44a6358bce94197a82a
@@ -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.2.4
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.2
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.2.2)
4
+ callable_tree (0.3.2)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
8
8
  specs:
9
- diff-lcs (1.4.4)
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.1)
15
+ rspec-core (3.10.2)
16
16
  rspec-support (~> 3.10.0)
17
- rspec-expectations (3.10.1)
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.2)
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.2)
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.2.22
35
+ 2.3.3
data/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  # CallableTree
2
2
 
3
3
  [![build](https://github.com/jsmmr/ruby_callable_tree/actions/workflows/build.yml/badge.svg)](https://github.com/jsmmr/ruby_callable_tree/actions/workflows/build.yml)
4
+ [![CodeQL](https://github.com/jsmmr/ruby_callable_tree/actions/workflows/codeql-analysis.yml/badge.svg)](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, **options)
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 value for
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?(output, **options)
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, **options)
74
+ def match?(input, **_options)
74
75
  !!input[@type.to_s]
75
76
  end
76
77
 
77
- def call(input, **options)
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, **options)
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 value for
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?(output, **options)
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, **options)
117
+ def match?(input, **_options)
117
118
  !input.get_elements("//#{@type}").empty?
118
119
  end
119
120
 
120
- def call(input, **options)
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__ + '/docs/*') do |file|
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
- lambda { |input, **| input * 2 }, # anonymous external node
186
- lambda { |input, **| input + 1 } # anonymous external node
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
- lambda { |input, **| input * 3 }, # anonymous external node
190
- lambda { |input, **| input - 1 } # anonymous external node
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 = ' '.freeze
438
+ BLANK = ' '
438
439
 
439
440
  module Match
440
- LIST_STYLE = '*'.freeze
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(self.depth * INDENT_SIZE - INDENT_SIZE + LIST_STYLE.length, BLANK)
445
- puts "#{prefix} #{self.identity}: [matched: #{matched}]"
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 :'.freeze
452
- OUTPUT_LABEL = 'Output:'.freeze
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(self.depth * INDENT_SIZE + INPUT_LABEL.length, BLANK)
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(self.depth * INDENT_SIZE + OUTPUT_LABEL.length, BLANK)
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, **options|
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, **options|
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, **options, &block|
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, **options|
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, **options)
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, **options)
35
+ def match?(input, **_options)
34
36
  !!input[@type.to_s]
35
37
  end
36
38
 
37
- def call(input, **options)
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, **options)
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, **options)
73
+ def match?(input, **_options)
72
74
  !input.get_elements("//#{@type}").empty?
73
75
  end
74
76
 
75
- def call(input, **options)
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__ + '/docs/*') do |file|
99
+ Dir.glob("#{__dir__}/docs/*") do |file|
98
100
  options = { foo: :bar }
99
101
  pp tree.call(file, **options)
100
102
  puts '---'
@@ -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.new
11
- .before_call do |input, **options|
12
- puts "before_call input: #{input}";
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, **options|
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, **options, &block|
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, **options|
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, **options)
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, **options)
52
+ def match?(input, **_options)
51
53
  !!input[@type.to_s]
52
54
  end
53
55
 
54
- def call(input, **options)
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, **options)
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, **options)
94
+ def match?(input, **_options)
93
95
  !input.get_elements("//#{@type}").empty?
94
96
  end
95
97
 
96
- def call(input, **options)
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__ + '/docs/*') do |file|
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
- lambda { |input, **| input * 2 }, # anonymous external node
20
- lambda { |input, **| input + 1 } # anonymous external node
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
- lambda { |input, **| input * 3 }, # anonymous external node
24
- lambda { |input, **| input - 1 } # anonymous external node
25
+ ->(input) { input * 3 }, # anonymous external node
26
+ ->(input) { input - 1 } # anonymous external node
25
27
  ).broadcast
26
28
  ).broadcast
27
29
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'callable_tree'
2
4
 
3
5
  module Node
@@ -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, **options)
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, **options)
35
+ def match?(input, **_options)
34
36
  !!input[@type.to_s]
35
37
  end
36
38
 
37
- def call(input, **options)
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, **options)
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, **options)
73
+ def match?(input, **_options)
72
74
  !input.get_elements("//#{@type}").empty?
73
75
  end
74
76
 
75
- def call(input, **options)
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__ + '/docs/*') do |file|
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 = ' '.freeze
10
+ BLANK = ' '
9
11
 
10
12
  module Match
11
- LIST_STYLE = '*'.freeze
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(self.depth * INDENT_SIZE - INDENT_SIZE + LIST_STYLE.length, BLANK)
16
- puts "#{prefix} #{self.identity}: [matched: #{matched}]"
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 :'.freeze
23
- OUTPUT_LABEL = 'Output:'.freeze
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(self.depth * INDENT_SIZE + INPUT_LABEL.length, BLANK)
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(self.depth * INDENT_SIZE + OUTPUT_LABEL.length, BLANK)
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, **options)
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, **options)
85
+ def match?(input, **_options)
84
86
  !!input[@type.to_s]
85
87
  end
86
88
 
87
- def call(input, **options)
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, **options)
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, **options)
130
+ def match?(input, **_options)
129
131
  !input.get_elements("//#{@type}").empty?
130
132
  end
131
133
 
132
- def call(input, **options)
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__ + '/docs/*') do |file|
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(input = nil, **options)
14
- output = super(input, **options)
14
+ def call(*inputs, **options)
15
+ output = super(*inputs, **options)
15
16
  routes = self.routes
16
17
 
17
18
  Output.new(output, options, routes)
@@ -37,6 +37,10 @@ module CallableTree
37
37
  .class
38
38
  end
39
39
 
40
+ def outline
41
+ { identity => nil }
42
+ end
43
+
40
44
  private
41
45
 
42
46
  def initialize_copy(_node)
@@ -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(input = nil, **options)
27
- input = before_callbacks.reduce(input) do |input, callable|
28
- callable.call(input, self, **options)
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(input, **options)
45
+ output = super(input_head, *input_tail, **options)
32
46
 
33
47
  output = around_callbacks.reduce(output) do |output, callable|
34
- callable.call(input, self, **options) { output }
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
- def call(nodes, input:, options:)
8
+ include Strategy
9
+
10
+ def call(nodes, *inputs, **options)
9
11
  nodes.map do |node|
10
- node.call(input, **options) if node.match?(input, **options)
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
- def call(nodes, input:, options:)
9
- nodes.reduce(input) do |input, node|
10
- if node.match?(input, **options)
11
- node.call(input, **options)
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
- def call(nodes, input:, options:)
8
+ include Strategy
9
+
10
+ def call(nodes, *inputs, **options)
9
11
  nodes
10
12
  .lazy
11
- .select { |node| node.match?(input, **options) }
13
+ .select { |node| node.match?(*inputs, **options) }
12
14
  .map do |node|
13
- output = node.call(input, **options)
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
- # TODO: Change to return a new array instance.
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) } # Use Array#push for Ruby 2.4
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 match?(_input = nil, **_options)
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(input = nil, **options)
43
- strategy.call(child_nodes, input: input, options: options)
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 strategy.is_a?(Strategy::Seek)
71
+ if seek?
48
72
  self
49
73
  else
50
74
  clone.tap do |node|
51
- node.send(:strategy=, Strategy::Seek.new)
75
+ node.strategy = Strategy::Seek.new
52
76
  end
53
77
  end
54
78
  end
55
79
 
56
80
  def seek!
57
- self.strategy = Strategy::Seek.new unless strategy.is_a?(Strategy::Seek)
58
- self
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 strategy.is_a?(Strategy::Broadcast)
91
+ if broadcast?
63
92
  self
64
93
  else
65
94
  clone.tap do |node|
66
- node.send(:strategy=, Strategy::Broadcast.new)
95
+ node.strategy = Strategy::Broadcast.new
67
96
  end
68
97
  end
69
98
  end
70
99
 
71
100
  def broadcast!
72
- self.strategy = Strategy::Broadcast.new unless strategy.is_a?(Strategy::Broadcast)
73
- self
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 strategy.is_a?(Strategy::Compose)
111
+ if compose?
78
112
  self
79
113
  else
80
114
  clone.tap do |node|
81
- node.send(:strategy=, Strategy::Compose.new)
115
+ node.strategy = Strategy::Compose.new
82
116
  end
83
117
  end
84
118
  end
85
119
 
86
120
  def compose!
87
- self.strategy = Strategy::Compose.new unless strategy.is_a?(Strategy::Compose)
88
- self
121
+ tap do |node|
122
+ node.strategy = Strategy::Compose.new unless compose?
123
+ end
89
124
  end
90
125
 
91
- private
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 :child_nodes, :strategy
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
- .tap { |node| node.send(:parent=, self) }
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.send(:parent=, self) }
161
+ node.clone.tap { |new_node| new_node.parent = self }
117
162
  end
118
163
  end
119
164
  end
@@ -30,19 +30,23 @@ module CallableTree
30
30
  root? ? 0 : parent.depth + 1
31
31
  end
32
32
 
33
- def match?(_input = nil, **_options)
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(_input = nil, **_options)
41
+ def call(*_inputs, **_options)
38
42
  raise ::CallableTree::Error, 'Not implemented'
39
43
  end
40
44
 
41
- def terminate?(output = nil, **_options)
45
+ def terminate?(output, *_inputs, **_options)
42
46
  !output.nil?
43
47
  end
44
48
 
45
- private
49
+ protected
46
50
 
47
51
  attr_writer :parent
48
52
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module CallableTree
4
- VERSION = '0.2.2'
4
+ VERSION = '0.3.2'
5
5
  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.2.2
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: 2021-10-24 00:00:00.000000000 Z
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.2.2/CHANGELOG.md
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.2.22
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