rubytree 1.0.2 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/TODO.org CHANGED
@@ -183,10 +183,7 @@
183
183
  This proposed change does make sense at one level (since the root node does not have any parent), but returning root
184
184
  as root's root (no pun intended) makes accessing the root from anywhere in the tree much easier.
185
185
 
186
-
187
-
188
-
189
- * R0.9.5
186
+ * R0.9.5 :ARCHIVE:
190
187
  ** DONE Add the `#get_path_as_string` method from feature request #48 :ARCHIVE:
191
188
  CLOSED: [2015-05-30 Sat 15:55]
192
189
  ** DONE Fix [[Issue:32][Issue #32]] and enable move semantics on the TreeNode#add method. :ARCHIVE:
@@ -202,11 +199,20 @@
202
199
  CLOSED: [2014-11-01 Sat 20:11]
203
200
 
204
201
 
202
+ * R2.0.0
203
+
204
+ This is primarily a *modernization* of the library, with removal of deprecated methods, the much-hated dependency on
205
+ ~structured_warnings~, and cleanup of other cruft.
206
+
207
+ In addition, the CI pipeline has been moved from <https://travis.ci> to ~Github Actions~.
205
208
 
209
+ - [X] Merge the modernization PR from @jmortlock (multiple changes).
210
+ - [X] Update the documentation to reflect the modernization changes.
206
211
 
207
- * Next Release
208
- DEADLINE: <2014-12-01 Mon>
209
- ** STARTED [#A] Resolve the infinite loop bug if a node is added to itself as a child :Partial:
212
+
213
+ * Unplanned / Not assigned to any release
214
+ *** STARTED Convert all documentation to markdown mode.
215
+ *** STARTED [#A] Resolve the infinite loop bug if a node is added to itself as a child :Partial:
210
216
  [[Issue:5][Issue #5.]]
211
217
 
212
218
  This is a subtle problem to resolve. The specific case of a node
@@ -237,15 +243,8 @@
237
243
  duplicates). This needs to be a hash (to allow O(1) access),
238
244
  and will sacrifice memory. There might be a need to
239
245
  restructure the internals to make better use of memory.
240
- ** STARTED Convert all documentation to markdown mode.
241
- ** TODO Expand the examples section, and add supporting documentation
246
+ *** TODO Expand the examples section, and add supporting documentation
242
247
 
243
- * Unplanned / Not assigned to any release
244
- *** DONE [#A] Migrate the website and references from http://rubyforge.org/ :ARCHIVE:
245
- CLOSED: [2014-07-04 Fri 22:18]
246
- *** DONE Revert the forced install of rubygem 2.1.11 from [[file:.travis.yml][.travis.yml]] :ARCHIVE:
247
- CLOSED: [2014-01-12 Sun 19:06]
248
- The issue seems to have been resolved with the 2.2.1 release of Rubygems.
249
248
  *** TODO Create a cycle-detection/validation mechanism to prevent cyclic graphs of nodes.
250
249
  *** TODO Create a generic validation method to check for various issues in the created tree.
251
250
  *** TODO Add a FAQ document to the project.
@@ -258,6 +257,11 @@
258
257
  *** TODO Add a YAML export method to the TreeNode class.
259
258
 
260
259
  *** TODO marshal_load method probably should be a class method. It currently clobbers self.
260
+ *** DONE Revert the forced install of rubygem 2.1.11 from [[file:.travis.yml][.travis.yml]] :ARCHIVE:
261
+ CLOSED: [2014-01-12 Sun 19:06]
262
+ The issue seems to have been resolved with the 2.2.1 release of Rubygems.
263
+ *** DONE [#A] Migrate the website and references from http://rubyforge.org/ :ARCHIVE:
264
+ CLOSED: [2014-07-04 Fri 22:18]
261
265
  *** DONE Fix bug # [[http://rubyforge.org/tracker/index.php%3Ffunc%3Ddetail&aid%3D22535&group_id%3D1215&atid%3D4793][22535]]: The method Tree::TreeNode#depth is a misnomer. The current definition actually provides the height function. :ARCHIVE:
262
266
  DEADLINE: <2010-01-09 Sat> CLOSED: [2010-01-03 Sun 22:15]
263
267
 
@@ -3,8 +3,8 @@
3
3
  # example_basic.rb:: Basic usage of the tree library.
4
4
  #
5
5
  # Author: Anupam Sengupta
6
- # Time-stamp: <2015-12-31 22:17:30 anupam>
7
- # Copyright (C) 2013, 2015 Anupam Sengupta <anupamsg@gmail.com>
6
+ # Time-stamp: <2022-06-19 22:52:29 anupam>
7
+ # Copyright (C) 2013, 2015, 2022 Anupam Sengupta <anupamsg@gmail.com>
8
8
  #
9
9
  # The following example implements this tree structure:
10
10
  #
@@ -21,22 +21,29 @@
21
21
  # +-------+-------+
22
22
  # | GRANDCHILD 1 |
23
23
  # +---------------+
24
+ #
25
+ # frozen_string_literal: true
24
26
 
25
27
  # ..... Example starts.
26
28
  require 'tree' # Load the library
27
29
 
28
- # ..... Create the root node first. Note that every node has a name and an optional content payload.
30
+ # ..... Create the root node first. Note that every node has a name and an
31
+ # ..... optional content payload.
29
32
  root_node = Tree::TreeNode.new('ROOT', 'Root Content')
30
33
  root_node.print_tree
31
34
 
32
- # ..... Now insert the child nodes. Note that you can "chain" the child insertions for a given path to any depth.
33
- root_node << Tree::TreeNode.new('CHILD1', 'Child1 Content') << Tree::TreeNode.new('GRANDCHILD1', 'GrandChild1 Content')
35
+ # ..... Now insert the child nodes. Note that you can "chain" the child
36
+ # ..... insertions for a given path to any depth.
37
+ root_node << Tree::TreeNode.new('CHILD1', 'Child1 Content') \
38
+ << Tree::TreeNode.new('GRANDCHILD1', 'GrandChild1 Content')
34
39
  root_node << Tree::TreeNode.new('CHILD2', 'Child2 Content')
35
40
 
36
- # ..... Lets print the representation to stdout. This is primarily used for debugging purposes.
41
+ # ..... Lets print the representation to stdout. This is primarily used for
42
+ # ..... debugging purposes.
37
43
  root_node.print_tree
38
44
 
39
- # ..... Lets directly access children and grandchildren of the root. The can be "chained" for a given path to any depth.
45
+ # ..... Lets directly access children and grandchildren of the root. The can be
46
+ # ..... "chained" for a given path to any depth.
40
47
  child1 = root_node['CHILD1']
41
48
  grand_child1 = root_node['CHILD1']['GRANDCHILD1']
42
49
 
data/lib/rubytree.rb CHANGED
@@ -8,9 +8,7 @@
8
8
  #
9
9
  # Author:: Anupam Sengupta (anupamsg@gmail.com)
10
10
  #
11
- # Copyright (c) 2012, 2015 Anupam Sengupta
12
- #
13
- # All rights reserved.
11
+ # Copyright (c) 2012-2022 Anupam Sengupta. All rights reserved.
14
12
  #
15
13
  # Redistribution and use in source and binary forms, with or without
16
14
  # modification, are permitted provided that the following conditions are met:
@@ -37,5 +35,6 @@
37
35
  # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38
36
  # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39
37
  #
38
+ # frozen_string_literal: true
40
39
 
41
40
  require 'tree'
@@ -8,9 +8,7 @@
8
8
  # Author:: Anupam Sengupta (anupamsg@gmail.com)
9
9
  #
10
10
 
11
- # Copyright (c) 2007, 2008, 2009, 2010, 2012, 2013, 2014, 2015 Anupam Sengupta
12
- #
13
- # All rights reserved.
11
+ # Copyright (c) 2007-2022 Anupam Sengupta. All rights reserved.
14
12
  #
15
13
  # Redistribution and use in source and binary forms, with or without
16
14
  # modification, are permitted provided that the following conditions are met:
@@ -37,6 +35,7 @@
37
35
  # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38
36
  # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39
37
  #
38
+ # frozen_string_literal: true
40
39
 
41
40
  require_relative '../tree'
42
41
 
@@ -76,28 +75,32 @@ module Tree
76
75
  children[1]
77
76
  end
78
77
 
79
- # @!attribute is_left_child?
78
+ # @!attribute left_child?
80
79
  # +true+ if the receiver node is the left child of its parent.
81
80
  # Always returns +false+ if it is a root node.
82
81
  #
83
82
  # @return [Boolean] +true+ if this is the left child of its parent.
84
- def is_left_child?
85
- return false if is_root?
83
+ def left_child?
84
+ return false if root?
86
85
 
87
86
  self == parent.left_child
88
87
  end
89
88
 
90
- # @!attribute [r] is_right_child?
89
+ alias is_left_child? left_child? # @todo: Aliased for eventual replacement
90
+
91
+ # @!attribute [r] right_child?
91
92
  # +true+ if the receiver node is the right child of its parent.
92
93
  # Always returns +false+ if it is a root node.
93
94
  #
94
95
  # @return [Boolean] +true+ if this is the right child of its parent.
95
- def is_right_child?
96
- return false if is_root?
96
+ def right_child?
97
+ return false if root?
97
98
 
98
99
  self == parent.right_child
99
100
  end
100
101
 
102
+ alias is_right_child? right_child? # @todo: Aliased for eventual replacement
103
+
101
104
  # @!group Structure Modification
102
105
 
103
106
  # Adds the specified child node to the receiver node. The child node's
@@ -164,8 +167,6 @@ module Tree
164
167
  #
165
168
  # @since 0.9.0
166
169
  #
167
- # @param [Object] block
168
- #
169
170
  # @see #each
170
171
  # @see #preordered_each
171
172
  # @see #postordered_each
@@ -176,7 +177,7 @@ module Tree
176
177
  node_stack = []
177
178
  current_node = self
178
179
 
179
- until node_stack.empty? and current_node.nil?
180
+ until node_stack.empty? && current_node.nil?
180
181
  if current_node
181
182
  node_stack.push(current_node)
182
183
  current_node = current_node.left_child
@@ -7,9 +7,7 @@
7
7
  # Author:: Anupam Sengupta (anupamsg@gmail.com)
8
8
  #
9
9
 
10
- # Copyright (c) 2006-2015 Anupam Sengupta
11
- #
12
- # All rights reserved.
10
+ # Copyright (c) 2006-2022 Anupam Sengupta. All rights reserved.
13
11
  #
14
12
  # Redistribution and use in source and binary forms, with or without
15
13
  # modification, are permitted provided that the following conditions are met:
@@ -36,14 +34,13 @@
36
34
  # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
37
35
  # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38
36
  #
37
+ # frozen_string_literal: true
39
38
 
40
- require 'structured_warnings'
41
39
  require 'json'
42
40
 
43
41
  require_relative '../tree/version'
44
42
  require_relative '../tree/utils/metrics_methods'
45
43
  require_relative '../tree/utils/path_methods'
46
- require_relative '../tree/utils/camel_case_method_handler'
47
44
  require_relative '../tree/utils/json_converter'
48
45
  require_relative '../tree/utils/tree_merge_handler'
49
46
  require_relative '../tree/utils/hash_converter'
@@ -5,9 +5,9 @@
5
5
  #
6
6
  # Author:: Jen Hamon (http://www.github.com/jhamon)
7
7
  #
8
- # Time-stamp: <2015-05-30 14:19:16 anupam>
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,138 +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
- require_relative '../../../lib/tree/utils/utils'
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
41
52
 
42
- module Tree::Utils::HashConverter
43
- def self.included(base)
44
- base.extend(ClassMethods)
45
- end
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.
46
99
 
47
- # Methods in {Tree::Utils::HashConverter::ClassMethods} will be added as
48
- # class methods on any class mixing in the {Tree::Utils::HashConverter}
49
- # module.
50
- module ClassMethods
51
- # Factory method builds a {Tree::TreeNode} from a +Hash+.
52
- #
53
- # This method will interpret each key of your +Hash+ as a {Tree::TreeNode}.
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
- def from_hash(hash)
95
- raise ArgumentError, 'Argument must be a type of hash'\
96
- unless hash.is_a?(Hash)
104
+ raise ArgumentError, 'Hash must have one top-level element'\
105
+ if hash.size != 1
97
106
 
98
- raise ArgumentError, 'Hash must have one top-level element'\
99
- if hash.size != 1
107
+ root, children = hash.first
100
108
 
101
- root, children = hash.first
109
+ raise ArgumentError, 'Invalid child. Must be nil or hash.' unless [Hash, NilClass].include?(children.class)
102
110
 
103
- raise ArgumentError, 'Invalid child. Must be nil or hash.' unless [Hash, NilClass].include?(children.class)
111
+ node = new(*root)
112
+ node.add_from_hash(children) unless children.nil?
113
+ node
114
+ end
115
+ end
104
116
 
105
- node = new(*root)
106
- node.add_from_hash(children) unless children.nil?
107
- node
108
- end
109
- end
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)
110
147
 
111
- # Instantiate and insert child nodes from data in a Ruby +Hash+
112
- #
113
- # This method is used in conjunction with from_hash to provide a
114
- # convenient way of building and inserting child nodes present in a Ruby
115
- # hashes.
116
- #
117
- # This method will instantiate a node instance for each top-
118
- # level key of the input hash, to be inserted as children of the receiver
119
- # instance.
120
- #
121
- # Nested hashes are expected and further child nodes will be created and
122
- # added accordingly. If a hash key is a single value that value will be
123
- # used as the name for the node. If a hash key is an Array, both node
124
- # name and content will be populated.
125
- #
126
- # A leaf element of the tree should be represented as a hash key with
127
- # corresponding value +nil+ or {}.
128
- #
129
- # @example
130
- # root = Tree::TreeNode.new(:A, "Root content!")
131
- # root.add_from_hash({:B => {:D => {}}, [:C, "C content!"] => {}})
132
- #
133
- # @author Jen Hamon (http://www.github.com/jhamon)
134
- # @param [Hash] children The hash of child subtrees.
135
- # @raise [ArgumentError] This exception is raised if a non-hash is passed.
136
- # @return [Array] Array of child nodes added
137
- # @see ClassMethods#from_hash
138
- def add_from_hash(children)
139
- raise ArgumentError, 'Argument must be a type of hash'\
140
- 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
141
154
 
142
- child_nodes = []
143
- children.each do |child, grandchildren|
144
- child_node = self.class.from_hash({ child => grandchildren })
145
- child_nodes << child_node
146
- self << child_node
147
- end
155
+ child_nodes
156
+ end
148
157
 
149
- child_nodes
150
- end
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
151
171
 
152
- # Convert a node and its subtree into a Ruby hash.
153
- #
154
- # @example
155
- # root = Tree::TreeNode.new(:root, "root content")
156
- # root << Tree::TreeNode.new(:child1, "child1 content")
157
- # root << Tree::TreeNode.new(:child2, "child2 content")
158
- # root.to_h # => {[:root, "root content"] =>
159
- # { [:child1, "child1 content"] =>
160
- # {}, [:child2, "child2 content"] => {}}}
161
- # @author Jen Hamon (http://www.github.com/jhamon)
162
- # @return [Hash] Hash representation of tree.
163
- def to_h
164
- key = has_content? ? [name, content] : name
172
+ children_hash = {}
173
+ children do |child|
174
+ children_hash.merge! child.to_h
175
+ end
165
176
 
166
- children_hash = {}
167
- children do |child|
168
- children_hash.merge! child.to_h
177
+ { key => children_hash }
178
+ end
169
179
  end
170
-
171
- { key => children_hash }
172
180
  end
173
181
  end