callable_tree 0.1.3 → 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8fa06f3d5119313cc62468deec9349bb902f92ff6267f9b0051d5625eea8a866
4
- data.tar.gz: 8679ef5bd22e419d6379b18fdc0a509074938073c9edaff37b4a7bee6029cda8
3
+ metadata.gz: df7b380d00c1a56530ddd6fc4ee7159ca4f1fc14d3418c2f567f43ff6d176553
4
+ data.tar.gz: 9e2d706c5d50ae1350dfdcf92951678e7284a83fba5a71e9f8f13ffcb58c4db7
5
5
  SHA512:
6
- metadata.gz: 6ccdf3baffda301532c51510b84d066cec428961f773618ddc8d344917c9af26ca3da3d6186d6748585a8eceb0eabac0d7e652bcbcafb28b3a4a9e74622eb98f
7
- data.tar.gz: e1aa253c87040bebc9f03080ad25f704c1cbde0410355b4ffb70bbe969338d3ec7a88804abe856d582b9e351a182db43a7abe4b2f0b89c3f7d97fc6bb64bf1eb
6
+ metadata.gz: 9cd503091f5ba29c416120bdf5eca39535048c920721d0e4180cbfa95b3eb4d40ea77e2f28a9a8f4cb271adbd11050ad6a4a33313a80baf5cfa587a4e81365a1
7
+ data.tar.gz: 1948d9a3f5ec7a8ed17030436e513f253c2f1d1e24719f8813128bdb7e3db68f6a6d573cf2dc5e155177c4c1558b0aaf4cf9befbaf0d2a7c71b3ce6b92d3b668
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 3.0.0
1
+ 3.0.2
data/CHANGELOG.md CHANGED
@@ -1,5 +1,27 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.2.3] - 2021-11-07
4
+ - Add `CallableTree::Node::Internal#shake` to recursively execute `CallableTree::Node::Internal#reject`, including child nodes. The child nodes that are empty because their children have been rejected will also be rejected.
5
+ - Add `CallableTree::Node::Internal#shake!` that make destructive change.
6
+ - Add `CallableTree::Node#outline` that may be useful for writing the specs.
7
+
8
+ ## [0.2.2] - 2021-10-24
9
+ - Add `CallableTree::Node::Internal#reject` to return a new node instance without rejected child nodes.
10
+ - Add `CallableTree::Node::Internal#reject!` to destructively reject child nodes.
11
+
12
+ ## [0.2.1] - 2021-07-24
13
+ - Add `CallableTree::Node#root?`.
14
+ - Add `CallableTree::Node::Internal#seek!` that make destructive change.
15
+ - Add `CallableTree::Node::Internal#broadcast!` that make destructive change.
16
+ - Add `CallableTree::Node::Internal#compose!` that make destructive change.
17
+
18
+ ## [0.2.0] - 2021-06-15
19
+ - Change `CallableTree::Node::Internal#append` to return a new instance.
20
+ To keep the same behavior as the older version, use `CallableTree::Node::External#append!` that make destructive change.
21
+ - Remove `CallableTree::Node::Internal#<<`. Use `CallableTree::Node::External#append!` instead.
22
+ - Change `CallableTree::Node::External#verbosify` to return a new instance.
23
+ To keep the same behavior as the older version, use `CallableTree::Node::External#verbosify!` that make destructive change.
24
+
3
25
  ## [0.1.3] - 2021-06-12
4
26
  - Minor improvements
5
27
 
data/Gemfile.lock CHANGED
@@ -1,13 +1,13 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- callable_tree (0.1.3)
4
+ callable_tree (0.2.3)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
8
8
  specs:
9
9
  diff-lcs (1.4.4)
10
- rake (13.0.3)
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.2.22
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:
@@ -158,7 +160,7 @@ Run `examples/internal-seek.rb`:
158
160
  ---
159
161
  ```
160
162
 
161
- #### `CallableTree::Node::Internal#broadcast` (experimental)
163
+ #### `CallableTree::Node::Internal#broadcast`
162
164
 
163
165
  This strategy calls all child nodes of the internal node and ignores their `terminate?` methods, and then outputs their results as array.
164
166
 
@@ -212,7 +214,7 @@ Run `examples/internal-broadcast.rb`:
212
214
  10 -> [nil, nil]
213
215
  ```
214
216
 
215
- #### `CallableTree::Node::Internal#compose` (experimental)
217
+ #### `CallableTree::Node::Internal#compose`
216
218
 
217
219
  This strategy calls all child nodes of the internal node in order to input the output of the previous node to the next node and ignores their `terminate?` methods, and then outputs a single result.
