callable_tree 0.2.1 → 0.3.1

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: 23417eaf997718c6d0e9b5fc52dea3fe4923ca9b426d9d41e57b5e27015d239a
4
- data.tar.gz: 34be74baf1014e41efbe0073fedfdf76dc02444c927bea2b089d9457842c04b8
3
+ metadata.gz: c16eb0b2fd83ffd98d61bca938bd449dac9c004e8240c4f1a3b61242bf841163
4
+ data.tar.gz: 9919ffcda275a5a5bcf81b0bfae40087cae1f701fc0b7b915fece81c21a79d6b
5
5
  SHA512:
6
- metadata.gz: 686e18552c5decad326d7bd0775a2be0b3726245edea1ccf2dbdf0ca3e264ec88883bf79cea5af873b074feff1b63e49b59522b5f3b7fc00e06122d494277cea
7
- data.tar.gz: 7db8a88a1bc19677f453237dd15137da05f3fdb2ddb25aeedd11df82e6afd7c769d3da3c61e9905c40285d35ea54059c6749b4f32a354fc542d7bd26fdd8992f
6
+ metadata.gz: 98c022cc2b12dccf2333f1a1fc079febe80f597bbbfbd4565384b88987c92c2426d7986ee80c11e1361139b95d495fdff9237e4f986d57dbb7eb355ce8244a0b
7
+ data.tar.gz: bcee44379ab11292a5c3bba4b0d37f2bdc2a6f587f9a2a757c11c6093d29fdbd1fe20bd9e0ee6561d98785121222ae1959b412ca8b4ecb5ddf579504f5a704c4
@@ -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.0
1
+ 3.1.0
data/CHANGELOG.md CHANGED
@@ -1,12 +1,40 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.3.1] - 2022-01-10
4
+
5
+ - Add `CallableTree::Node::Internal#seek?` to check whether the node's strategy is `seek` or not.
6
+ - Add `CallableTree::Node::Internal#broadcast?` to check whether the node's strategy is `broadcast` or not.
7
+ - Add `CallableTree::Node::Internal#compose?` to check whether the node's strategy is `compose` or not.
8
+
9
+ ## [0.3.0] - 2021-12-27
10
+
11
+ - Change `CallableTree::Node#match?` to accept inputs to the node as variable length arguments.
12
+ - Change `CallableTree::Node#call` to accept inputs to the node as variable length arguments.
13
+ - Change `CallableTree::Node#terminate?` to accept inputs to the node as variable length arguments, after the `output` argument.
14
+ - Add `CallableTree::Node::Internal#[]` to return the child node using `index`.
15
+ - Change `CallableTree::Node::Internal#children` to return a new array including child nodes of the node.
16
+ - Add `CallableTree::Node::Internal#children!` to return destructively changeable array including child nodes of the node.
17
+
18
+ ## [0.2.3] - 2021-11-07
19
+
20
+ - 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.
21
+ - Add `CallableTree::Node::Internal#shake!` that make destructive change.
22
+ - Add `CallableTree::Node#outline` that may be useful for writing the specs.
23
+
24
+ ## [0.2.2] - 2021-10-24
25
+
26
+ - Add `CallableTree::Node::Internal#reject` to return a new node instance without rejected child nodes.
27
+ - Add `CallableTree::Node::Internal#reject!` to destructively reject child nodes.
28
+
3
29
  ## [0.2.1] - 2021-07-24
4
- - Add `CallableTree::Node::root?`.
30
+
31
+ - Add `CallableTree::Node#root?`.
5
32
  - Add `CallableTree::Node::Internal#seek!` that make destructive change.
6
33
  - Add `CallableTree::Node::Internal#broadcast!` that make destructive change.
7
34
  - Add `CallableTree::Node::Internal#compose!` that make destructive change.
8
35
 
9
36
  ## [0.2.0] - 2021-06-15
37
+
10
38
  - Change `CallableTree::Node::Internal#append` to return a new instance.
11
39
  To keep the same behavior as the older version, use `CallableTree::Node::External#append!` that make destructive change.
12
40
  - Remove `CallableTree::Node::Internal#<<`. Use `CallableTree::Node::External#append!` instead.
@@ -14,6 +42,7 @@
14
42
  To keep the same behavior as the older version, use `CallableTree::Node::External#verbosify!` that make destructive change.
15
43
 
