callable_tree 0.2.0 → 0.3.0

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