callable_tree 0.2.0 → 0.3.0

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: 9213a2a82a38c85e401f291bf2d37e60210bf167c765576033eed93fb1d7cbbd
4
- data.tar.gz: 4a3f2fce73c82b8e5b7e537d21eeedc500e84dbe9f3c972c596701b654a9f234
3
+ metadata.gz: d7daab378247c364839a830fd43b028fd0933cef6026a1df1a614fb4a59c7a66
4
+ data.tar.gz: 66ac7c3de2198ef3acd80bddadeccc0f3ccd34e5a3d3de7d959bd43fb0801436
5
5
  SHA512:
6
- metadata.gz: 72ccbffb1ffe2e66ddf41b2f29c715c9cda1d6a91dc8ee5ef493bcaa531b2c1c99ee9024b1776a8c9ecad6e82b84b051d0121c55e9abc26a1ba3d4bb449dced2
7
- data.tar.gz: 243f05208c10de0a60af884479f8a2a9d3edc5735b16fece2994b694d0734bf75f57f1dfc57afc8c265df038fe736fd86e063042362d495140410819f47bbc70
6
+ metadata.gz: 7b15c987aeeab91a5250f48e6d429d4176478f74dc7866a0209b0cf7f82909f58fa8f96dbae30c5d37151e63f8dab6c1e8028b2faf15b3919d9afe9ed43eb4fd
7
+ data.tar.gz: eb1017e10c4f94635058523979c2aeea5edd7d6899a932f2481ae72bd93b74657cd73dc2c1a12935b069e34910f9dba260ef8b62cb70e8a4f4b6dc73915ba0e5
@@ -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,6 +1,34 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.3.0] - 2021-12-27
4
+
5
+ - Change `CallableTree::Node#match?` to accept inputs to the node as variable length arguments.
6
+ - Change `CallableTree::Node#call` to accept inputs to the node as variable length arguments.
7
+ - Change `CallableTree::Node#terminate?` to accept inputs to the node as variable length arguments, after the `output` argument.
8
+ - Add `CallableTree::Node::Internal#[]` to return the child node using `index`.
9
+ - Change `CallableTree::Node::Internal#children` to return a new array including child nodes of the node.
10
+ - Add `CallableTree::Node::Internal#children!` to return destructively changeable array including child nodes of the node.
11
+
12
+ ## [0.2.3] - 2021-11-07
13
+
14
+ - 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.
15
+ - Add `CallableTree::Node::Internal#shake!` that make destructive change.
16
+ - Add `CallableTree::Node#outline` that may be useful for writing the specs.
17
+
18
+ ## [0.2.2] - 2021-10-24
19
+
20
+ - Add `CallableTree::Node::Internal#reject` to return a new node instance without rejected child nodes.
21
+ - Add `CallableTree::Node::Internal#reject!` to destructively reject child nodes.
22
+
23
+ ## [0.2.1] - 2021-07-24
24
+
25
+ - Add `CallableTree::Node#root?`.
26
+ - Add `CallableTree::Node::Internal#seek!` that make destructive change.
27
+ - Add `CallableTree::Node::Internal#broadcast!` that make destructive change.
28
+ - Add `CallableTree::Node::Internal#compose!` that make destructive change.
29
+
3
30
  ## [0.2.0] - 2021-06-15
31
+
4
32
  - Change `CallableTree::Node::Internal#append` to return a new instance.
5
33
  To keep the same behavior as the older version, use `CallableTree::Node::External#append!` that make destructive change.
6
34
  - Remove `CallableTree::Node::Internal#<<`. Use `CallableTree::Node::External#append!` instead.
@@ -8,6 +36,7 @@
8
36
  To keep the same behavior as the older version, use `CallableTree::Node::External#verbosify!` that make destructive change.
9
37
 
10
38
  ## [0.1.3] - 2021-06-12
39
+
11
40
  - Minor improvements
12
41
 
13
42
  ## [0.1.2] - 2021-05-29