16
44
  ## [0.1.3] - 2021-06-12
45
+
17
46
  - Minor improvements
18
47
 
19
48
  ## [0.1.2] - 2021-05-29
data/Gemfile.lock CHANGED
@@ -1,12 +1,12 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- callable_tree (0.2.1)
4
+ callable_tree (0.3.1)
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)
@@ -20,7 +20,7 @@ GEM
20
20
  rspec-mocks (3.10.2)
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.17
35
+ 2.3.3
data/LICENSE.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2021  
3
+ Copyright (c) 2021 jsmmr
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -1,5 +1,8 @@
1
1
  # CallableTree
2
2
 
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)
5
+
3
6
  ## Installation
4
7
 
5
8
  Add this line to your application's Gemfile:
@@ -40,11 +43,11 @@ module Node
40
43
  class Parser
41
44
  include CallableTree::Node::Internal
42
45
 
43
- def match?(input, **options)
46
+ def match?(input, **_options)
44
47
  File.extname(input) == '.json'
45
48
  end
46
49
 
47
- # If there is need to convert the input value for
50
+ # If there is need to convert the input values for
48
51
  # child nodes, override the `call` method.
49
52
  def call(input, **options)
50
53
  File.open(input) do |file|
@@ -56,7 +59,7 @@ module Node
56
59
  # If a returned value of the `call` method is `nil`,
57
60
  # but there is no need to call the sibling nodes,
58
61
  # override the `terminate?` method to return `true`.
59
- def terminate?(output, **options)
62
+ def terminate?(_output, *_inputs, **_options)
60
63
  true
61
64
  end
62
65
  end
@@ -68,11 +71,11 @@ module Node
68
71
  @type = type
69
72
  end
70
73
 
71
- def match?(input, **options)
74
+ def match?(input, **_options)
72
75
  !!input[@type.to_s]
73
76
  end
74
77
 
75
- def call(input, **options)
78
+ def call(input, **_options)
76
79
  input[@type.to_s]
77
80
  .map { |element| [element['name'], element['emoji']] }
78
81
  .to_h
@@ -84,11 +87,11 @@ module Node
84
87
  class Parser
85
88
  include CallableTree::Node::Internal
86
89
 
87
- def match?(input, **options)
90
+ def match?(input, **_options)
88
91
  File.extname(input) == '.xml'
89
92
  end
90
93
 
91
- # If there is need to convert the input value for
94
+ # If there is need to convert the input values for
92
95
  # child nodes, override the `call` method.
93
96
  def call(input, **options)
94
97
  File.open(input) do |file|
@@ -99,7 +102,7 @@ module Node
99
102
  # If a returned value of the `call` method is `nil`,
100
103
  # but there is no need to call the sibling nodes,
101
104
  # override the `terminate?` method to return `true`.
102
- def terminate?(output, **options)
105
+ def terminate?(_output, *_inputs, **_options)
103
106
  true
104
107
  end
105
108
  end
@@ -111,11 +114,11 @@ module Node
111
114
  @type = type
112
115
  end
113
116
 
114
- def match?(input, **options)
117
+ def match?(input, **_options)
115
118
  !input.get_elements("//#{@type}").empty?
116
119
  end
117
120
 
118
- def call(input, **options)
121
+ def call(input, **_options)
119
122
  input
120
123
  .get_elements("//#{@type}")
121
124
  .first
@@ -138,7 +141,7 @@ tree = CallableTree::Node::Root.new.append(
138
141
  )#.seek
139
142
  )#.seek
140
143
 
141
- Dir.glob(__dir__ + '/docs/*') do |file|
144
+ Dir.glob("#{__dir__}/docs/*") do |file|
142
145
  options = { foo: :bar }
143
146
  pp tree.call(file, **options)
144
147
  puts '---'
@@ -180,12 +183,12 @@ end
180
183
 
181
184
  tree = CallableTree::Node::Root.new.append(
182
185
  Node::LessThan.new(5).append(
183
- lambda { |input, **| input * 2 }, # anonymous external node
184
- lambda { |input, **| input + 1 } # anonymous external node
186
+ ->(input) { input * 2 }, # anonymous external node
187
+ ->(input) { input + 1 } # anonymous external node
185
188
  ).broadcast,
186
189
  Node::LessThan.new(10).append(
187
- lambda { |input, **| input * 3 }, # anonymous external node
188
- lambda { |input, **| input - 1 } # anonymous external node
190
+ ->(input) { input * 3 }, # anonymous external node
191
+ ->(input) { input - 1 } # anonymous external node
189
192
  ).broadcast
190
193
  ).broadcast