218
220
 
@@ -9,7 +9,7 @@ Gem::Specification.new do |spec|
9
9
  spec.email = ['jsmmr@icloud.com']
10
10
 
11
11
  spec.summary = 'Builds a tree by linking callable nodes. The nodes that match the conditions are called in a chain from the root node to the leaf node. These are like nested `if` or `case` expressions.'
12
- spec.description = 'Builds a tree by linking callable nodes. The nodes that match the conditiosn are called in a chain from the root node to the leaf node. These are like nested `if` or `case` expressions.'
12
+ spec.description = 'Builds a tree by linking callable nodes. The nodes that match the conditions are called in a chain from the root node to the leaf node. These are like nested `if` or `case` expressions.'
13
13
  spec.homepage = 'https://github.com/jsmmr/ruby_callable_tree'
14
14
  spec.license = 'MIT'
15
15
  spec.required_ruby_version = Gem::Requirement.new('>= 2.4.0')
@@ -18,6 +18,12 @@ module CallableTree
18
18
  end
19
19
 
20
20
  def verbosify
21
+ clone.tap do |node|
22
+ node.extend Verbose
23
+ end
24
+ end
25
+
26
+ def verbosify!
21
27
  extend Verbose
22
28
  self
23
29
  end
@@ -31,6 +37,17 @@ module CallableTree
31
37
  .class
32
38
  end
33
39
 
40
+ def outline
41
+ { identity => nil }
42
+ end
43
+
44
+ private
45
+
46
+ def initialize_copy(_node)
47
+ super
48
+ self.parent = nil
49
+ end
50
+
34
51
  class Proxy
35
52
  extend ::Forwardable
36
53
  include External
