callable_tree 0.2.3 → 0.3.3

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: df7b380d00c1a56530ddd6fc4ee7159ca4f1fc14d3418c2f567f43ff6d176553
4
- data.tar.gz: 9e2d706c5d50ae1350dfdcf92951678e7284a83fba5a71e9f8f13ffcb58c4db7
3
+ metadata.gz: 3feea9db6a3844729a1644e56d60cc0cf8961e95e5ae5d58fcf4eb10eab6c80d
4
+ data.tar.gz: 6de275fcb284556be10c22cea0e310adecadebab11bd5b884b736b809543120c
5
5
  SHA512:
6
- metadata.gz: 9cd503091f5ba29c416120bdf5eca39535048c920721d0e4180cbfa95b3eb4d40ea77e2f28a9a8f4cb271adbd11050ad6a4a33313a80baf5cfa587a4e81365a1
7
- data.tar.gz: 1948d9a3f5ec7a8ed17030436e513f253c2f1d1e24719f8813128bdb7e3db68f6a6d573cf2dc5e155177c4c1558b0aaf4cf9befbaf0d2a7c71b3ce6b92d3b668
6
+ metadata.gz: 14883eaed6a4655f62908ae53dabadd007e56befb50cb8d5b02790d91441afe3749ecf00019709a5ba39b8bfaafeaa8e475a318e62d1a93f21511ef3611d4238
7
+ data.tar.gz: b58152e34c1e7b7c3f9941715d7f512f71d40b1abbacbb7481e965ceb34969117c56b4a9ee218ed62f087dedc7d85ffdde1d9f43ab6beb25aa6da8b89b9dfde1
@@ -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,21 +1,54 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.3.3] - 2022-02-19
4
+
5
+ - Add `recursive` option to `CallableTree::Node::Internal#reject` and `CallableTree::Node::Internal#reject!`.
6
+ - Add `CallableTree::Node::Internal#find` to return the first node evaluated as `true` by block.
7
+
8
+ ## [0.3.2] - 2022-02-05
9
+
10
+ - Change `CallableTree::Node::Hooks::Call#before_call` to return a new instance.
11
+ To keep the same behavior as the older version, use `CallableTree::Node::Hooks::Call#before_call!` that makes destructive change.
12
+ - Change `CallableTree::Node::Hooks::Call#around_call` to return a new instance.
13
+ To keep the same behavior as the older version, use `CallableTree::Node::Hooks::Call#around_call!` that makes destructive change.
14
+ - Change `CallableTree::Node::Hooks::Call#after_call` to return a new instance.
15
+ To keep the same behavior as the older version, use `CallableTree::Node::Hooks::Call#after_call!` that makes destructive change.
16
+
17
+ ## [0.3.1] - 2022-01-10
18
+
19
+ - Add `CallableTree::Node::Internal#seek?` to check whether the node's strategy is `seek` or not.
20
+ - Add `CallableTree::Node::Internal#broadcast?` to check whether the node's strategy is `broadcast` or not.
21
+ - Add `CallableTree::Node::Internal#compose?` to check whether the node's strategy is `compose` or not.
22
+
23
+ ## [0.3.0] - 2021-12-27
24
+
25
+ - Change `CallableTree::Node#match?` to accept inputs to the node as variable length arguments.
26
+ - Change `CallableTree::Node#call` to accept inputs to the node as variable length arguments.
27
+ - Change `CallableTree::Node#terminate?` to accept inputs to the node as variable length arguments, after the `output` argument.
28
+ - Add `CallableTree::Node::Internal#[]` to return the child node using `index`.
29
+ - Change `CallableTree::Node::Internal#children` to return a new array including child nodes of the node.
30
+ - Add `CallableTree::Node::Internal#children!` to return destructively changeable array including child nodes of the node.
31
+
3
32
  ## [0.2.3] - 2021-11-07
33
+
4
34
  - 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.
5
35
  - Add `CallableTree::Node::Internal#shake!` that make destructive change.
6
36
  - Add `CallableTree::Node#outline` that may be useful for writing the specs.
7
37
 
8
38
  ## [0.2.2] - 2021-10-24
39
+
9
40
  - Add `CallableTree::Node::Internal#reject` to return a new node instance without rejected child nodes.
10
41
  - Add `CallableTree::Node::Internal#reject!` to destructively reject child nodes.
11
42
 
12
43
  ## [0.2.1] - 2021-07-24
44
+
13
45
  - Add `CallableTree::Node#root?`.
14
46
  - Add `CallableTree::Node::Internal#seek!` that make destructive change.
