rubytree 0.9.7 → 2.0.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 +5 -5
- data/API-CHANGES.md +153 -0
- data/Gemfile +2 -13
- data/Gemfile.lock +60 -61
- data/History.md +410 -0
- data/LICENSE.md +1 -2
- data/README.md +24 -28
- data/Rakefile +65 -48
- data/TODO.org +19 -15
- data/examples/example_basic.rb +19 -12
- data/lib/rubytree.rb +3 -4
- data/lib/tree/binarytree.rb +27 -27
- data/lib/tree/tree_deps.rb +9 -12
- data/lib/tree/utils/hash_converter.rb +127 -121
- data/lib/tree/utils/json_converter.rb +81 -79
- data/lib/tree/utils/metrics_methods.rb +18 -48
- data/lib/tree/utils/path_methods.rb +15 -17
- data/lib/tree/utils/tree_merge_handler.rb +79 -80
- data/lib/tree/utils/utils.rb +9 -6
- data/lib/tree/version.rb +3 -5
- data/lib/tree.rb +194 -177
- data/rubytree.gemspec +67 -44
- data/spec/spec_helper.rb +5 -3
- data/spec/tree_spec.rb +136 -37
- data/test/run_test.rb +9 -8
- data/test/test_binarytree.rb +86 -105
- data/test/test_rubytree_require.rb +4 -5
- data/test/test_subclassed_node.rb +5 -26
- data/test/test_thread_and_fiber.rb +13 -16
- data/test/test_tree.rb +577 -657
- metadata +142 -55
- data/API-CHANGES.rdoc +0 -99
- data/History.rdoc +0 -303
- data/TAGS +0 -248
- data/gem_graph.png +0 -0
- data/lib/tree/utils/camel_case_method_handler.rb +0 -79
- data/setup.rb +0 -1585
@@ -5,9 +5,9 @@
|
|
5
5
|
#
|
6
6
|
# Author:: Jen Hamon (http://www.github.com/jhamon)
|
7
7
|
#
|
8
|
-
# Time-stamp: <
|
8
|
+
# Time-stamp: <2022-06-20 22:16:39 anupam>
|
9
9
|
#
|
10
|
-
# Copyright (C) 2014, 2015 Jen Hamon (http://www.github.com/jhamon) and
|
10
|
+
# Copyright (C) 2014, 2015, 2022, 2022 Jen Hamon (http://www.github.com/jhamon) and
|
11
11
|
# Anupam Sengupta <anupamsg@gmail.com>
|
12
12
|
#
|
13
13
|
# All rights reserved.
|
@@ -36,140 +36,146 @@
|
|
36
36
|
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
37
37
|
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
38
38
|
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
39
|
+
#
|
40
|
+
# frozen_string_literal: true
|
39
41
|
|
40
|
-
module Tree
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
42
|
+
module Tree
|
43
|
+
module Utils
|
44
|
+
# Provides a utility for marshalling/unmarshalling TreeNode objects to Ruby
|
45
|
+
# +hash+ objects.
|
46
|
+
#
|
47
|
+
# @author Jen Hamon (https://www.github.com/jhamon)
|
48
|
+
module HashConverter
|
49
|
+
def self.included(base)
|
50
|
+
base.extend(ClassMethods)
|
51
|
+
end
|
45
52
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
53
|
+
# Methods in {Tree::Utils::HashConverter::ClassMethods} will be added as
|
54
|
+
# class methods on any class mixing in the {Tree::Utils::HashConverter}
|
55
|
+
# module.
|
56
|
+
module ClassMethods
|
57
|
+
# Factory method builds a {Tree::TreeNode} from a +Hash+.
|
58
|
+
#
|
59
|
+
# This method will interpret each key of your +Hash+ as a {Tree::TreeNode}.
|
60
|
+
# Nested hashes are expected and child nodes will be added accordingly. If
|
61
|
+
# a hash key is a single value that value will be used as the name for the
|
62
|
+
# node. If a hash key is an Array, both node name and content will be
|
63
|
+
# populated.
|
64
|
+
#
|
65
|
+
# A leaf element of the tree should be represented as a hash key with
|
66
|
+
# corresponding value +nil+ or +{}+.
|
67
|
+
#
|
68
|
+
# @example
|
69
|
+
# TreeNode.from_hash({:A => {:B => {}, :C => {:D => {}, :E => {}}}})
|
70
|
+
# # would be parsed into the following tree structure:
|
71
|
+
# # A
|
72
|
+
# # / \
|
73
|
+
# # B C
|
74
|
+
# # / \
|
75
|
+
# # D E
|
76
|
+
#
|
77
|
+
# # The same tree would result from this nil-terminated Hash
|
78
|
+
# {:A => {:B => nil, :C => {:D => nil, :E => nil}}}
|
79
|
+
#
|
80
|
+
# # A tree with equivalent structure but with content present for
|
81
|
+
# # nodes A and D could be built from a hash like this:
|
82
|
+
# {[:A, "A content"] => {:B => {},
|
83
|
+
# :C => { [:D, "D content"] => {},
|
84
|
+
# :E => {} }}}
|
85
|
+
#
|
86
|
+
# @author Jen Hamon (http://www.github.com/jhamon)
|
87
|
+
# @param [Hash] hash Hash to build tree from.
|
88
|
+
#
|
89
|
+
# @return [Tree::TreeNode] The {Tree::TreeNode} instance representing the
|
90
|
+
# root of your tree.
|
91
|
+
#
|
92
|
+
# @raise [ArgumentError] This exception is raised if a non-Hash is passed.
|
93
|
+
#
|
94
|
+
# @raise [ArgumentError] This exception is raised if the hash has multiple
|
95
|
+
# top-level elements.
|
96
|
+
#
|
97
|
+
# @raise [ArgumentError] This exception is raised if the hash contains
|
98
|
+
# values that are not hashes or nils.
|
50
99
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
# Nested hashes are expected and child nodes will be added accordingly. If
|
55
|
-
# a hash key is a single value that value will be used as the name for the
|
56
|
-
# node. If a hash key is an Array, both node name and content will be
|
57
|
-
# populated.
|
58
|
-
#
|
59
|
-
# A leaf element of the tree should be represented as a hash key with
|
60
|
-
# corresponding value +nil+ or +{}+.
|
61
|
-
#
|
62
|
-
# @example
|
63
|
-
# TreeNode.from_hash({:A => {:B => {}, :C => {:D => {}, :E => {}}}})
|
64
|
-
# # would be parsed into the following tree structure:
|
65
|
-
# # A
|
66
|
-
# # / \
|
67
|
-
# # B C
|
68
|
-
# # / \
|
69
|
-
# # D E
|
70
|
-
#
|
71
|
-
# # The same tree would result from this nil-terminated Hash
|
72
|
-
# {:A => {:B => nil, :C => {:D => nil, :E => nil}}}
|
73
|
-
#
|
74
|
-
# # A tree with equivalent structure but with content present for
|
75
|
-
# # nodes A and D could be built from a hash like this:
|
76
|
-
# {[:A, "A content"] => {:B => {},
|
77
|
-
# :C => { [:D, "D content"] => {},
|
78
|
-
# :E => {} }}}
|
79
|
-
#
|
80
|
-
# @author Jen Hamon (http://www.github.com/jhamon)
|
81
|
-
# @param [Hash] hash Hash to build tree from.
|
82
|
-
#
|
83
|
-
# @return [Tree::TreeNode] The {Tree::TreeNode} instance representing the
|
84
|
-
# root of your tree.
|
85
|
-
#
|
86
|
-
# @raise [ArgumentError] This exception is raised if a non-Hash is passed.
|
87
|
-
#
|
88
|
-
# @raise [ArgumentError] This exception is raised if the hash has multiple
|
89
|
-
# top-level elements.
|
90
|
-
#
|
91
|
-
# @raise [ArgumentError] This exception is raised if the hash contains
|
92
|
-
# values that are not hashes or nils.
|
100
|
+
def from_hash(hash)
|
101
|
+
raise ArgumentError, 'Argument must be a type of hash'\
|
102
|
+
unless hash.is_a?(Hash)
|
93
103
|
|
94
|
-
|
95
|
-
|
96
|
-
unless hash.is_a?(Hash)
|
104
|
+
raise ArgumentError, 'Hash must have one top-level element'\
|
105
|
+
if hash.size != 1
|
97
106
|
|
98
|
-
|
99
|
-
if hash.size != 1
|
107
|
+
root, children = hash.first
|
100
108
|
|
101
|
-
|
109
|
+
raise ArgumentError, 'Invalid child. Must be nil or hash.' unless [Hash, NilClass].include?(children.class)
|
102
110
|
|
103
|
-
|
104
|
-
|
111
|
+
node = new(*root)
|
112
|
+
node.add_from_hash(children) unless children.nil?
|
113
|
+
node
|
114
|
+
end
|
105
115
|
end
|
106
116
|
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
117
|
+
# Instantiate and insert child nodes from data in a Ruby +Hash+
|
118
|
+
#
|
119
|
+
# This method is used in conjunction with from_hash to provide a
|
120
|
+
# convenient way of building and inserting child nodes present in a Ruby
|
121
|
+
# hashes.
|
122
|
+
#
|
123
|
+
# This method will instantiate a node instance for each top-
|
124
|
+
# level key of the input hash, to be inserted as children of the receiver
|
125
|
+
# instance.
|
126
|
+
#
|
127
|
+
# Nested hashes are expected and further child nodes will be created and
|
128
|
+
# added accordingly. If a hash key is a single value that value will be
|
129
|
+
# used as the name for the node. If a hash key is an Array, both node
|
130
|
+
# name and content will be populated.
|
131
|
+
#
|
132
|
+
# A leaf element of the tree should be represented as a hash key with
|
133
|
+
# corresponding value +nil+ or {}.
|
134
|
+
#
|
135
|
+
# @example
|
136
|
+
# root = Tree::TreeNode.new(:A, "Root content!")
|
137
|
+
# root.add_from_hash({:B => {:D => {}}, [:C, "C content!"] => {}})
|
138
|
+
#
|
139
|
+
# @author Jen Hamon (http://www.github.com/jhamon)
|
140
|
+
# @param [Hash] children The hash of child subtrees.
|
141
|
+
# @raise [ArgumentError] This exception is raised if a non-hash is passed.
|
142
|
+
# @return [Array] Array of child nodes added
|
143
|
+
# @see ClassMethods#from_hash
|
144
|
+
def add_from_hash(children)
|
145
|
+
raise ArgumentError, 'Argument must be a type of hash'\
|
146
|
+
unless children.is_a?(Hash)
|
112
147
|
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
# This method will instantiate a node instance for each top-
|
120
|
-
# level key of the input hash, to be inserted as children of the receiver
|
121
|
-
# instance.
|
122
|
-
#
|
123
|
-
# Nested hashes are expected and further child nodes will be created and
|
124
|
-
# added accordingly. If a hash key is a single value that value will be
|
125
|
-
# used as the name for the node. If a hash key is an Array, both node
|
126
|
-
# name and content will be populated.
|
127
|
-
#
|
128
|
-
# A leaf element of the tree should be represented as a hash key with
|
129
|
-
# corresponding value +nil+ or {}.
|
130
|
-
#
|
131
|
-
# @example
|
132
|
-
# root = Tree::TreeNode.new(:A, "Root content!")
|
133
|
-
# root.add_from_hash({:B => {:D => {}}, [:C, "C content!"] => {}})
|
134
|
-
#
|
135
|
-
# @author Jen Hamon (http://www.github.com/jhamon)
|
136
|
-
# @param [Hash] children The hash of child subtrees.
|
137
|
-
# @raise [ArgumentError] This exception is raised if a non-hash is passed.
|
138
|
-
# @return [Array] Array of child nodes added
|
139
|
-
# @see ClassMethods#from_hash
|
140
|
-
def add_from_hash(children)
|
141
|
-
raise ArgumentError, "Argument must be a type of hash"\
|
142
|
-
unless children.is_a?(Hash)
|
148
|
+
child_nodes = []
|
149
|
+
children.each do |child, grandchildren|
|
150
|
+
child_node = self.class.from_hash({ child => grandchildren })
|
151
|
+
child_nodes << child_node
|
152
|
+
self << child_node
|
153
|
+
end
|
143
154
|
|
144
|
-
|
145
|
-
children.each do |child, grandchildren|
|
146
|
-
child_node = self.class.from_hash({child => grandchildren})
|
147
|
-
child_nodes << child_node
|
148
|
-
self << child_node
|
155
|
+
child_nodes
|
149
156
|
end
|
150
157
|
|
151
|
-
|
152
|
-
|
158
|
+
# Convert a node and its subtree into a Ruby hash.
|
159
|
+
#
|
160
|
+
# @example
|
161
|
+
# root = Tree::TreeNode.new(:root, "root content")
|
162
|
+
# root << Tree::TreeNode.new(:child1, "child1 content")
|
163
|
+
# root << Tree::TreeNode.new(:child2, "child2 content")
|
164
|
+
# root.to_h # => {[:root, "root content"] =>
|
165
|
+
# { [:child1, "child1 content"] =>
|
166
|
+
# {}, [:child2, "child2 content"] => {}}}
|
167
|
+
# @author Jen Hamon (http://www.github.com/jhamon)
|
168
|
+
# @return [Hash] Hash representation of tree.
|
169
|
+
def to_h
|
170
|
+
key = content? ? [name, content] : name
|
153
171
|
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
# root << Tree::TreeNode.new(:child1, "child1 content")
|
159
|
-
# root << Tree::TreeNode.new(:child2, "child2 content")
|
160
|
-
# root.to_h # => {[:root, "root content"] =>
|
161
|
-
# { [:child1, "child1 content"] =>
|
162
|
-
# {}, [:child2, "child2 content"] => {}}}
|
163
|
-
# @author Jen Hamon (http://www.github.com/jhamon)
|
164
|
-
# @return [Hash] Hash representation of tree.
|
165
|
-
def to_h
|
166
|
-
key = has_content? ? [name, content] : name
|
172
|
+
children_hash = {}
|
173
|
+
children do |child|
|
174
|
+
children_hash.merge! child.to_h
|
175
|
+
end
|
167
176
|
|
168
|
-
|
169
|
-
children do |child|
|
170
|
-
children_hash.merge! child.to_h
|
177
|
+
{ key => children_hash }
|
171
178
|
end
|
172
|
-
|
173
|
-
{ key => children_hash }
|
174
179
|
end
|
180
|
+
end
|
175
181
|
end
|
@@ -4,9 +4,9 @@
|
|
4
4
|
#
|
5
5
|
# Author:: Anupam Sengupta (anupamsg@gmail.com)
|
6
6
|
#
|
7
|
-
# Time-stamp: <
|
7
|
+
# Time-stamp: <2022-06-20 22:16:46 anupam>
|
8
8
|
#
|
9
|
-
# Copyright (C) 2012, 2013, 2014, 2015 Anupam Sengupta <anupamsg@gmail.com>
|
9
|
+
# Copyright (C) 2012, 2013, 2014, 2015, 2022 Anupam Sengupta <anupamsg@gmail.com>
|
10
10
|
#
|
11
11
|
# All rights reserved.
|
12
12
|
#
|
@@ -34,94 +34,96 @@
|
|
34
34
|
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
35
35
|
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
36
36
|
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
37
|
+
#
|
38
|
+
# frozen_string_literal: true
|
37
39
|
|
38
40
|
require 'json'
|
39
41
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
# @!group Converting to/from JSON
|
49
|
-
|
50
|
-
# Creates a JSON ready Hash for the #to_json method.
|
51
|
-
#
|
52
|
-
# @author Eric Cline (https://github.com/escline)
|
53
|
-
# @since 0.8.3
|
54
|
-
#
|
55
|
-
# @return A hash based representation of the JSON
|
56
|
-
#
|
57
|
-
# Rails uses JSON in ActiveSupport, and all Rails JSON encoding goes through
|
58
|
-
# +as_json+.
|
59
|
-
#
|
60
|
-
# @see #to_json
|
61
|
-
# @see http://stackoverflow.com/a/6880638/273808
|
62
|
-
def as_json(options = {})
|
42
|
+
module Tree
|
43
|
+
module Utils
|
44
|
+
# Provides utility methods to convert a {Tree::TreeNode} to and from
|
45
|
+
# JSON[http://flori.github.com/json/].
|
46
|
+
module JSONConverter
|
47
|
+
def self.included(base)
|
48
|
+
base.extend(ClassMethods)
|
49
|
+
end
|
63
50
|
|
64
|
-
|
65
|
-
"name" => name,
|
66
|
-
"content" => content,
|
67
|
-
JSON.create_id => self.class.name
|
68
|
-
}
|
51
|
+
# @!group Converting to/from JSON
|
69
52
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
53
|
+
# Creates a JSON ready Hash for the #to_json method.
|
54
|
+
#
|
55
|
+
# @author Eric Cline (https://github.com/escline)
|
56
|
+
# @since 0.8.3
|
57
|
+
#
|
58
|
+
# @return A hash based representation of the JSON
|
59
|
+
#
|
60
|
+
# Rails uses JSON in ActiveSupport, and all Rails JSON encoding goes through
|
61
|
+
# +as_json+.
|
62
|
+
#
|
63
|
+
# @param [Object] _options
|
64
|
+
#
|
65
|
+
# @see #to_json
|
66
|
+
# @see http://stackoverflow.com/a/6880638/273808
|
67
|
+
# noinspection RubyUnusedLocalVariable
|
68
|
+
def as_json(_options = {})
|
69
|
+
json_hash = {
|
70
|
+
name: name,
|
71
|
+
content: content,
|
72
|
+
JSON.create_id => self.class.name
|
73
|
+
}
|
75
74
|
|
76
|
-
|
77
|
-
|
78
|
-
# Creates a JSON representation of this node including all it's children.
|
79
|
-
# This requires the JSON gem to be available, or else the operation fails with
|
80
|
-
# a warning message. Uses the Hash output of #as_json method.
|
81
|
-
#
|
82
|
-
# @author Dirk Breuer (http://github.com/railsbros-dirk)
|
83
|
-
# @since 0.7.0
|
84
|
-
#
|
85
|
-
# @return The JSON representation of this subtree.
|
86
|
-
#
|
87
|
-
# @see ClassMethods#json_create
|
88
|
-
# @see #as_json
|
89
|
-
# @see http://flori.github.com/json
|
90
|
-
def to_json(*a)
|
91
|
-
as_json.to_json(*a)
|
92
|
-
end
|
75
|
+
json_hash['children'] = children if children?
|
93
76
|
|
94
|
-
|
95
|
-
|
96
|
-
module ClassMethods
|
97
|
-
# Helper method to create a Tree::TreeNode instance from the JSON hash
|
98
|
-
# representation. Note that this method should *NOT* be called directly.
|
99
|
-
# Instead, to convert the JSON hash back to a tree, do:
|
100
|
-
#
|
101
|
-
# tree = JSON.parse(the_json_hash)
|
102
|
-
#
|
103
|
-
# This operation requires the {JSON gem}[http://flori.github.com/json/] to
|
104
|
-
# be available, or else the operation fails with a warning message.
|
105
|
-
#
|
106
|
-
# @author Dirk Breuer (http://github.com/railsbros-dirk)
|
107
|
-
# @since 0.7.0
|
108
|
-
#
|
109
|
-
# @param [Hash] json_hash The JSON hash to convert from.
|
110
|
-
#
|
111
|
-
# @return [Tree::TreeNode] The created tree.
|
112
|
-
#
|
113
|
-
# @see #to_json
|
114
|
-
# @see http://flori.github.com/json
|
115
|
-
def json_create(json_hash)
|
77
|
+
json_hash
|
78
|
+
end
|
116
79
|
|
117
|
-
node
|
80
|
+
# Creates a JSON representation of this node including all it's children.
|
81
|
+
# This requires the JSON gem to be available, or else the operation fails with
|
82
|
+
# a warning message. Uses the Hash output of #as_json method.
|
83
|
+
#
|
84
|
+
# @author Dirk Breuer (http://github.com/railsbros-dirk)
|
85
|
+
# @since 0.7.0
|
86
|
+
#
|
87
|
+
# @return The JSON representation of this subtree.
|
88
|
+
#
|
89
|
+
# @see ClassMethods#json_create
|
90
|
+
# @see #as_json
|
91
|
+
# @see http://flori.github.com/json
|
92
|
+
def to_json(*args)
|
93
|
+
as_json.to_json(*args)
|
94
|
+
end
|
118
95
|
|
119
|
-
|
120
|
-
|
121
|
-
|
96
|
+
# ClassMethods for the {JSONConverter} module. Will become class methods in
|
97
|
+
# the +include+ target.
|
98
|
+
module ClassMethods
|
99
|
+
# Helper method to create a Tree::TreeNode instance from the JSON hash
|
100
|
+
# representation. Note that this method should *NOT* be called directly.
|
101
|
+
# Instead, to convert the JSON hash back to a tree, do:
|
102
|
+
#
|
103
|
+
# tree = JSON.parse(the_json_hash)
|
104
|
+
#
|
105
|
+
# This operation requires the {JSON gem}[http://flori.github.com/json/] to
|
106
|
+
# be available, or else the operation fails with a warning message.
|
107
|
+
#
|
108
|
+
# @author Dirk Breuer (http://github.com/railsbros-dirk)
|
109
|
+
# @since 0.7.0
|
110
|
+
#
|
111
|
+
# @param [Hash] json_hash The JSON hash to convert from.
|
112
|
+
#
|
113
|
+
# @return [Tree::TreeNode] The created tree.
|
114
|
+
#
|
115
|
+
# @see #to_json
|
116
|
+
# @see http://flori.github.com/json
|
117
|
+
def json_create(json_hash)
|
118
|
+
node = new(json_hash['name'], json_hash['content'])
|
122
119
|
|
123
|
-
|
120
|
+
json_hash['children']&.each do |child|
|
121
|
+
node << child
|
122
|
+
end
|
124
123
|
|
124
|
+
node
|
125
|
+
end
|
126
|
+
end
|
125
127
|
end
|
126
128
|
end
|
127
129
|
end
|
@@ -4,9 +4,9 @@
|
|
4
4
|
#
|
5
5
|
# Author:: Anupam Sengupta (anupamsg@gmail.com)
|
6
6
|
#
|
7
|
-
# Time-stamp: <
|
7
|
+
# Time-stamp: <2022-06-20 22:17:00 anupam>
|
8
8
|
#
|
9
|
-
# Copyright (C) 2013, 2015 Anupam Sengupta <anupamsg@gmail.com>
|
9
|
+
# Copyright (C) 2013, 2015, 2017, 2021, 2022 Anupam Sengupta <anupamsg@gmail.com>
|
10
10
|
#
|
11
11
|
# All rights reserved.
|
12
12
|
#
|
@@ -35,14 +35,12 @@
|
|
35
35
|
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
36
36
|
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
37
37
|
#
|
38
|
+
# frozen_string_literal: true
|
38
39
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
module TreeMetricsHandler
|
44
|
-
def self.included(base)
|
45
|
-
|
40
|
+
module Tree
|
41
|
+
module Utils
|
42
|
+
# Provides utility functions to measure various tree metrics.
|
43
|
+
module TreeMetricsHandler
|
46
44
|
# @!group Metrics and Measures
|
47
45
|
|
48
46
|
# @!attribute [r] size
|
@@ -54,7 +52,7 @@ module Tree::Utils
|
|
54
52
|
#
|
55
53
|
# @return [Integer] Total number of nodes in this (sub)tree.
|
56
54
|
def size
|
57
|
-
inject(0) {|sum, node| sum + 1 if node}
|
55
|
+
inject(0) { |sum, node| sum + 1 if node }
|
58
56
|
end
|
59
57
|
|
60
58
|
# @!attribute [r] length
|
@@ -66,7 +64,7 @@ module Tree::Utils
|
|
66
64
|
# @return [Integer] The total number of nodes in this (sub)tree.
|
67
65
|
# @see #size
|
68
66
|
def length
|
69
|
-
size
|
67
|
+
size
|
70
68
|
end
|
71
69
|
|
72
70
|
# @!attribute [r] node_height
|
@@ -79,8 +77,9 @@ module Tree::Utils
|
|
79
77
|
#
|
80
78
|
# @return [Integer] Height of the node.
|
81
79
|
def node_height
|
82
|
-
return 0 if
|
83
|
-
|
80
|
+
return 0 if leaf?
|
81
|
+
|
82
|
+
1 + @children.collect(&:node_height).max
|
84
83
|
end
|
85
84
|
|
86
85
|
# @!attribute [r] node_depth
|
@@ -89,15 +88,12 @@ module Tree::Utils
|
|
89
88
|
# Depth:: Length of the node's path to its root. Depth of a root node is
|
90
89
|
# zero.
|
91
90
|
#
|
92
|
-
# *Note* that the deprecated method {#depth} was incorrectly computing
|
93
|
-
# this value. Please replace all calls to the old method with
|
94
|
-
# {#node_depth} instead.
|
95
|
-
#
|
96
91
|
# {#level} is an alias for this method.
|
97
92
|
#
|
98
93
|
# @return [Integer] Depth of this node.
|
99
94
|
def node_depth
|
100
|
-
return 0 if
|
95
|
+
return 0 if root?
|
96
|
+
|
101
97
|
1 + parent.node_depth
|
102
98
|
end
|
103
99
|
|
@@ -109,32 +105,6 @@ module Tree::Utils
|
|
109
105
|
node_depth
|
110
106
|
end
|
111
107
|
|
112
|
-
# @!attribute [r] depth
|
113
|
-
# Depth of the tree from this node. A single leaf node has a depth of 1.
|
114
|
-
#
|
115
|
-
# This method is *DEPRECATED* and may be removed in the subsequent
|
116
|
-
# releases. Note that the value returned by this method is actually the:
|
117
|
-
#
|
118
|
-
# _height_ + 1 of the node, *NOT* the _depth_.
|
119
|
-
#
|
120
|
-
# For correct and conventional behavior, please use {#node_depth} and
|
121
|
-
# {#node_height} methods instead.
|
122
|
-
#
|
123
|
-
# @return [Integer] depth of the node.
|
124
|
-
#
|
125
|
-
# @deprecated This method returns an incorrect value. Use the
|
126
|
-
# {#node_depth} method instead.
|
127
|
-
#
|
128
|
-
# @see #node_depth
|
129
|
-
def depth
|
130
|
-
warn DeprecatedMethodWarning,
|
131
|
-
"This method is deprecated. "\
|
132
|
-
"Please use node_depth() or node_height() instead (bug # 22535)"
|
133
|
-
|
134
|
-
return 1 if is_leaf?
|
135
|
-
1 + @children.collect { |child| child.depth }.max
|
136
|
-
end
|
137
|
-
|
138
108
|
# @!attribute [r] breadth
|
139
109
|
# Breadth of the tree at this node's level.
|
140
110
|
# A single node without siblings has a breadth of 1.
|
@@ -145,7 +115,7 @@ module Tree::Utils
|
|
145
115
|
#
|
146
116
|
# @return [Integer] breadth of the node's level.
|
147
117
|
def breadth
|
148
|
-
|
118
|
+
root? ? 1 : parent.children.size
|
149
119
|
end
|
150
120
|
|
151
121
|
# @!attribute [r] in_degree
|
@@ -160,7 +130,7 @@ module Tree::Utils
|
|
160
130
|
#
|
161
131
|
# @return [Integer] The in-degree of this node.
|
162
132
|
def in_degree
|
163
|
-
|
133
|
+
root? ? 0 : 1
|
164
134
|
end
|
165
135
|
|
166
136
|
# @!attribute [r] out_degree
|
@@ -171,10 +141,10 @@ module Tree::Utils
|
|
171
141
|
#
|
172
142
|
# @return [Integer] The out-degree of this node.
|
173
143
|
def out_degree
|
174
|
-
|
144
|
+
leaf? ? 0 : children.size
|
175
145
|
end
|
176
146
|
|
177
147
|
# @!endgroup
|
178
|
-
end
|
148
|
+
end
|
179
149
|
end
|
180
150
|
end
|
@@ -4,9 +4,9 @@
|
|
4
4
|
#
|
5
5
|
# Author:: Marco Ziccardi and Anupam Sengupta (anupamsg@gmail.com)
|
6
6
|
#
|
7
|
-
# Time-stamp: <
|
7
|
+
# Time-stamp: <2022-06-20 02:00:11 anupam>
|
8
8
|
#
|
9
|
-
# Copyright (C) 2015 Anupam Sengupta <anupamsg@gmail.com>
|
9
|
+
# Copyright (C) 2015, 2021, 2022 Anupam Sengupta <anupamsg@gmail.com>
|
10
10
|
#
|
11
11
|
# All rights reserved.
|
12
12
|
#
|
@@ -35,12 +35,12 @@
|
|
35
35
|
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
36
36
|
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
37
37
|
#
|
38
|
+
# frozen_string_literal: true
|
38
39
|
|
39
|
-
module Tree
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
40
|
+
module Tree
|
41
|
+
module Utils
|
42
|
+
# Provides utility methods for path extraction
|
43
|
+
module TreePathHandler
|
44
44
|
# @!group Node Path
|
45
45
|
|
46
46
|
# Returns the path of this node from the root as a string, with the node
|
@@ -53,7 +53,7 @@ module Tree::Utils
|
|
53
53
|
# @return [String] The node path with names separated using the specified
|
54
54
|
# separator.
|
55
55
|
def path_as_string(separator = '=>')
|
56
|
-
path_as_array
|
56
|
+
path_as_array.join(separator)
|
57
57
|
end
|
58
58
|
|
59
59
|
# Returns the node-names from this node to the root as an array. The first
|
@@ -61,8 +61,8 @@ module Tree::Utils
|
|
61
61
|
#
|
62
62
|
# @return [Array] The array containing the node names for the path to this
|
63
63
|
# node
|
64
|
-
def path_as_array
|
65
|
-
get_path_name_array
|
64
|
+
def path_as_array
|
65
|
+
get_path_name_array.reverse
|
66
66
|
end
|
67
67
|
|
68
68
|
# @!visibility private
|
@@ -75,18 +75,16 @@ module Tree::Utils
|
|
75
75
|
def get_path_name_array(current_array_path = [])
|
76
76
|
path_array = current_array_path + [name]
|
77
77
|
|
78
|
-
if
|
79
|
-
|
80
|
-
else #
|
81
|
-
path_array
|
82
|
-
return path_array
|
78
|
+
if parent # Recurse to parent node.
|
79
|
+
parent.get_path_name_array(path_array)
|
80
|
+
else # else If detached node or root node.
|
81
|
+
path_array
|
83
82
|
end
|
84
83
|
end
|
85
84
|
|
86
85
|
protected :get_path_name_array
|
87
86
|
|
88
87
|
# @!endgroup
|
89
|
-
end
|
88
|
+
end
|
90
89
|
end
|
91
|
-
|
92
90
|
end
|