data/Gemfile.lock CHANGED
@@ -1,13 +1,13 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- callable_tree (0.2.0)
4
+ callable_tree (0.3.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
8
8
  specs:
9
- diff-lcs (1.4.4)
10
- rake (13.0.3)
9
+ diff-lcs (1.5.0)
10
+ rake (13.0.6)
11
11
  rspec (3.10.0)
12
12
  rspec-core (~> 3.10.0)
13
13
  rspec-expectations (~> 3.10.0)
@@ -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,7 @@
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
+
3
5
  ## Installation
4
6
 
5
7
  Add this line to your application's Gemfile:
@@ -40,11 +42,11 @@ module Node
40
42
  class Parser
41
43
  include CallableTree::Node::Internal
42
44
 
43
- def match?(input, **options)
45
+ def match?(input, **_options)
44
46
  File.extname(input) == '.json'
45
47
  end
46
48
 
47
- # If there is need to convert the input value for
49
+ # If there is need to convert the input values for
48
50
  # child nodes, override the `call` method.
49
51
  def call(input, **options)
50
52
  File.open(input) do |file|
@@ -56,7 +58,7 @@ module Node
56
58
  # If a returned value of the `call` method is `nil`,
57
59
  # but there is no need to call the sibling nodes,
58
60
  # override the `terminate?` method to return `true`.
59
- def terminate?(output, **options)
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[@type.to_s]
73
75
  end
74
76
 
75
- def call(input, **options)
77
+ def call(input, **_options)
76
78
  input[@type.to_s]
77
79
  .map { |element| [element['name'], element['emoji']] }
78
80
  .to_h
@@ -84,11 +86,11 @@ module Node
84
86
  class Parser
85
87
  include CallableTree::Node::Internal
86
88
 
87
- def match?(input, **options)
89
+ def match?(input, **_options)
88
90
  File.extname(input) == '.xml'
89
91
  end
90
92
 
91
- # If there is need to convert the input value for
93
+ # If there is need to convert the input values for
92
94
  # child nodes, override the `call` method.
93
95
  def call(input, **options)
94
96
  File.open(input) do |file|
@@ -99,7 +101,7 @@ module Node
99
101
  # If a returned value of the `call` method is `nil`,
100
102
  # but there is no need to call the sibling nodes,
101
103
  # override the `terminate?` method to return `true`.
102
- def terminate?(output, **options)
104
+ def terminate?(_output, *_inputs, **_options)
103
105
  true
104
106
  end
105
107
  end
@@ -111,11 +113,11 @@ module Node
111
113
  @type = type
112
114
  end
113
115
 
114
- def match?(input, **options)
116
+ def match?(input, **_options)
115
117
  !input.get_elements("//#{@type}").empty?
116
118
  end
117
119
 
118
- def call(input, **options)
120
+ def call(input, **_options)
119
121
  input
120
122
  .get_elements("//#{@type}")
121
123
  .first
@@ -138,7 +140,7 @@ tree = CallableTree::Node::Root.new.append(
138
140
  )#.seek
139
141
  )#.seek
140
142
 
141
- Dir.glob(__dir__ + '/docs/*') do |file|
143
+ Dir.glob("#{__dir__}/docs/*") do |file|
142
144
  options = { foo: :bar }
143
145
  pp tree.call(file, **options)
144
146
  puts '---'
@@ -180,12 +182,12 @@ end
180
182
 
181
183
  tree = CallableTree::Node::Root.new.append(
182
184
  Node::LessThan.new(5).append(
183
- lambda { |input, **| input * 2 }, # anonymous external node
184
- lambda { |input, **| input + 1 } # anonymous external node
185
+ ->(input) { input * 2 }, # anonymous external node
186
+ ->(input) { input + 1 } # anonymous external node
185
187
  ).broadcast,
186
188
  Node::LessThan.new(10).append(
187
- lambda { |input, **| input * 3 }, # anonymous external node
188
- lambda { |input, **| input - 1 } # anonymous external node
189
+ ->(input) { input * 3 }, # anonymous external node
190
+ ->(input) { input - 1 } # anonymous external node
189
191
  ).broadcast
190
192
  ).broadcast
191
193
 
@@ -432,28 +434,28 @@ This is an example of logging.
432
434
  module Node
433
435
  module Logging