191
194
 
@@ -432,28 +435,28 @@ This is an example of logging.
432
435
  module Node
433
436
  module Logging
434
437
  INDENT_SIZE = 2
435
- BLANK = ' '.freeze
438
+ BLANK = ' '
436
439
 
437
440
  module Match
438
- LIST_STYLE = '*'.freeze
441
+ LIST_STYLE = '*'
439
442
 
440
- def match?(_input, **)
443
+ def match?(_input, **_options)
441
444
  super.tap do |matched|
442
- prefix = LIST_STYLE.rjust(self.depth * INDENT_SIZE - INDENT_SIZE + LIST_STYLE.length, BLANK)
443
- 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}]"
444
447
  end
445
448
  end
446
449
  end
447
450
 
448
451
  module Call
449
- INPUT_LABEL = 'Input :'.freeze
450
- OUTPUT_LABEL = 'Output:'.freeze
452
+ INPUT_LABEL = 'Input :'
453
+ OUTPUT_LABEL = 'Output:'
451
454
 
452
- def call(input, **)
455
+ def call(input, **_options)
453
456
  super.tap do |output|
454
- 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)
455
458
  puts "#{input_prefix} #{input}"
456
- 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)
457
460
  puts "#{output_prefix} #{output}"
458
461
  end
459
462
  end
@@ -577,24 +580,24 @@ module Node
577
580
  end
578
581
 
579
582
  Node::HooksSample.new
580
- .before_call do |input, **options|
583
+ .before_call do |input, **_options|
581
584
  puts "before_call input: #{input}";
582
585
  input + 1
583
586
  end
584
587
  .append(
585
588
  # anonymous external node
586
- lambda do |input, **options|
589
+ lambda do |input, **_options|
587
590
  puts "external input: #{input}"
588
591
  input * 2
589
592
  end
590
593
  )
591
- .around_call do |input, **options, &block|
594
+ .around_call do |input, **_options, &block|
592
595
  puts "around_call input: #{input}"
593
596
  output = block.call
594
597
  puts "around_call output: #{output}"
595
598
  output * input
596
599
  end
597
- .after_call do |output, **options|
600
+ .after_call do |output, **_options|
598
601
  puts "after_call output: #{output}"
599
602
  output * 2
600
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
@@ -8,24 +10,24 @@ module Node
8
10
  end
9
11
 
10
12
  Node::HooksSample.new
11
- .before_call do |input, **options|
13
+ .before_call do |input, **_options|
12
14
  puts "before_call input: #{input}";
13
15
  input + 1
14
16
  end
15
17
  .append(
16
18
  # anonymous external node
17
- lambda do |input, **options|
19
+ lambda do |input, **_options|
18
20
  puts "external input: #{input}"
19
21
  input * 2
20
22
  end
21
23
  )
22
- .around_call do |input, **options, &block|
24
+ .around_call do |input, **_options, &block|
23
25
  puts "around_call input: #{input}"
24
26
  output = block.call
25
27
  puts "around_call output: #{output}"
26
28
  output * input
27
29
  end
28
- .after_call do |output, **options|
30
+ .after_call do |output, **_options|
29
31
  puts "after_call output: #{output}"
30
32
  output * 2
31
33
  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)
@@ -23,15 +23,17 @@ module CallableTree
23
23
  self
24
24
  end
25
25
 
26
- def call(input = nil, **options)
27
- input = before_callbacks.reduce(input) do |input, callable|
28
- callable.call(input, self, **options)
26
+ def call(*inputs, **options)
27
+ input_head, *input_tail = inputs
28
+
29
+ input_head = before_callbacks.reduce(input_head) do |input_head, callable|
30
+ callable.call(input_head, *input_tail, self, **options)
29
31
  end
30
32
 
31
- output = super(input, **options)
33
+ output = super(input_head, *input_tail, **options)
32
34
 
33
35
  output = around_callbacks.reduce(output) do |output, callable|
34
- callable.call(input, self, **options) { output }
36
+ callable.call(input_head, *input_tail, self, **options) { output }
35
37
  end
36
38
 