15
47
  - Add `CallableTree::Node::Internal#broadcast!` that make destructive change.
16
48
  - Add `CallableTree::Node::Internal#compose!` that make destructive change.
17
49
 
18
50
  ## [0.2.0] - 2021-06-15
51
+
19
52
  - Change `CallableTree::Node::Internal#append` to return a new instance.
20
53
  To keep the same behavior as the older version, use `CallableTree::Node::External#append!` that make destructive change.
21
54
  - Remove `CallableTree::Node::Internal#<<`. Use `CallableTree::Node::External#append!` instead.
@@ -23,6 +56,7 @@
23
56
  To keep the same behavior as the older version, use `CallableTree::Node::External#verbosify!` that make destructive change.
24
57
 
25
58
  ## [0.1.3] - 2021-06-12
59
+
26
60
  - Minor improvements
27
61
 
28
62
  ## [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.3)
4
+ callable_tree (0.3.3)
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
- rspec (3.10.0)
12
- rspec-core (~> 3.10.0)
13
- rspec-expectations (~> 3.10.0)
14
- rspec-mocks (~> 3.10.0)
15
- rspec-core (3.10.1)
16
- rspec-support (~> 3.10.0)
17
- rspec-expectations (3.10.1)
11
+ rspec (3.11.0)
12
+ rspec-core (~> 3.11.0)
13
+ rspec-expectations (~> 3.11.0)
14
+ rspec-mocks (~> 3.11.0)
15
+ rspec-core (3.11.0)
16
+ rspec-support (~> 3.11.0)
17
+ rspec-expectations (3.11.0)
18
18
  diff-lcs (>= 1.2.0, < 2.0)
19
- rspec-support (~> 3.10.0)
20
- rspec-mocks (3.10.2)
19
+ rspec-support (~> 3.11.0)
20
+ rspec-mocks (3.11.0)
21
21
  diff-lcs (>= 1.2.0, < 2.0)
22
- rspec-support (~> 3.10.0)
23
- rspec-support (3.10.3)
22
+ rspec-support (~> 3.11.0)
23
+ rspec-support (3.11.0)
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)
@@ -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,42 +3,63 @@
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
 
13
19
  def append(*callables)
14
- clone.tap do |node|
15
- node.append!(*callables)
16
- end
20
+ clone.append!(*callables)
17
21
  end
18
22
 
19
23
  def append!(*callables)
20
24
  callables
21
25
  .map { |callable| nodeify(callable) }
22
- .tap { |nodes| child_nodes.push(*nodes) } # Use Array#push for Ruby 2.4
26
+ .tap { |nodes| child_nodes.push(*nodes) }
23
27
 
24
28
  self
25
29
  end
26
30
 
27
- def reject(&block)
28
- clone.tap do |node|
29
- node.reject!(&block)
31
+ def find(recursive: false, &block)
32
+ node = child_nodes.find(&block)
33
+ return node if node
34
+
35
+ if recursive
36
+ child_nodes
37
+ .lazy
38
+ .select { |node| node.is_a?(Internal) }
39
+ .map { |node| node.find(recursive: true, &block) }
40
+ .reject(&:nil?)
41
+ .first
30
42
  end
31
43
  end
32
44
 
33
- def reject!(&block)
45
+ def reject(recursive: false, &block)
46
+ clone.reject!(recursive: recursive, &block)
47
+ end
48
+
49
+ def reject!(recursive: false, &block)
34
50
  child_nodes.reject!(&block)
51
+
52
+ if recursive
53
+ child_nodes.each do |node|
54
+ node.reject!(recursive: true, &block) if node.is_a?(Internal)
55
+ end
56
+ end
57
+
35
58
  self
36
59
  end
37
60
 
38
61
  def shake(&block)
39
- clone.tap do |node|
40
- node.shake!(&block)
41
- end
62
+ clone.shake!(&block)
42
63
  end
43
64
 
44
65
  def shake!(&block)
@@ -49,57 +70,72 @@ module CallableTree
49
70
  end
50
71
  end
51
72
 
52
- def match?(_input = nil, **_options)
73
+ def match?(*, **)
53
74
  !child_nodes.empty?
54
75
  end
55
76
 
56
- def call(input = nil, **options)
57
- strategy.call(child_nodes, input: input, options: options)
77
+ def call(*inputs, **options)
78
+ strategy.call(child_nodes, *inputs, **options)
79
+ end
80
+
81
+ def seek?
82
+ strategy.is_a?(Strategy::Seek)
58
83
  end