434
436
  INDENT_SIZE = 2
435
- BLANK = ' '.freeze
437
+ BLANK = ' '
436
438
 
437
439
  module Match
438
- LIST_STYLE = '*'.freeze
440
+ LIST_STYLE = '*'
439
441
 
440
- def match?(_input, **)
442
+ def match?(_input, **_options)
441
443
  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}]"
444
+ prefix = LIST_STYLE.rjust(depth * INDENT_SIZE - INDENT_SIZE + LIST_STYLE.length, BLANK)
445
+ puts "#{prefix} #{identity}: [matched: #{matched}]"
444
446
  end
445
447
  end
446
448
  end
447
449
 
448
450
  module Call
449
- INPUT_LABEL = 'Input :'.freeze
450
- OUTPUT_LABEL = 'Output:'.freeze
451
+ INPUT_LABEL = 'Input :'
452
+ OUTPUT_LABEL = 'Output:'
451
453
 
452
- def call(input, **)
454
+ def call(input, **_options)
453
455
  super.tap do |output|
454
- input_prefix = INPUT_LABEL.rjust(self.depth * INDENT_SIZE + INPUT_LABEL.length, BLANK)
456
+ input_prefix = INPUT_LABEL.rjust(depth * INDENT_SIZE + INPUT_LABEL.length, BLANK)
455
457
  puts "#{input_prefix} #{input}"
456
- output_prefix = OUTPUT_LABEL.rjust(self.depth * INDENT_SIZE + OUTPUT_LABEL.length, BLANK)
458
+ output_prefix = OUTPUT_LABEL.rjust(depth * INDENT_SIZE + OUTPUT_LABEL.length, BLANK)
457
459
  puts "#{output_prefix} #{output}"
458
460
  end
459
461
  end
@@ -577,24 +579,24 @@ module Node
577
579
  end
578
580
 
579
581
  Node::HooksSample.new
580
- .before_call do |input, **options|
582
+ .before_call do |input, **_options|
581
583
  puts "before_call input: #{input}";
582
584
  input + 1
583
585
  end
584
586
  .append(
585
587
  # anonymous external node
586
- lambda do |input, **options|
588
+ lambda do |input, **_options|
587
589
  puts "external input: #{input}"
588
590
  input * 2
589
591
  end
590
592
  )
591
- .around_call do |input, **options, &block|
593
+ .around_call do |input, **_options, &block|
592
594
  puts "around_call input: #{input}"
593
595
  output = block.call
594
596
  puts "around_call output: #{output}"
595
597
  output * input
596
598
  end
597
- .after_call do |output, **options|
599
+ .after_call do |output, **_options|
598
600
  puts "after_call output: #{output}"
599
601
  output * 2
600
602
  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,11 +37,15 @@ 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)
43
47
  super
44
- send(:parent=, nil)
48
+ self.parent = nil
45
49
  end
46
50
 
47
51
  class Proxy
@@ -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|
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CallableTree
4
+ module Node
5
+ module Internal
6
+ module Strategy
7
+ class Broadcast
8
+ def call(nodes, *inputs, **options)
9
+ nodes.map do |node|
10
+ node.call(*inputs, **options) if node.match?(*inputs, **options)
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CallableTree
4
+ module Node
5
+ module Internal
6
+ module Strategy
7
+ class Compose
8
+ def call(nodes, *inputs, **options)
9
+ head, *tail = inputs
10
+ nodes.reduce(head) do |input, node|
11
+ inputs = [input, *tail]
12
+ if node.match?(*inputs, **options)
13
+ node.call(*inputs, **options)
14
+ else
15
+ input
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CallableTree
4
+ module Node
5
+ module Internal
6
+ module Strategy
7
+ class Seek
8
+ def call(nodes, *inputs, **options)
9
+ nodes
10
+ .lazy
11
+ .select { |node| node.match?(*inputs, **options) }
12
+ .map do |node|
13
+ output = node.call(*inputs, **options)
14
+ terminated = node.terminate?(output, *inputs, **options)
15
+ [output, terminated]
16
+ end
17
+ .select { |_output, terminated| terminated }
18
+ .map { |output, _terminated| output }
19
+ .first
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ 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,52 +25,104 @@ 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) } # Use Array#push for Ruby 2.4
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)
32
64
  end
