callable_tree 0.2.3 → 0.3.3

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: 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