@@ -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, input:, options:)
9
+ nodes.map do |node|
10
+ node.call(input, **options) if node.match?(input, **options)
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,21 @@
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, input:, options:)
9
+ nodes.reduce(input) do |input, node|
10
+ if node.match?(input, **options)
11
+ node.call(input, **options)
12
+ else
13
+ input
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ 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, input:, options:)
9
+ nodes
10
+ .lazy
11
+ .select { |node| node.match?(input, **options) }
12
+ .map do |node|
13
+ output = node.call(input, **options)
14
+ terminated = node.terminate?(output, **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
@@ -6,75 +6,135 @@ module CallableTree
6
6
  include Node
7
7
 
8
8
  def children
9
- @children ||= []
9
+ # TODO: Change to return a new array instance.
10
+ child_nodes
10
11
  end
11
12
 
12
- def <<(callable)
13
- children <<
14
- if callable.is_a?(Node)
15
- callable.clone
16
- else
17
- External.proxify(callable)
18
- end
19
- .tap { |node| node.send(:parent=, self) }
13
+ def append(*callables)
14
+ clone.tap do |node|
15
+ node.append!(*callables)
16
+ end
17
+ end
18
+
19
+ def append!(*callables)
20
+ callables
21
+ .map { |callable| nodeify(callable) }
22
+ .tap { |nodes| child_nodes.push(*nodes) } # Use Array#push for Ruby 2.4
20
23
 
21
24
  self
22
25
  end
23
26
 
24
- def append(*callables)
25
- callables.each { |callable| self.<<(callable) }
27
+ def reject(&block)
28
+ clone.tap do |node|
29
+ node.reject!(&block)
30
+ end
31
+ end
32
+
33
+ def reject!(&block)
34
+ child_nodes.reject!(&block)
26
35
  self
27
36
  end
28
37
 
38
+ def shake(&block)
39
+ clone.tap do |node|
40
+ node.shake!(&block)
41
+ end
42
+ end
43
+
44
+ def shake!(&block)
45
+ reject!(&block) if block_given?
46
+
47
+ reject! do |node|
48
+ node.is_a?(Internal) && node.shake!(&block).child_nodes.empty?
49
+ end
50
+ end
51
+
29
52
  def match?(_input = nil, **_options)
30
- !children.empty?
53
+ !child_nodes.empty?
31
54
  end
32
55
 
33
56
  def call(input = nil, **options)
34
- strategy.call(children, input: input, options: options)
57
+ strategy.call(child_nodes, input: input, options: options)
35
58
  end
36
59
 
37
60
  def seek
38
- if strategy.is_a?(Seek)
61
+ if strategy.is_a?(Strategy::Seek)
39
62
  self
40
63
  else
41
64
  clone.tap do |node|
42
- node.send(:strategy=, Seek.new)
65
+ node.send(:strategy=, Strategy::Seek.new)
43
66
  end
44
67
  end
45
68
  end
46
69
 
70
+ def seek!
71
+ self.strategy = Strategy::Seek.new unless strategy.is_a?(Strategy::Seek)
72
+ self
73
+ end
74
+
47
75
  def broadcast
48
- if strategy.is_a?(Broadcast)
76
+ if strategy.is_a?(Strategy::Broadcast)
49
77
  self
50
78
  else
51
79
  clone.tap do |node|
52
- node.send(:strategy=, Broadcast.new)
80
+ node.send(:strategy=, Strategy::Broadcast.new)
53
81
  end
54
82
  end
55
83
  end
56
84
 
85
+ def broadcast!
86
+ self.strategy = Strategy::Broadcast.new unless strategy.is_a?(Strategy::Broadcast)
87
+ self
88
+ end
89
+
57
90
  def compose
58
- if strategy.is_a?(Compose)
91
+ if strategy.is_a?(Strategy::Compose)
59
92
  self
60
93
  else
61
94
  clone.tap do |node|
62
- node.send(:strategy=, Compose.new)
95
+ node.send(:strategy=, Strategy::Compose.new)
63
96
  end
64
97
  end
65
98
  end
66
99
 
100
+ def compose!
101
+ self.strategy = Strategy::Compose.new unless strategy.is_a?(Strategy::Compose)
102
+ self
103
+ end
104
+
105
+ def outline(&block)
106
+ key = block ? block.call(self) : identity
107
+ value = child_nodes.reduce({}) { |memo, node| memo.merge!(node.outline(&block)) }
108
+ { key => value }
109
+ end
110
+
111
+ protected
112
+
113
+ def child_nodes
114
+ @child_nodes ||= []
115
+ end
116
+
67
117
  private
68
118
 
69
- attr_writer :children, :strategy
119
+ attr_writer :child_nodes, :strategy
120
+
121
+ def nodeify(callable)
122
+ if callable.is_a?(Node)
123
+ callable.clone
124
+ else
125
+ External.proxify(callable)
126
+ end
127
+ .tap { |node| node.send(:parent=, self) }
128
+ end
70
129
 
71
130
  def strategy
72
- @strategy ||= Seek.new
131
+ @strategy ||= Strategy::Seek.new
73
132
  end
74
133
 
75
134
  def initialize_copy(_node)
76
135
  super
77
- self.children = children.map do |node|
136
+ self.parent = nil
137
+ self.child_nodes = child_nodes.map do |node|
78
138
  node.clone.tap { |new_node| new_node.send(:parent=, self) }
79
139
  end
80
140
  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,7 +27,11 @@ 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
37
  def match?(_input = nil, **_options)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module CallableTree
4
- VERSION = '0.1.3'
4
+ VERSION = '0.2.3'
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,16 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: callable_tree
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.2.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - jsmmr
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-06-12 00:00:00.000000000 Z
11
+ date: 2021-11-07 00:00:00.000000000 Z
12
12
  dependencies: []
13
- description: Builds a tree by linking callable nodes. The nodes that match the conditiosn
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
15
15
  `if` or `case` expressions.
16
16
  email:
@@ -49,9 +49,9 @@ files:
49
49
  - lib/callable_tree/node/external/verbose.rb
50
50
  - lib/callable_tree/node/hooks/call.rb
51
51
  - 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
52
+ - lib/callable_tree/node/internal/strategy/broadcast.rb
53
+ - lib/callable_tree/node/internal/strategy/compose.rb
54
+ - lib/callable_tree/node/internal/strategy/seek.rb
55
55
  - lib/callable_tree/node/root.rb
56
56
  - lib/callable_tree/version.rb
57
57
  homepage: https://github.com/jsmmr/ruby_callable_tree
@@ -60,7 +60,7 @@ licenses:
60
60
  metadata:
61
61
  homepage_uri: https://github.com/jsmmr/ruby_callable_tree
62
62
  source_code_uri: https://github.com/jsmmr/ruby_callable_tree
63
- changelog_uri: https://github.com/jsmmr/ruby_callable_tree/blob/v0.1.3/CHANGELOG.md
63
+ changelog_uri: https://github.com/jsmmr/ruby_callable_tree/blob/v0.2.3/CHANGELOG.md
64
64
  post_install_message:
65
65
  rdoc_options: []
66
66
  require_paths:
@@ -76,7 +76,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
76
76
  - !ruby/object:Gem::Version
77
77
  version: '0'
78
78
  requirements: []
79
- rubygems_version: 3.2.16
79
+ rubygems_version: 3.2.22
80
80
  signing_key:
81
81
  specification_version: 4
82
82
  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