59
84
 
60
85
  def seek
61
- if strategy.is_a?(Strategy::Seek)
86
+ if seek?
62
87
  self
63
88
  else
64
89
  clone.tap do |node|
65
- node.send(:strategy=, Strategy::Seek.new)
90
+ node.strategy = Strategy::Seek.new
66
91
  end
67
92
  end
68
93
  end
69
94
 
70
95
  def seek!
71
- self.strategy = Strategy::Seek.new unless strategy.is_a?(Strategy::Seek)
72
- self
96
+ tap do |node|
97
+ node.strategy = Strategy::Seek.new unless seek?
98
+ end
99
+ end
100
+
101
+ def broadcast?
102
+ strategy.is_a?(Strategy::Broadcast)
73
103
  end
74
104
 
75
105
  def broadcast
76
- if strategy.is_a?(Strategy::Broadcast)
106
+ if broadcast?
77
107
  self
78
108
  else
79
109
  clone.tap do |node|
80
- node.send(:strategy=, Strategy::Broadcast.new)
110
+ node.strategy = Strategy::Broadcast.new
81
111
  end
82
112
  end
83
113
  end
84
114
 
85
115
  def broadcast!
86
- self.strategy = Strategy::Broadcast.new unless strategy.is_a?(Strategy::Broadcast)
87
- self
116
+ tap do |node|
117
+ node.strategy = Strategy::Broadcast.new unless broadcast?
118
+ end
119
+ end
120
+
121
+ def compose?
122
+ strategy.is_a?(Strategy::Compose)
88
123
  end
89
124
 
90
125
  def compose
91
- if strategy.is_a?(Strategy::Compose)
126
+ if compose?
92
127
  self
93
128
  else
94
129
  clone.tap do |node|
95
- node.send(:strategy=, Strategy::Compose.new)
130
+ node.strategy = Strategy::Compose.new
96
131
  end
97
132
  end
98
133
  end
99
134
 
100
135
  def compose!
101
- self.strategy = Strategy::Compose.new unless strategy.is_a?(Strategy::Compose)
102
- self
136
+ tap do |node|
137
+ node.strategy = Strategy::Compose.new unless compose?
138
+ end
103
139
  end
104
140
 
105
141
  def outline(&block)
@@ -110,13 +146,15 @@ module CallableTree
110
146
 
111
147
  protected
112
148
 
149
+ attr_writer :strategy
150
+
113
151
  def child_nodes
114
152
  @child_nodes ||= []
115
153
  end
116
154
 
117
155
  private
118
156
 
119
- attr_writer :child_nodes, :strategy
157
+ attr_writer :child_nodes
120
158
 
121
159
  def nodeify(callable)
122
160
  if callable.is_a?(Node)
@@ -124,7 +162,7 @@ module CallableTree
124
162
  else
125
163
  External.proxify(callable)
126
164
  end
127
- .tap { |node| node.send(:parent=, self) }
165
+ .tap { |node| node.parent = self }
128
166
  end
129
167
 
130
168
  def strategy
@@ -135,7 +173,7 @@ module CallableTree
135
173
  super
136
174
  self.parent = nil
137
175
  self.child_nodes = child_nodes.map do |node|
138
- node.clone.tap { |new_node| new_node.send(:parent=, self) }
176
+ node.clone.tap { |new_node| new_node.parent = self }
139
177
  end
140
178
  end
141
179
  end
@@ -34,19 +34,19 @@ module CallableTree
34
34
  raise ::CallableTree::Error, 'Not implemented'
35
35
  end
36
36
 
37
- def match?(_input = nil, **_options)
37
+ def match?(*_inputs, **_options)
38
38
  true
39
39
  end
40
40
 
41
- def call(_input = nil, **_options)
41
+ def call(*_inputs, **_options)
42
42
  raise ::CallableTree::Error, 'Not implemented'
43
43
  end
44
44
 
45
- def terminate?(output = nil, **_options)
45
+ def terminate?(output, *_inputs, **_options)
46
46
  !output.nil?
47
47
  end
48
48
 
49
- private
49
+ protected
50
50
 
51
51
  attr_writer :parent
52
52
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module CallableTree
4
- VERSION = '0.2.3'
4
+ VERSION = '0.3.3'
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.3
4
+ version: 0.3.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - jsmmr
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-11-07 00:00:00.000000000 Z
11
+ date: 2022-02-19 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.3/CHANGELOG.md
65
+ changelog_uri: https://github.com/jsmmr/ruby_callable_tree/blob/v0.3.3/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