33
65
 
34
66
  def seek
35
- if strategy.is_a?(Seek)
67
+ if strategy.is_a?(Strategy::Seek)
36
68
  self
37
69
  else
38
70
  clone.tap do |node|
39
- node.send(:strategy=, Seek.new)
71
+ node.send(:strategy=, Strategy::Seek.new)
40
72
  end
41
73
  end
42
74
  end
43
75
 
76
+ def seek!
77
+ self.strategy = Strategy::Seek.new unless strategy.is_a?(Strategy::Seek)
78
+ self
79
+ end
80
+
44
81
  def broadcast
45
- if strategy.is_a?(Broadcast)
82
+ if strategy.is_a?(Strategy::Broadcast)
46
83
  self
47
84
  else
48
85
  clone.tap do |node|
49
- node.send(:strategy=, Broadcast.new)
86
+ node.send(:strategy=, Strategy::Broadcast.new)
50
87
  end
51
88
  end
52
89
  end
53
90
 
91
+ def broadcast!
92
+ self.strategy = Strategy::Broadcast.new unless strategy.is_a?(Strategy::Broadcast)
93
+ self
94
+ end
95
+
54
96
  def compose
55
- if strategy.is_a?(Compose)
97
+ if strategy.is_a?(Strategy::Compose)
56
98
  self
57
99
  else
58
100
  clone.tap do |node|
59
- node.send(:strategy=, Compose.new)
101
+ node.send(:strategy=, Strategy::Compose.new)
60
102
  end
61
103
  end
62
104
  end
63
105
 
106
+ def compose!
107
+ self.strategy = Strategy::Compose.new unless strategy.is_a?(Strategy::Compose)
108
+ self
109
+ end
110
+
111
+ def outline(&block)
112
+ key = block ? block.call(self) : identity
113
+ value = child_nodes.reduce({}) { |memo, node| memo.merge!(node.outline(&block)) }
114
+ { key => value }
115
+ end
116
+
117
+ protected
118
+
119
+ def child_nodes
120
+ @child_nodes ||= []
121
+ end
122
+
64
123
  private
65
124
 
66
- attr_writer :children, :strategy
125
+ attr_writer :child_nodes, :strategy
67
126
 
68
127
  def nodeify(callable)
69
128
  if callable.is_a?(Node)
@@ -71,17 +130,17 @@ module CallableTree
71
130
  else
72
131
  External.proxify(callable)
73
132
  end
74
- .tap { |node| node.send(:parent=, self) }
133
+ .tap { |node| node.send(:parent=, self) }
75
134
  end
76
135
 
77
136
  def strategy
78
- @strategy ||= Seek.new
137
+ @strategy ||= Strategy::Seek.new
79
138
  end
80
139
 
81
140
  def initialize_copy(_node)
82
141
  super
83
- send(:parent=, nil)
84
- self.children = children.map do |node|
142
+ self.parent = nil
143
+ self.child_nodes = child_nodes.map do |node|
85
144
  node.clone.tap { |new_node| new_node.send(:parent=, self) }
86
145
  end
87
146
  end
@@ -4,12 +4,16 @@ module CallableTree
4
4
  module Node
5
5
  attr_reader :parent
6
6
 
7
+ def root?
8
+ parent.nil?
9
+ end
10
+
7
11
  def ancestors
8
12
  ::Enumerator.new do |y|
9
13
  node = self
10
14
  loop do
11
15
  y << node
12
- break unless node = node&.parent
16
+ break unless node = node.parent
13
17
  end
14
18
  end
15
19
  end
@@ -23,18 +27,22 @@ module CallableTree
23
27
  end
24
28
 
25
29
  def depth
26
- parent.nil? ? 0 : parent.depth + 1
30
+ root? ? 0 : parent.depth + 1
31
+ end
32
+
33
+ def outline
34
+ raise ::CallableTree::Error, 'Not implemented'
27
35
  end
28
36
 
29
- def match?(_input = nil, **_options)
37
+ def match?(*_inputs, **_options)
30
38
  true