37
39
  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,17 @@
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
- @children ||= []
12
+ [*child_nodes]
13
+ end
14
+
15
+ def children!
16
+ child_nodes
10
17
  end
11
18
 
12
19
  def append(*callables)
@@ -18,67 +25,121 @@ module CallableTree
18
25
  def append!(*callables)
19
26
  callables
20
27
  .map { |callable| nodeify(callable) }
21
- .tap { |nodes| children.push(*nodes) } # Use Array#push for Ruby 2.4
28
+ .tap { |nodes| child_nodes.push(*nodes) }
29
+
30
+ self
31
+ end
32
+
33
+ def reject(&block)
34
+ clone.tap do |node|
35
+ node.reject!(&block)
36
+ end
37
+ end
22
38
 
39
+ def reject!(&block)
40
+ child_nodes.reject!(&block)
23
41
  self
24
42
  end
25
43
 
26
- def match?(_input = nil, **_options)
27
- !children.empty?
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?(*, **)
59
+ !child_nodes.empty?
28
60
  end
29
61
 
30
- def call(input = nil, **options)
31
- strategy.call(children, 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)
32
68
  end
33
69
 
34
70
  def seek
35
- if strategy.is_a?(Strategy::Seek)
71
+ if seek?
36
72
  self
37
73
  else
38
74
  clone.tap do |node|
39
- node.send(:strategy=, Strategy::Seek.new)
75
+ node.strategy = Strategy::Seek.new
40
76
  end
41
77
  end
42
78
  end
43
79
 
44
80
  def seek!
45
- self.strategy = Strategy::Seek.new unless strategy.is_a?(Strategy::Seek)
46
- 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)
47
88
  end
48
89
 
49
90
  def broadcast
50
- if strategy.is_a?(Strategy::Broadcast)
91
+ if broadcast?
51
92
  self
52
93
  else
53
94
  clone.tap do |node|
54
- node.send(:strategy=, Strategy::Broadcast.new)
95
+ node.strategy = Strategy::Broadcast.new
55
96
  end
56
97
  end
57
98
  end
58
99
 
59
100
  def broadcast!
60
- self.strategy = Strategy::Broadcast.new unless strategy.is_a?(Strategy::Broadcast)
61
- 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)
62
108
  end
63
109
 
64
110
  def compose
65
- if strategy.is_a?(Strategy::Compose)
111
+ if compose?
66
112
  self
67
113
  else
68
114
  clone.tap do |node|
69
- node.send(:strategy=, Strategy::Compose.new)
115
+ node.strategy = Strategy::Compose.new
70
116
  end
71
117
  end
72
118
  end
73
119
 
74
120
  def compose!
75
- self.strategy = Strategy::Compose.new unless strategy.is_a?(Strategy::Compose)
76
- self
121
+ tap do |node|
122
+ node.strategy = Strategy::Compose.new unless compose?
123
+ end
124
+ end
125
+
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
133
+
134
+ attr_writer :strategy
135
+
136
+ def child_nodes
137
+ @child_nodes ||= []
77
138
  end
78
139
 
79
140
  private
80
141
 
81
- attr_writer :children, :strategy
142
+ attr_writer :child_nodes
82
143
 
83
144
  def nodeify(callable)
84
145
  if callable.is_a?(Node)
@@ -86,7 +147,7 @@ module CallableTree
86
147
  else
87
148
  External.proxify(callable)
88
149
  end
89
- .tap { |node| node.send(:parent=, self) }
150
+ .tap { |node| node.parent = self }
90
151
  end
91
152
 
92
153
  def strategy
@@ -96,8 +157,8 @@ module CallableTree
96
157
  def initialize_copy(_node)
97
158
  super
98
159
  self.parent = nil
99
- self.children = children.map do |node|
100
- node.clone.tap { |new_node| new_node.send(:parent=, self) }
160
+ self.child_nodes = child_nodes.map do |node|
161
+ node.clone.tap { |new_node| new_node.parent = self }
101
162
  end
102
163
  end
103
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.1'
4
+ VERSION = '0.3.1'
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.1
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - jsmmr
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-07-24 00:00:00.000000000 Z
11
+ date: 2022-01-10 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.1/CHANGELOG.md
65
+ changelog_uri: https://github.com/jsmmr/ruby_callable_tree/blob/v0.3.1/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.16
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