callable_tree 0.2.2 → 0.3.2

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