rubytree 1.0.2 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/API-CHANGES.md +153 -0
- data/Gemfile +2 -6
- data/Gemfile.lock +40 -55
- data/History.md +410 -0
- data/LICENSE.md +1 -1
- data/README.md +21 -24
- data/Rakefile +41 -20
- data/TODO.org +19 -15
- data/examples/example_basic.rb +14 -7
- data/lib/rubytree.rb +2 -3
- data/lib/tree/binarytree.rb +13 -12
- data/lib/tree/tree_deps.rb +2 -5
- data/lib/tree/utils/hash_converter.rb +129 -121
- data/lib/tree/utils/json_converter.rb +80 -77
- data/lib/tree/utils/metrics_methods.rb +14 -47
- data/lib/tree/utils/path_methods.rb +11 -11
- data/lib/tree/utils/tree_merge_handler.rb +80 -80
- data/lib/tree/utils/utils.rb +9 -7
- data/lib/tree/version.rb +3 -4
- data/lib/tree.rb +80 -82
- data/rubytree.gemspec +61 -38
- data/spec/spec_helper.rb +4 -2
- data/spec/tree_spec.rb +129 -28
- data/test/run_test.rb +4 -3
- data/test/test_binarytree.rb +25 -45
- data/test/test_rubytree_require.rb +2 -1
- data/test/test_subclassed_node.rb +2 -20
- data/test/test_thread_and_fiber.rb +4 -4
- data/test/test_tree.rb +126 -199
- metadata +103 -69
- data/API-CHANGES.rdoc +0 -99
- data/History.rdoc +0 -303
- data/lib/tree/utils/camel_case_method_handler.rb +0 -77
- data/setup.rb +0 -1565
data/lib/tree.rb
CHANGED
@@ -9,9 +9,7 @@
|
|
9
9
|
# Author:: Anupam Sengupta (anupamsg@gmail.com)
|
10
10
|
#
|
11
11
|
|
12
|
-
# Copyright (c) 2006-
|
13
|
-
#
|
14
|
-
# All rights reserved.
|
12
|
+
# Copyright (c) 2006-2022 Anupam Sengupta. All rights reserved.
|
15
13
|
#
|
16
14
|
# Redistribution and use in source and binary forms, with or without
|
17
15
|
# modification, are permitted provided that the following conditions are met:
|
@@ -38,6 +36,7 @@
|
|
38
36
|
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
39
37
|
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
40
38
|
#
|
39
|
+
# frozen_string_literal: true
|
41
40
|
|
42
41
|
require 'tree/tree_deps'
|
43
42
|
|
@@ -88,7 +87,6 @@ module Tree
|
|
88
87
|
include Comparable
|
89
88
|
include Tree::Utils::TreeMetricsHandler
|
90
89
|
include Tree::Utils::TreePathHandler
|
91
|
-
include Tree::Utils::CamelCaseMethodHandler
|
92
90
|
include Tree::Utils::JSONConverter
|
93
91
|
include Tree::Utils::TreeMergeHandler
|
94
92
|
include Tree::Utils::HashConverter
|
@@ -132,38 +130,44 @@ module Tree
|
|
132
130
|
# @return [Tree::TreeNode] Root of the (sub)tree.
|
133
131
|
def root
|
134
132
|
root = self
|
135
|
-
root = root.parent until root.
|
133
|
+
root = root.parent until root.root?
|
136
134
|
root
|
137
135
|
end
|
138
136
|
|
139
|
-
# @!attribute [r]
|
137
|
+
# @!attribute [r] root?
|
140
138
|
# Returns +true+ if this is a root node. Note that
|
141
139
|
# orphaned children will also be reported as root nodes.
|
142
140
|
#
|
143
141
|
# @return [Boolean] +true+ if this is a root node.
|
144
|
-
def
|
142
|
+
def root?
|
145
143
|
@parent.nil?
|
146
144
|
end
|
147
145
|
|
148
|
-
#
|
146
|
+
alias is_root? root? # @todo: Aliased for eventual replacement
|
147
|
+
|
148
|
+
# @!attribute [r] content?
|
149
149
|
# +true+ if this node has content.
|
150
150
|
#
|
151
151
|
# @return [Boolean] +true+ if the node has content.
|
152
|
-
def
|
152
|
+
def content?
|
153
153
|
@content != nil
|
154
154
|
end
|
155
155
|
|
156
|
-
#
|
156
|
+
alias has_content? content? # @todo: Aliased for eventual replacement
|
157
|
+
|
158
|
+
# @!attribute [r] leaf?
|
157
159
|
# +true+ if this node is a _leaf_ - i.e., one without
|
158
160
|
# any children.
|
159
161
|
#
|
160
162
|
# @return [Boolean] +true+ if this is a leaf node.
|
161
163
|
#
|
162
|
-
# @see #
|
163
|
-
def
|
164
|
-
!
|
164
|
+
# @see #children?
|
165
|
+
def leaf?
|
166
|
+
!children?
|
165
167
|
end
|
166
168
|
|
169
|
+
alias is_leaf? leaf? # @todo: Aliased for eventual replacement
|
170
|
+
|
167
171
|
# @!attribute [r] parentage
|
168
172
|
# An array of ancestors of this node in reversed order
|
169
173
|
# (the first element is the immediate parent of this node).
|
@@ -173,7 +177,7 @@ module Tree
|
|
173
177
|
# @return [Array<Tree::TreeNode>] An array of ancestors of this node
|
174
178
|
# @return [nil] if this is a root node.
|
175
179
|
def parentage
|
176
|
-
return nil if
|
180
|
+
return nil if root?
|
177
181
|
|
178
182
|
parentage_array = []
|
179
183
|
prev_parent = parent
|
@@ -184,16 +188,18 @@ module Tree
|
|
184
188
|
parentage_array
|
185
189
|
end
|
186
190
|
|
187
|
-
# @!attribute [r]
|
191
|
+
# @!attribute [r] children?
|
188
192
|
# +true+ if the this node has any child node.
|
189
193
|
#
|
190
194
|
# @return [Boolean] +true+ if child nodes exist.
|
191
195
|
#
|
192
|
-
# @see #
|
193
|
-
def
|
194
|
-
|
196
|
+
# @see #leaf?
|
197
|
+
def children?
|
198
|
+
!@children.empty?
|
195
199
|
end
|
196
200
|
|
201
|
+
alias has_children? children? # @todo: Aliased for eventual replacement
|
202
|
+
|
197
203
|
# @!group Node Creation
|
198
204
|
|
199
205
|
# Creates a new node with a name and optional content.
|
@@ -217,16 +223,10 @@ module Tree
|
|
217
223
|
def initialize(name, content = nil)
|
218
224
|
raise ArgumentError, 'Node name HAS to be provided!' if name.nil?
|
219
225
|
|
226
|
+
name = name.to_s if name.is_a?(Integer)
|
220
227
|
@name = name
|
221
228
|
@content = content
|
222
229
|
|
223
|
-
if name.is_a?(Integer)
|
224
|
-
warn StructuredWarnings::StandardWarning,
|
225
|
-
'Using integer as node name.'\
|
226
|
-
' Semantics of TreeNode[] may not be what you expect!'\
|
227
|
-
" #{name} #{content}"
|
228
|
-
end
|
229
|
-
|
230
230
|
set_as_root!
|
231
231
|
@children_hash = {}
|
232
232
|
@children = []
|
@@ -237,7 +237,13 @@ module Tree
|
|
237
237
|
#
|
238
238
|
# @return [Tree::TreeNode] A copy of this node.
|
239
239
|
def detached_copy
|
240
|
-
|
240
|
+
cloned_content =
|
241
|
+
begin
|
242
|
+
@content&.clone
|
243
|
+
rescue TypeError
|
244
|
+
@content
|
245
|
+
end
|
246
|
+
self.class.new(@name, cloned_content)
|
241
247
|
end
|
242
248
|
|
243
249
|
# Returns a copy of entire (sub-)tree from this node.
|
@@ -261,14 +267,14 @@ module Tree
|
|
261
267
|
# representation of the (sub)tree rooted at this node.
|
262
268
|
#
|
263
269
|
def marshal_dump
|
264
|
-
collect
|
270
|
+
collect(&:create_dump_rep)
|
265
271
|
end
|
266
272
|
|
267
273
|
# Creates a dump representation of this node and returns the same as
|
268
274
|
# a hash.
|
269
275
|
def create_dump_rep # :nodoc:
|
270
276
|
{ name: @name,
|
271
|
-
parent: (
|
277
|
+
parent: (root? ? nil : @parent.name),
|
272
278
|
content: Marshal.dump(@content) }
|
273
279
|
end
|
274
280
|
|
@@ -279,6 +285,9 @@ module Tree
|
|
279
285
|
# {Marshal}[http://ruby-doc.org/core-1.8.7/Marshal.html] class for
|
280
286
|
# additional details.
|
281
287
|
#
|
288
|
+
# NOTE: This is a potentially *unsafe* method with similar concerns as with
|
289
|
+
# the Marshal#load method, and should *not* be used with untrusted user
|
290
|
+
# provided data.
|
282
291
|
#
|
283
292
|
# @todo This method probably should be a class method. It currently clobbers
|
284
293
|
# self and makes itself the root.
|
@@ -291,7 +300,7 @@ module Tree
|
|
291
300
|
content = Marshal.load(node_hash[:content])
|
292
301
|
|
293
302
|
if parent_name
|
294
|
-
nodes[name] = current_node =
|
303
|
+
nodes[name] = current_node = self.class.new(name, content)
|
295
304
|
nodes[parent_name].add current_node
|
296
305
|
else
|
297
306
|
# This is the root node, hence initialize self.
|
@@ -309,7 +318,9 @@ module Tree
|
|
309
318
|
#
|
310
319
|
# @return [String] A string representation of the node.
|
311
320
|
def to_s
|
312
|
-
"Node Name: #{@name} Content: #{@content.to_s || '<Empty>'}
|
321
|
+
"Node Name: #{@name} Content: #{@content.to_s || '<Empty>'} " \
|
322
|
+
"Parent: #{root? ? '<None>' : @parent.name.to_s} " \
|
323
|
+
"Children: #{@children.length} Total Nodes: #{size}"
|
313
324
|
end
|
314
325
|
|
315
326
|
# @!group Structure Modification
|
@@ -422,7 +433,7 @@ module Tree
|
|
422
433
|
def rename(new_name)
|
423
434
|
old_name = @name
|
424
435
|
|
425
|
-
if
|
436
|
+
if root?
|
426
437
|
self.name = new_name
|
427
438
|
else
|
428
439
|
@parent.rename_child old_name, new_name
|
@@ -516,7 +527,7 @@ module Tree
|
|
516
527
|
#
|
517
528
|
# @see #remove_all!
|
518
529
|
def remove_from_parent!
|
519
|
-
@parent.remove!(self) unless
|
530
|
+
@parent.remove!(self) unless root?
|
520
531
|
end
|
521
532
|
|
522
533
|
# Removes all children from this node. If an independent reference exists to
|
@@ -528,7 +539,7 @@ module Tree
|
|
528
539
|
# @see #remove!
|
529
540
|
# @see #remove_from_parent!
|
530
541
|
def remove_all!
|
531
|
-
@children.each
|
542
|
+
@children.each(&:remove_all!)
|
532
543
|
|
533
544
|
@children_hash.clear
|
534
545
|
@children.clear
|
@@ -549,7 +560,7 @@ module Tree
|
|
549
560
|
# The nodes become immutable after this operation. In effect, the entire tree's
|
550
561
|
# structure and contents become _read-only_ and cannot be changed.
|
551
562
|
def freeze_tree!
|
552
|
-
each
|
563
|
+
each(&:freeze)
|
553
564
|
end
|
554
565
|
|
555
566
|
# @!endgroup
|
@@ -560,45 +571,31 @@ module Tree
|
|
560
571
|
#
|
561
572
|
# - If the +name+ argument is an _Integer_, then the in-sequence
|
562
573
|
# array of children is accessed using the argument as the
|
563
|
-
# *index* (zero-based).
|
564
|
-
# +num_as_name+ argument is +true+, then the +name+ is used
|
565
|
-
# literally as a name, and *NOT* as an *index*
|
574
|
+
# *index* (zero-based).
|
566
575
|
#
|
567
576
|
# - If the +name+ argument is *NOT* an _Integer_, then it is taken to
|
568
577
|
# be the *name* of the child node to be returned.
|
569
578
|
#
|
570
|
-
#
|
571
|
-
#
|
572
|
-
# redundant use of the +num_as_name+ flag.)
|
579
|
+
# - To use an _Integer_ as the name, convert it to a _String_ first using
|
580
|
+
# +<integer>.to_s+.
|
573
581
|
#
|
574
582
|
# @param [String|Number] name_or_index Name of the child, or its
|
575
583
|
# positional index in the array of child nodes.
|
576
584
|
#
|
577
|
-
# @param [Boolean] num_as_name Whether to treat the +Integer+
|
578
|
-
# +name+ argument as an actual name, and *NOT* as an _index_ to
|
579
|
-
# the children array.
|
580
|
-
#
|
581
585
|
# @return [Tree::TreeNode] the requested child node. If the index
|
582
586
|
# in not in range, or the name is not present, then a +nil+
|
583
587
|
# is returned.
|
584
588
|
#
|
585
|
-
# @note The use of +Integer+ names is allowed by using the optional
|
586
|
-
# +num_as_name+ flag.
|
587
|
-
#
|
588
589
|
# @raise [ArgumentError] Raised if the +name_or_index+ argument is +nil+.
|
589
590
|
#
|
590
591
|
# @see #add
|
591
592
|
# @see #initialize
|
592
|
-
def [](name_or_index
|
593
|
+
def [](name_or_index)
|
593
594
|
raise ArgumentError, 'Name_or_index needs to be provided!' if name_or_index.nil?
|
594
595
|
|
595
|
-
if name_or_index.is_a?(Integer)
|
596
|
+
if name_or_index.is_a?(Integer)
|
596
597
|
@children[name_or_index]
|
597
598
|
else
|
598
|
-
if num_as_name && !name_or_index.is_a?(Integer)
|
599
|
-
warn StructuredWarnings::StandardWarning,
|
600
|
-
'Redundant use of the `num_as_name` flag for non-integer node name'
|
601
|
-
end
|
602
599
|
@children_hash[name_or_index]
|
603
600
|
end
|
604
601
|
end
|
@@ -609,7 +606,6 @@ module Tree
|
|
609
606
|
# The traversal is *depth-first* and from *left-to-right* in pre-ordered
|
610
607
|
# sequence.
|
611
608
|
#
|
612
|
-
# @param [Object] block
|
613
609
|
# @yieldparam node [Tree::TreeNode] Each node.
|
614
610
|
#
|
615
611
|
# @see #preordered_each
|
@@ -651,7 +647,6 @@ module Tree
|
|
651
647
|
|
652
648
|
# Traverses the (sub)tree rooted at this node in post-ordered sequence.
|
653
649
|
#
|
654
|
-
# @param [Object] block
|
655
650
|
# @yieldparam node [Tree::TreeNode] Each node.
|
656
651
|
#
|
657
652
|
# @see #preordered_each
|
@@ -670,7 +665,7 @@ module Tree
|
|
670
665
|
|
671
666
|
until node_stack.empty?
|
672
667
|
peek_node = node_stack[0]
|
673
|
-
if peek_node.node.
|
668
|
+
if peek_node.node.children? && !peek_node.visited
|
674
669
|
peek_node.visited = true
|
675
670
|
# Add the children to the stack. Use the marking structure.
|
676
671
|
marked_children =
|
@@ -689,7 +684,6 @@ module Tree
|
|
689
684
|
# traversal at a given level is from *left-to-right*. this node itself is
|
690
685
|
# the first node to be traversed.
|
691
686
|
#
|
692
|
-
# @param [Object] block
|
693
687
|
# @yieldparam node [Tree::TreeNode] Each node.
|
694
688
|
#
|
695
689
|
# @see #preordered_each
|
@@ -741,7 +735,6 @@ module Tree
|
|
741
735
|
# May yield this node as well if this is a leaf node.
|
742
736
|
# Leaf traversal is *depth-first* and *left-to-right*.
|
743
737
|
#
|
744
|
-
# @param [Object] block
|
745
738
|
# @yieldparam node [Tree::TreeNode] Each leaf node.
|
746
739
|
#
|
747
740
|
# @see #each
|
@@ -752,10 +745,10 @@ module Tree
|
|
752
745
|
# noinspection RubyUnusedLocalVariable
|
753
746
|
def each_leaf
|
754
747
|
if block_given?
|
755
|
-
each { |node| yield(node) if node.
|
748
|
+
each { |node| yield(node) if node.leaf? }
|
756
749
|
self
|
757
750
|
else
|
758
|
-
self.select
|
751
|
+
self.select(&:leaf?)
|
759
752
|
end
|
760
753
|
end
|
761
754
|
|
@@ -813,22 +806,24 @@ module Tree
|
|
813
806
|
#
|
814
807
|
# @return [Tree::TreeNode] The first sibling node.
|
815
808
|
#
|
816
|
-
# @see #
|
809
|
+
# @see #first_sibling?
|
817
810
|
# @see #last_sibling
|
818
811
|
def first_sibling
|
819
|
-
|
812
|
+
root? ? self : parent.children.first
|
820
813
|
end
|
821
814
|
|
822
815
|
# Returns +true+ if this node is the first sibling at its level.
|
823
816
|
#
|
824
817
|
# @return [Boolean] +true+ if this is the first sibling.
|
825
818
|
#
|
826
|
-
# @see #
|
819
|
+
# @see #last_sibling?
|
827
820
|
# @see #first_sibling
|
828
|
-
def
|
821
|
+
def first_sibling?
|
829
822
|
first_sibling == self
|
830
823
|
end
|
831
824
|
|
825
|
+
alias is_first_sibling? first_sibling? # @todo: Aliased for eventual replacement
|
826
|
+
|
832
827
|
# Last sibling of this node. If this is the root node, then returns
|
833
828
|
# itself.
|
834
829
|
#
|
@@ -839,22 +834,24 @@ module Tree
|
|
839
834
|
#
|
840
835
|
# @return [Tree::TreeNode] The last sibling node.
|
841
836
|
#
|
842
|
-
# @see #
|
837
|
+
# @see #last_sibling?
|
843
838
|
# @see #first_sibling
|
844
839
|
def last_sibling
|
845
|
-
|
840
|
+
root? ? self : parent.children.last
|
846
841
|
end
|
847
842
|
|
848
843
|
# Returns +true+ if this node is the last sibling at its level.
|
849
844
|
#
|
850
845
|
# @return [Boolean] +true+ if this is the last sibling.
|
851
846
|
#
|
852
|
-
# @see #
|
847
|
+
# @see #first_sibling?
|
853
848
|
# @see #last_sibling
|
854
|
-
def
|
849
|
+
def last_sibling?
|
855
850
|
last_sibling == self
|
856
851
|
end
|
857
852
|
|
853
|
+
alias is_last_sibling? last_sibling? # @todo: Aliased for eventual replacement
|
854
|
+
|
858
855
|
# An array of siblings for this node. This node is excluded.
|
859
856
|
#
|
860
857
|
# If a block is provided, yields each of the sibling nodes to the block.
|
@@ -874,7 +871,7 @@ module Tree
|
|
874
871
|
parent.children.each { |sibling| yield sibling if sibling != self }
|
875
872
|
self
|
876
873
|
else
|
877
|
-
return [] if
|
874
|
+
return [] if root?
|
878
875
|
|
879
876
|
siblings = []
|
880
877
|
parent.children do |my_sibling|
|
@@ -891,10 +888,12 @@ module Tree
|
|
891
888
|
# @return [Boolean] +true+ if this is the only child of its parent.
|
892
889
|
#
|
893
890
|
# @see #siblings
|
894
|
-
def
|
895
|
-
|
891
|
+
def only_child?
|
892
|
+
root? ? true : parent.children.size == 1
|
896
893
|
end
|
897
894
|
|
895
|
+
alias is_only_child? only_child? # @todo: Aliased for eventual replacement
|
896
|
+
|
898
897
|
# Next sibling for this node.
|
899
898
|
# The _next_ node is defined as the node to right of this node.
|
900
899
|
#
|
@@ -906,7 +905,7 @@ module Tree
|
|
906
905
|
# @see #previous_sibling
|
907
906
|
# @see #siblings
|
908
907
|
def next_sibling
|
909
|
-
return nil if
|
908
|
+
return nil if root?
|
910
909
|
|
911
910
|
idx = parent.children.index(self)
|
912
911
|
parent.children.at(idx + 1) if idx
|
@@ -923,10 +922,10 @@ module Tree
|
|
923
922
|
# @see #next_sibling
|
924
923
|
# @see #siblings
|
925
924
|
def previous_sibling
|
926
|
-
return nil if
|
925
|
+
return nil if root?
|
927
926
|
|
928
927
|
idx = parent.children.index(self)
|
929
|
-
parent.children.at(idx - 1) if idx
|
928
|
+
parent.children.at(idx - 1) if idx&.positive?
|
930
929
|
end
|
931
930
|
|
932
931
|
# @!endgroup
|
@@ -941,7 +940,7 @@ module Tree
|
|
941
940
|
# this node is a 'predecessor'. Returns 'nil' if the other
|
942
941
|
# object is not a 'Tree::TreeNode'.
|
943
942
|
def <=>(other)
|
944
|
-
return nil if other.nil? || other.
|
943
|
+
return nil if other.nil? || !other.is_a?(Tree::TreeNode)
|
945
944
|
|
946
945
|
name <=> other.name
|
947
946
|
end
|
@@ -956,16 +955,16 @@ module Tree
|
|
956
955
|
block = lambda { |node, prefix|
|
957
956
|
puts "#{prefix} #{node.name}"
|
958
957
|
})
|
959
|
-
prefix = ''
|
958
|
+
prefix = ''.dup # dup NEEDs to be invoked to make this mutable.
|
960
959
|
|
961
|
-
if
|
960
|
+
if root?
|
962
961
|
prefix << '*'
|
963
962
|
else
|
964
|
-
prefix << '|' unless parent.
|
963
|
+
prefix << '|' unless parent.last_sibling?
|
965
964
|
prefix << (' ' * (level - 1) * 4)
|
966
|
-
prefix << (
|
965
|
+
prefix << (last_sibling? ? '+' : '|')
|
967
966
|
prefix << '---'
|
968
|
-
prefix << (
|
967
|
+
prefix << (children? ? '+' : '>')
|
969
968
|
end
|
970
969
|
|
971
970
|
block.call(self, prefix)
|
@@ -975,8 +974,7 @@ module Tree
|
|
975
974
|
|
976
975
|
# Child might be 'nil'
|
977
976
|
children do |child|
|
978
|
-
child&.print_tree(level + 1,
|
979
|
-
max_depth, block)
|
977
|
+
child&.print_tree(level + 1, max_depth, block)
|
980
978
|
end
|
981
979
|
end
|
982
980
|
end
|
data/rubytree.gemspec
CHANGED
@@ -3,51 +3,55 @@
|
|
3
3
|
#
|
4
4
|
# Author:: Anupam Sengupta (anupamsg@gmail.com)
|
5
5
|
#
|
6
|
-
# Copyright (c) 2012
|
7
|
-
#
|
6
|
+
# Copyright (c) 2012-2022 Anupam Sengupta. All rights reserved.
|
7
|
+
#
|
8
|
+
# frozen_string_literal: true
|
8
9
|
|
9
10
|
require './lib/tree/version'
|
10
11
|
|
11
12
|
Gem::Specification.new do |s|
|
12
13
|
s.name = 'rubytree'
|
13
|
-
s.date = '2021-12-29'
|
14
14
|
s.version = Tree::VERSION
|
15
15
|
s.license = 'BSD-3-Clause-Clear'
|
16
|
-
|
16
|
+
# NOTE: s.date should NOT be assigned. It is automatically set to pkg date.
|
17
17
|
s.platform = Gem::Platform::RUBY
|
18
18
|
s.author = 'Anupam Sengupta'
|
19
19
|
s.email = 'anupamsg@gmail.com'
|
20
20
|
s.homepage = 'http://rubytree.anupamsg.me'
|
21
21
|
|
22
|
-
s.required_ruby_version = '>=2.
|
22
|
+
s.required_ruby_version = '>=2.6'
|
23
23
|
|
24
|
-
s.summary = 'A generic tree data structure.'
|
25
|
-
s.description = <<-END_OF_TEXT
|
24
|
+
s.summary = 'A generic tree data structure for Ruby.'
|
26
25
|
|
27
|
-
|
28
|
-
|
29
|
-
|
26
|
+
s.description = <<-END_DESC
|
27
|
+
RubyTree is a pure Ruby implementation of the generic tree data
|
28
|
+
structure. It provides a node-based model to store named nodes in the tree,
|
29
|
+
and provides simple APIs to access, modify and traverse the structure.
|
30
30
|
|
31
|
-
The implementation is node-centric, where individual nodes in the tree are
|
32
|
-
primary structural elements. All common tree-traversal methods
|
33
|
-
post-order, and breadth-first) are supported.
|
31
|
+
The implementation is node-centric, where individual nodes in the tree are
|
32
|
+
the primary structural elements. All common tree-traversal methods
|
33
|
+
(pre-order, post-order, and breadth-first) are supported.
|
34
34
|
|
35
|
-
The library mixes in the Enumerable and Comparable modules to allow access
|
36
|
-
the tree as a standard collection (iteration, comparison, etc.).
|
35
|
+
The library mixes in the Enumerable and Comparable modules to allow access
|
36
|
+
to the tree as a standard collection (iteration, comparison, etc.).
|
37
37
|
|
38
38
|
A Binary tree is also provided, which provides the in-order traversal in
|
39
39
|
addition to the other methods.
|
40
40
|
|
41
|
-
RubyTree supports importing from, and exporting to JSON, and also supports
|
42
|
-
Ruby's standard object marshaling.
|
41
|
+
RubyTree supports importing from, and exporting to JSON, and also supports
|
42
|
+
the Ruby's standard object marshaling.
|
43
43
|
|
44
44
|
This is a BSD licensed open source project, and is hosted at
|
45
|
-
|
46
|
-
|
45
|
+
<https://github.com/evolve75/RubyTree>, and is available as a standard gem
|
46
|
+
from <https://rubygems.org/gems/rubytree>.
|
47
|
+
|
48
|
+
The home page for RubyTree is at <http://rubytree.anupamsg.me>.
|
47
49
|
|
48
|
-
|
50
|
+
END_DESC
|
49
51
|
|
50
|
-
|
52
|
+
s.metadata = {
|
53
|
+
'rubygems_mfa_required' => 'true'
|
54
|
+
}
|
51
55
|
|
52
56
|
s.files = Dir['lib/**/*.rb'] # The actual code
|
53
57
|
s.files += Dir['[A-Z]*'] # Various documentation files
|
@@ -55,36 +59,55 @@ Gem::Specification.new do |s|
|
|
55
59
|
s.files += Dir['spec/**/*.rb'] # Rspec Test cases
|
56
60
|
s.files += Dir['examples/**/*.rb'] # Examples
|
57
61
|
|
62
|
+
# @todo: Check if this is really needed.
|
58
63
|
s.files += ['.gemtest'] # Support for gem-test
|
59
64
|
|
60
65
|
s.require_paths = ['lib']
|
61
66
|
|
62
67
|
s.test_files = Dir.glob('test/**/test_*.rb')
|
63
68
|
|
64
|
-
s.extra_rdoc_files = %w[README.md LICENSE.md API-CHANGES.
|
65
|
-
s.rdoc_options = ['--title',
|
69
|
+
s.extra_rdoc_files = %w[README.md LICENSE.md API-CHANGES.md History.md]
|
70
|
+
s.rdoc_options = ['--title', "Rubytree Documentation: #{s.name}-#{s.version}",
|
71
|
+
'--main', 'README.md',
|
72
|
+
'--quiet']
|
66
73
|
|
67
|
-
s.add_runtime_dependency 'json', '~> 2.
|
68
|
-
s.add_runtime_dependency 'structured_warnings', '~> 0.4.0'
|
74
|
+
s.add_runtime_dependency 'json', '~> 2.0', '> 2.3.1'
|
69
75
|
|
70
|
-
#
|
71
|
-
s.add_development_dependency 'bundler', '~> 2.3
|
72
|
-
s.add_development_dependency '
|
73
|
-
s.add_development_dependency '
|
74
|
-
s.add_development_dependency '
|
75
|
-
s.add_development_dependency 'rspec', '~> 3.10.0'
|
76
|
+
# NOTE: Rake is added as a development and test dependency in the Gemfile.
|
77
|
+
s.add_development_dependency 'bundler', '~> 2.3'
|
78
|
+
s.add_development_dependency 'rake', '~> 13.0'
|
79
|
+
s.add_development_dependency 'rdoc', '~> 6.0'
|
80
|
+
s.add_development_dependency 'rspec', '~> 3.0', '> 3.10'
|
76
81
|
s.add_development_dependency 'rtagstask', '~> 0.0.4'
|
77
|
-
s.add_development_dependency 'rubocop', '
|
78
|
-
s.add_development_dependency '
|
79
|
-
s.add_development_dependency '
|
82
|
+
s.add_development_dependency 'rubocop', '~> 1.0'
|
83
|
+
s.add_development_dependency 'rubocop-rake', '~> 0.0'
|
84
|
+
s.add_development_dependency 'rubocop-rspec', '~> 2.0'
|
85
|
+
s.add_development_dependency 'test-unit', '~> 3.0'
|
86
|
+
s.add_development_dependency 'yard', '~> 0.0', '>= 0.9.20'
|
80
87
|
|
81
|
-
s.post_install_message = <<-
|
88
|
+
s.post_install_message = <<-END_MESSAGE
|
82
89
|
========================================================================
|
83
90
|
Thank you for installing RubyTree.
|
84
91
|
|
85
|
-
Note::
|
92
|
+
Note::
|
93
|
+
|
94
|
+
- 2.0.0 is a major release with BREAKING API changes.
|
95
|
+
See `API-CHANGES.md` for details.
|
96
|
+
|
97
|
+
- `Tree::TreeNode#depth` method has been removed (it was broken).
|
98
|
+
|
99
|
+
- Support for `CamelCase` methods names has bee removed.
|
100
|
+
|
101
|
+
- The predicate methods no longer have `is_` or `has_` prefixes. However,
|
102
|
+
aliases with these prefixes exist to support existing client code.
|
103
|
+
|
104
|
+
- Use of integers as node names does not require the optional
|
105
|
+
`num_as_name` flag.
|
106
|
+
|
107
|
+
- `structured_warnings` is no longer a dependency.
|
108
|
+
|
109
|
+
- Explicit support for rbx Ruby has been removed.
|
86
110
|
|
87
|
-
Details of the API changes are documented in the API-CHANGES file.
|
88
111
|
========================================================================
|
89
|
-
|
112
|
+
END_MESSAGE
|
90
113
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -3,8 +3,10 @@
|
|
3
3
|
# spec_helper.rb
|
4
4
|
#
|
5
5
|
# Author: Anupam Sengupta
|
6
|
-
# Time-stamp: <
|
7
|
-
# Copyright (C) 2015 Anupam Sengupta <anupamsg@gmail.com>
|
6
|
+
# Time-stamp: <2022-06-19 22:38:14 anupam>
|
8
7
|
#
|
8
|
+
# Copyright (C) 2015, 2022 Anupam Sengupta <anupamsg@gmail.com>
|
9
|
+
#
|
10
|
+
# frozen_string_literal: true
|
9
11
|
|
10
12
|
require 'tree'
|