31
39
  end
32
40
 
33
- def call(_input = nil, **_options)
41
+ def call(*_inputs, **_options)
34
42
  raise ::CallableTree::Error, 'Not implemented'
35
43
  end
36
44
 
37
- def terminate?(output = nil, **_options)
45
+ def terminate?(output, *_inputs, **_options)
38
46
  !output.nil?
39
47
  end
40
48
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module CallableTree
4
- VERSION = '0.2.0'
4
+ VERSION = '0.3.0'
5
5
  end
data/lib/callable_tree.rb CHANGED
@@ -8,9 +8,9 @@ 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/broadcast'
12
- require_relative 'callable_tree/node/internal/seek'
13
- require_relative 'callable_tree/node/internal/compose'
11
+ require_relative 'callable_tree/node/internal/strategy/broadcast'
12
+ require_relative 'callable_tree/node/internal/strategy/seek'
13
+ require_relative 'callable_tree/node/internal/strategy/compose'
14
14
  require_relative 'callable_tree/node/external/verbose'
15
15
  require_relative 'callable_tree/node/external'
16
16
  require_relative 'callable_tree/node/internal'
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.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - jsmmr
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-06-14 00:00:00.000000000 Z
11
+ date: 2021-12-27 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,9 +50,9 @@ 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
52
- - lib/callable_tree/node/internal/broadcast.rb
53
- - lib/callable_tree/node/internal/compose.rb
54
- - lib/callable_tree/node/internal/seek.rb
53
+ - lib/callable_tree/node/internal/strategy/broadcast.rb
54
+ - lib/callable_tree/node/internal/strategy/compose.rb
55
+ - lib/callable_tree/node/internal/strategy/seek.rb
55
56
  - lib/callable_tree/node/root.rb
56
57
  - lib/callable_tree/version.rb
57
58
  homepage: https://github.com/jsmmr/ruby_callable_tree
@@ -60,7 +61,7 @@ licenses:
60
61
  metadata:
61
62
  homepage_uri: https://github.com/jsmmr/ruby_callable_tree
62
63
  source_code_uri: https://github.com/jsmmr/ruby_callable_tree
63
- changelog_uri: https://github.com/jsmmr/ruby_callable_tree/blob/v0.2.0/CHANGELOG.md
64
+ changelog_uri: https://github.com/jsmmr/ruby_callable_tree/blob/v0.3.0/CHANGELOG.md
64
65
  post_install_message:
65
66
  rdoc_options: []
66
67
  require_paths:
@@ -76,7 +77,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
76
77
  - !ruby/object:Gem::Version
77
78
  version: '0'
78
79
  requirements: []
79
- rubygems_version: 3.2.16
80
+ rubygems_version: 3.3.3
80
81
  signing_key:
81
82
  specification_version: 4
82
83
  summary: Builds a tree by linking callable nodes. The nodes that match the conditions
@@ -1,15 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module CallableTree
4
- module Node
5
- module Internal
6
- class Broadcast
7
- def call(nodes, input:, options:)
8
- nodes.map do |node|
9
- node.call(input, **options) if node.match?(input, **options)
10
- end
11
- end
12
- end
13
- end
14
- end
15
- end
@@ -1,19 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module CallableTree
4
- module Node
5
- module Internal
6
- class Compose
7
- def call(nodes, input:, options:)
8
- nodes.reduce(input) do |input, node|
9
- if node.match?(input, **options)
10
- node.call(input, **options)
11
- else
12
- input
13
- end
14
- end
15
- end
16
- end
17
- end
18
- end
19
- end
@@ -1,23 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module CallableTree
4
- module Node
5
- module Internal
6
- class Seek
7
- def call(nodes, input:, options:)
8
- nodes
9
- .lazy
10
- .select { |node| node.match?(input, **options) }
11
- .map do |node|
12
- output = node.call(input, **options)
13
- terminated = node.terminate?(output, **options)
14
- [output, terminated]
15
- end
16
- .select { |_output, terminated| terminated }
17
- .map { |output, _terminated| output }
18
- .first
19
- end
20
- end
21
- end
22
- end
23
- end