rubytree 0.8.2 → 0.8.3
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.
- data/.dir-locals.el +5 -0
- data/{API-CHANGES → API-CHANGES.rdoc} +12 -9
- data/{COPYING → COPYING.rdoc} +2 -13
- data/Gemfile +8 -0
- data/Gemfile.lock +28 -0
- data/{History.txt → History.rdoc} +35 -1
- data/{README → README.rdoc} +6 -8
- data/Rakefile +65 -89
- data/TODO.org +174 -0
- data/lib/rubytree.rb +41 -0
- data/lib/tree.rb +195 -133
- data/lib/tree/binarytree.rb +5 -7
- data/lib/tree/tree_deps.rb +41 -0
- data/lib/tree/version.rb +41 -0
- data/test/test_binarytree.rb +1 -2
- data/test/test_rubytree_require.rb +48 -0
- data/test/test_tree.rb +72 -10
- metadata +152 -104
- data/Manifest.txt +0 -12
- data/TODO +0 -57
- data/setup.rb +0 -1585
data/lib/rubytree.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
# rubytree.rb - This file is part of the RubyTree package.
|
2
|
+
#
|
3
|
+
|
4
|
+
# = rubytree.rb - Generic implementation of an N-ary tree data structure.
|
5
|
+
#
|
6
|
+
# This file provides an alternative mechanism to require 'tree.rb', in case
|
7
|
+
# there is a conflict with another gem or Ruby package.
|
8
|
+
#
|
9
|
+
# Author:: Anupam Sengupta (anupamsg@gmail.com)
|
10
|
+
#
|
11
|
+
# Copyright (c) 2012 Anupam Sengupta
|
12
|
+
#
|
13
|
+
# All rights reserved.
|
14
|
+
#
|
15
|
+
# Redistribution and use in source and binary forms, with or without modification,
|
16
|
+
# are permitted provided that the following conditions are met:
|
17
|
+
#
|
18
|
+
# - Redistributions of source code must retain the above copyright notice, this
|
19
|
+
# list of conditions and the following disclaimer.
|
20
|
+
#
|
21
|
+
# - Redistributions in binary form must reproduce the above copyright notice, this
|
22
|
+
# list of conditions and the following disclaimer in the documentation and/or
|
23
|
+
# other materials provided with the distribution.
|
24
|
+
#
|
25
|
+
# - Neither the name of the organization nor the names of its contributors may
|
26
|
+
# be used to endorse or promote products derived from this software without
|
27
|
+
# specific prior written permission.
|
28
|
+
#
|
29
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
30
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
31
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
32
|
+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
33
|
+
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
34
|
+
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
35
|
+
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
36
|
+
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
37
|
+
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
38
|
+
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
39
|
+
#
|
40
|
+
|
41
|
+
require "tree.rb"
|
data/lib/tree.rb
CHANGED
@@ -1,7 +1,5 @@
|
|
1
1
|
# tree.rb - This file is part of the RubyTree package.
|
2
2
|
#
|
3
|
-
# $Revision$ by $Author$ on $Date$
|
4
|
-
#
|
5
3
|
# = tree.rb - Generic implementation of an N-ary tree data structure.
|
6
4
|
#
|
7
5
|
# Provides a generic tree data structure with ability to
|
@@ -11,7 +9,7 @@
|
|
11
9
|
# Author:: Anupam Sengupta (anupamsg@gmail.com)
|
12
10
|
#
|
13
11
|
|
14
|
-
# Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011 Anupam Sengupta
|
12
|
+
# Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011, 2012 Anupam Sengupta
|
15
13
|
#
|
16
14
|
# All rights reserved.
|
17
15
|
#
|
@@ -41,37 +39,44 @@
|
|
41
39
|
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
42
40
|
#
|
43
41
|
|
42
|
+
require 'tree/tree_deps'
|
43
|
+
require 'tree/version'
|
44
|
+
|
44
45
|
# This module provides a TreeNode class which is the primary class for representing
|
45
46
|
# nodes in the tree.
|
46
47
|
#
|
47
48
|
# This module also acts as the namespace for all classes in the RubyTree package.
|
48
49
|
module Tree
|
49
50
|
|
50
|
-
# Rubytree Package Version
|
51
|
-
VERSION = '0.8.2'
|
52
|
-
|
53
51
|
# == TreeNode Class Description
|
54
52
|
#
|
55
|
-
# This class models the nodes for an *N-ary* tree data structue. The
|
56
|
-
# and have a place-holder for the node data (i.e.,
|
57
|
-
# names are required to be *unique*
|
53
|
+
# This class models the nodes for an *N-ary* tree data structue. The
|
54
|
+
# nodes are *named* and have a place-holder for the node data (i.e.,
|
55
|
+
# _content_ of the node). The node names are required to be *unique*
|
56
|
+
# within the tree (as the name is implicitly used as an _ID_ within
|
57
|
+
# the data structure).
|
58
58
|
#
|
59
|
-
# The node's _content_ is *not* required to be unique across
|
60
|
-
# can be +nil+ as well.
|
59
|
+
# The node's _content_ is *not* required to be unique across
|
60
|
+
# different nodes in the tree, and can be +nil+ as well.
|
61
61
|
#
|
62
|
-
# The class provides various methods to navigate the tree, traverse
|
63
|
-
# modify contents of the node, change position of the
|
64
|
-
# and to make structural changes to the tree.
|
62
|
+
# The class provides various methods to navigate the tree, traverse
|
63
|
+
# the structure, modify contents of the node, change position of the
|
64
|
+
# node in the tree, and to make structural changes to the tree.
|
65
65
|
#
|
66
|
-
# A node can have any number of *child* nodes attached to it and
|
67
|
-
#
|
68
|
-
#
|
66
|
+
# A node can have any number of *child* nodes attached to it and
|
67
|
+
# hence can be used to create N-ary trees. Access to the child
|
68
|
+
# nodes can be made in order (with the conventional left to right
|
69
|
+
# access), or randomly.
|
69
70
|
#
|
70
|
-
# The node also provides direct access to its *parent* node as well
|
71
|
-
#
|
71
|
+
# The node also provides direct access to its *parent* node as well
|
72
|
+
# as other superior parents in the path to root of the tree. In
|
73
|
+
# addition, a node can also access its *sibling* nodes, if present.
|
72
74
|
#
|
73
|
-
# Note that while this implementation does not _explicitly_ support
|
74
|
-
#
|
75
|
+
# Note that while this implementation does not _explicitly_ support
|
76
|
+
# directed graphs, the class itself makes no restrictions on
|
77
|
+
# associating a node's *content* with multiple nodes in the tree.
|
78
|
+
# However, having duplicate nodes within the structure is likely to
|
79
|
+
# cause unpredictable behavior.
|
75
80
|
#
|
76
81
|
#
|
77
82
|
# == Example
|
@@ -126,28 +131,62 @@ module Tree
|
|
126
131
|
class TreeNode
|
127
132
|
include Enumerable
|
128
133
|
|
134
|
+
# @!attribute [r] name
|
135
|
+
#
|
129
136
|
# Name of this node. Expected to be unique within the tree.
|
137
|
+
#
|
138
|
+
# Note that the name attribute really functions as an *ID* within
|
139
|
+
# the tree structure, and hence the uniqueness constraint is
|
140
|
+
# required.
|
141
|
+
#
|
142
|
+
# This may be changed in the future, but for now it is best to
|
143
|
+
# retain unique names within the tree structure, and use the
|
144
|
+
# +content+ attribute for any non-unique node requirements.
|
145
|
+
#
|
146
|
+
# @see content
|
130
147
|
attr_reader :name
|
131
148
|
|
132
|
-
#
|
149
|
+
# @!attribute [rw] content
|
150
|
+
#
|
151
|
+
# Content of this node. Can be +nil+. Note that there is no
|
152
|
+
# uniqueness constraint related to this attribute.
|
153
|
+
#
|
154
|
+
# @see name
|
133
155
|
attr_accessor :content
|
134
156
|
|
157
|
+
# @!attribute [r] parent
|
158
|
+
#
|
135
159
|
# Parent of this node. Will be +nil+ for a root node.
|
136
160
|
attr_reader :parent
|
137
161
|
|
162
|
+
# @!group Node Creation
|
163
|
+
|
138
164
|
# Creates a new node with a name and optional content.
|
139
165
|
# The node name is expected to be unique within the tree.
|
140
166
|
#
|
141
167
|
# The content can be of any type, and defaults to +nil+.
|
142
168
|
#
|
143
|
-
# @param [Object] name Name of the node.
|
169
|
+
# @param [Object] name Name of the node. Conventional usage is to pass a String
|
170
|
+
# (Integer names may cause *surprises*)
|
144
171
|
# @param [Object] content Content of the node.
|
145
172
|
#
|
146
173
|
# @raise [ArgumentError] Raised if the node name is empty.
|
174
|
+
#
|
175
|
+
# @note If the name is an +Integer+, then the semantics of +TreeNode[]+ can
|
176
|
+
# be surprising, as an +Integer+ parameter to that method normally acts
|
177
|
+
# as an index to the <em>children array</em>, and follows the
|
178
|
+
# <em>zero-based</em> indexing convention.
|
179
|
+
#
|
180
|
+
# @see #[]
|
147
181
|
def initialize(name, content = nil)
|
148
182
|
raise ArgumentError, "Node name HAS to be provided!" if name == nil
|
149
183
|
@name, @content = name, content
|
150
184
|
|
185
|
+
if name.kind_of?(Integer)
|
186
|
+
warn StandardWarning,
|
187
|
+
"Using integer as node name. Semantics of TreeNode[] may not be what you expect! #{name} #{content}"
|
188
|
+
end
|
189
|
+
|
151
190
|
self.set_as_root!
|
152
191
|
@children_hash = Hash.new
|
153
192
|
@children = []
|
@@ -178,6 +217,8 @@ module Tree
|
|
178
217
|
# @see Tree::TreeNode#detached_subtree_copy
|
179
218
|
alias :dup :detached_subtree_copy
|
180
219
|
|
220
|
+
# @!endgroup
|
221
|
+
|
181
222
|
# Returns string representation of the receiver node.
|
182
223
|
# This method is primarily meant for debugging purposes.
|
183
224
|
#
|
@@ -190,7 +231,8 @@ module Tree
|
|
190
231
|
" Total Nodes: #{size()}"
|
191
232
|
end
|
192
233
|
|
193
|
-
#
|
234
|
+
# @!attribute [r] parentage
|
235
|
+
# An array of ancestors of the receiver node in reversed order
|
194
236
|
# (the first element is the immediate parent of the receiver).
|
195
237
|
#
|
196
238
|
# Returns +nil+ if the receiver is a root node.
|
@@ -219,6 +261,8 @@ module Tree
|
|
219
261
|
@parent = parent
|
220
262
|
end
|
221
263
|
|
264
|
+
# @!group Structure Modification
|
265
|
+
|
222
266
|
# Convenience synonym for {Tree::TreeNode#add} method.
|
223
267
|
#
|
224
268
|
# This method allows an easy mechanism to add node hierarchies to the tree
|
@@ -267,7 +311,8 @@ module Tree
|
|
267
311
|
#
|
268
312
|
# @see #<<
|
269
313
|
def add(child, at_index = -1)
|
270
|
-
raise ArgumentError, "Attempting to add a nil node" unless child
|
314
|
+
raise ArgumentError, "Attempting to add a nil node" unless child # Only handles the immediate child scenario
|
315
|
+
raise ArgumentError, "Attempting add node to itself" if self == child
|
271
316
|
raise "Child #{child.name} already added!" if @children_hash.has_key?(child.name)
|
272
317
|
|
273
318
|
if insertion_range.include?(at_index)
|
@@ -281,8 +326,6 @@ module Tree
|
|
281
326
|
return child
|
282
327
|
end
|
283
328
|
|
284
|
-
|
285
|
-
|
286
329
|
# Removes the specified child node from the receiver node.
|
287
330
|
#
|
288
331
|
# This method can also be used for *pruning* a sub-tree, in cases where the removed child node is
|
@@ -346,6 +389,8 @@ module Tree
|
|
346
389
|
@parent = nil
|
347
390
|
end
|
348
391
|
|
392
|
+
# @!endgroup
|
393
|
+
|
349
394
|
# Returns +true+ if the receiver is a root node. Note that
|
350
395
|
# orphaned children will also be reported as root nodes.
|
351
396
|
#
|
@@ -373,10 +418,13 @@ module Tree
|
|
373
418
|
!has_children?
|
374
419
|
end
|
375
420
|
|
376
|
-
#
|
377
|
-
#
|
421
|
+
# @!attribute [rw] children
|
422
|
+
# An array of all the immediate children of the receiver
|
423
|
+
# node. The child nodes are ordered "left-to-right" in the
|
424
|
+
# returned array.
|
378
425
|
#
|
379
|
-
# If a block is given, yields each child node to the block
|
426
|
+
# If a block is given, yields each child node to the block
|
427
|
+
# traversing from left to right.
|
380
428
|
#
|
381
429
|
# @yield [child] Each child is passed to the block, if given
|
382
430
|
# @yieldparam [Tree::TreeNode] child Each child node.
|
@@ -390,24 +438,26 @@ module Tree
|
|
390
438
|
end
|
391
439
|
end
|
392
440
|
|
393
|
-
#
|
394
|
-
#
|
395
|
-
# Will
|
441
|
+
# @!attribute [rw] first_child
|
442
|
+
# First child of the receiver node.
|
443
|
+
# Will be +nil+ if no children are present.
|
396
444
|
#
|
397
445
|
# @return [Tree::TreeNode] The first child, or +nil+ if none is present.
|
398
446
|
def first_child
|
399
447
|
children.first
|
400
448
|
end
|
401
449
|
|
402
|
-
#
|
403
|
-
#
|
404
|
-
# Will
|
450
|
+
# @!attribute [rw] last_child
|
451
|
+
# Last child of the receiver node.
|
452
|
+
# Will be +nil+ if no children are present.
|
405
453
|
#
|
406
454
|
# @return [Tree::TreeNode] The last child, or +nil+ if none is present.
|
407
455
|
def last_child
|
408
456
|
children.last
|
409
457
|
end
|
410
458
|
|
459
|
+
# @!group Tree Traversal
|
460
|
+
|
411
461
|
# Traverses each node (including the receiver node) of the (sub)tree rooted at this node
|
412
462
|
# by yielding the nodes to the specified block.
|
413
463
|
#
|
@@ -467,55 +517,77 @@ module Tree
|
|
467
517
|
# @see #each
|
468
518
|
# @see #breadth_each
|
469
519
|
def each_leaf &block
|
470
|
-
|
520
|
+
if block_given?
|
521
|
+
self.each { |node| yield(node) if node.is_leaf? }
|
522
|
+
else
|
523
|
+
self.select { |node| node.is_leaf?}
|
524
|
+
end
|
471
525
|
end
|
472
526
|
|
473
527
|
# Returns the requested node from the set of immediate children.
|
474
528
|
#
|
475
|
-
# If the argument is
|
476
|
-
# the argument as the
|
529
|
+
# - If the +name+ argument is an _Integer_, then the in-sequence
|
530
|
+
# array of children is accessed using the argument as the
|
531
|
+
# *index* (zero-based). However, if the second _optional_
|
532
|
+
# +num_as_name+ argument is +true+, then the +name+ is used
|
533
|
+
# literally as a name, and *NOT* as an *index*
|
477
534
|
#
|
478
|
-
# If the argument is *NOT*
|
535
|
+
# - If the +name+ argument is *NOT* an _Integer_, then it is taken to
|
536
|
+
# be the *name* of the child node to be returned.
|
479
537
|
#
|
480
|
-
#
|
538
|
+
# If a non-+Integer+ +name+ is passed, and the +num_as_name+
|
539
|
+
# parameter is also +true+, then a warning is thrown (as this is a
|
540
|
+
# redundant use of the +num_as_name+ flag.)
|
481
541
|
#
|
482
|
-
# @param [String|Number] name_or_index Name of the child, or its
|
542
|
+
# @param [String|Number] name_or_index Name of the child, or its
|
543
|
+
# positional index in the array of child nodes.
|
483
544
|
#
|
484
|
-
# @
|
485
|
-
#
|
545
|
+
# @param [Boolean] num_as_name Whether to treat the +Integer+
|
546
|
+
# +name+ argument as an actual name, and *NOT* as an _index_ to
|
547
|
+
# the children array.
|
486
548
|
#
|
487
|
-
# @
|
549
|
+
# @return [Tree::TreeNode] the requested child node. If the index
|
550
|
+
# in not in range, or the name is not present, then a +nil+
|
551
|
+
# is returned.
|
552
|
+
#
|
553
|
+
# @note The use of +Integer+ names is allowed by using the optional +num_as_name+ flag.
|
554
|
+
#
|
555
|
+
# @raise [ArgumentError] Raised if the +name_or_index+ argument is +nil+.
|
488
556
|
#
|
489
557
|
# @see #add
|
490
|
-
|
558
|
+
# @see #initialize
|
559
|
+
def [](name_or_index, num_as_name=false)
|
491
560
|
raise ArgumentError, "Name_or_index needs to be provided!" if name_or_index == nil
|
492
561
|
|
493
|
-
if name_or_index.kind_of?(Integer)
|
562
|
+
if name_or_index.kind_of?(Integer) and not num_as_name
|
494
563
|
@children[name_or_index]
|
495
564
|
else
|
565
|
+
if num_as_name and not name_or_index.kind_of?(Integer)
|
566
|
+
warn StandardWarning, "Redundant use of the `num_as_name` flag for non-integer node name"
|
567
|
+
end
|
496
568
|
@children_hash[name_or_index]
|
497
569
|
end
|
498
570
|
end
|
499
571
|
|
500
|
-
#
|
572
|
+
# @!endgroup
|
573
|
+
|
574
|
+
# @!attribute [r] size
|
575
|
+
# Total number of nodes in this (sub)tree, including the receiver node.
|
501
576
|
#
|
502
577
|
# Size of the tree is defined as:
|
503
578
|
#
|
504
579
|
# Size:: Total number nodes in the subtree including the receiver node.
|
505
580
|
#
|
506
|
-
# @return [
|
581
|
+
# @return [Integer] Total number of nodes in this (sub)tree.
|
507
582
|
def size
|
508
583
|
@children.inject(1) {|sum, node| sum + node.size}
|
509
584
|
end
|
510
585
|
|
511
586
|
# Convenience synonym for {Tree::TreeNode#size}.
|
512
587
|
#
|
513
|
-
# @todo The semantic of length is probably unclear. Should return the node depth instead
|
514
|
-
# to reflect the path length.
|
515
|
-
#
|
516
588
|
# @deprecated This method name is ambiguous and may be removed. Use TreeNode#size instead.
|
517
589
|
#
|
518
|
-
# @return [
|
590
|
+
# @return [Integer] The total number of nodes in this (sub)tree.
|
519
591
|
# @see #size
|
520
592
|
def length
|
521
593
|
size()
|
@@ -523,7 +595,7 @@ module Tree
|
|
523
595
|
|
524
596
|
# Pretty prints the (sub)tree rooted at the receiver node.
|
525
597
|
#
|
526
|
-
# @param [
|
598
|
+
# @param [Integer] level The indentation level (4 spaces) to start with.
|
527
599
|
def print_tree(level = 0)
|
528
600
|
if is_root?
|
529
601
|
print "*"
|
@@ -540,11 +612,9 @@ module Tree
|
|
540
612
|
children { |child| child.print_tree(level + 1)}
|
541
613
|
end
|
542
614
|
|
543
|
-
#
|
544
|
-
#
|
545
|
-
#
|
546
|
-
#
|
547
|
-
# @todo We should perhaps return nil as root's root.
|
615
|
+
# @!attribute [rw] root
|
616
|
+
# root node for the (sub)tree to which the receiver node belongs.
|
617
|
+
# A root node's root is itself.
|
548
618
|
#
|
549
619
|
# @return [Tree::TreeNode] Root of the (sub)tree.
|
550
620
|
def root
|
@@ -553,15 +623,13 @@ module Tree
|
|
553
623
|
root
|
554
624
|
end
|
555
625
|
|
556
|
-
#
|
626
|
+
# @!attribute [rw] first_sibling
|
627
|
+
# First sibling of the receiver node. If this is the root node, then returns
|
557
628
|
# itself.
|
558
629
|
#
|
559
630
|
# 'First' sibling is defined as follows:
|
560
631
|
# First sibling:: The left-most child of the receiver's parent, which may be the receiver itself
|
561
632
|
#
|
562
|
-
# @todo Fix the inconsistency of returning root as its first sibling, and returning
|
563
|
-
# a +nil+ array for siblings of the node.
|
564
|
-
#
|
565
633
|
# @return [Tree::TreeNode] The first sibling node.
|
566
634
|
#
|
567
635
|
# @see #is_first_sibling?
|
@@ -580,15 +648,13 @@ module Tree
|
|
580
648
|
first_sibling == self
|
581
649
|
end
|
582
650
|
|
583
|
-
#
|
651
|
+
# @!attribute [rw] last_sibling
|
652
|
+
# Last sibling of the receiver node. If this is the root node, then returns
|
584
653
|
# itself.
|
585
654
|
#
|
586
655
|
# 'Last' sibling is defined as follows:
|
587
656
|
# Last sibling:: The right-most child of the receiver's parent, which may be the receiver itself
|
588
657
|
#
|
589
|
-
# @todo Fix the inconsistency of returning root as its last sibling, and returning
|
590
|
-
# a +nil+ array for siblings of the node.
|
591
|
-
#
|
592
658
|
# @return [Tree::TreeNode] The last sibling node.
|
593
659
|
#
|
594
660
|
# @see #is_last_sibling?
|
@@ -607,16 +673,12 @@ module Tree
|
|
607
673
|
last_sibling == self
|
608
674
|
end
|
609
675
|
|
610
|
-
#
|
676
|
+
# @!attribute [rw] siblings
|
677
|
+
# An array of siblings for the receiver node. The receiver node is excluded.
|
611
678
|
#
|
612
679
|
# If a block is provided, yields each of the sibling nodes to the block.
|
613
680
|
# The root always has +nil+ siblings.
|
614
681
|
#
|
615
|
-
# @todo Fix the inconsistency of returning root as its own first/last sibling, and returning
|
616
|
-
# a +nil+ array for siblings of the same root node.
|
617
|
-
# @todo Also fix the inconsistency of returning +nil+ for a root node, and an empty array for nodes
|
618
|
-
# which have no siblings.
|
619
|
-
#
|
620
682
|
# @yield [sibling] Each sibling is passed to the block.
|
621
683
|
# @yieldparam [Tree::TreeNode] sibling Each sibling node.
|
622
684
|
#
|
@@ -625,7 +687,7 @@ module Tree
|
|
625
687
|
# @see #first_sibling
|
626
688
|
# @see #last_sibling
|
627
689
|
def siblings
|
628
|
-
return
|
690
|
+
return [] if is_root?
|
629
691
|
|
630
692
|
if block_given?
|
631
693
|
parent.children.each { |sibling| yield sibling if sibling != self }
|
@@ -647,7 +709,8 @@ module Tree
|
|
647
709
|
is_root? ? true : parent.children.size == 1
|
648
710
|
end
|
649
711
|
|
650
|
-
#
|
712
|
+
# @!attribute [rw] next_sibling
|
713
|
+
# Next sibling for the receiver node.
|
651
714
|
# The 'next' node is defined as the node to right of the receiver node.
|
652
715
|
#
|
653
716
|
# Will return +nil+ if no subsequent node is present, or if the receiver is a root node.
|
@@ -663,7 +726,8 @@ module Tree
|
|
663
726
|
parent.children.at(myidx + 1) if myidx
|
664
727
|
end
|
665
728
|
|
666
|
-
#
|
729
|
+
# @!attribute [rw] previous_sibling
|
730
|
+
# Previous sibling of the receiver node.
|
667
731
|
# 'Previous' node is defined to be the node to left of the receiver node.
|
668
732
|
#
|
669
733
|
# Will return +nil+ if no predecessor node is present, or if the receiver is a root node.
|
@@ -685,7 +749,7 @@ module Tree
|
|
685
749
|
#
|
686
750
|
# @param [Tree::TreeNode] other The other node to compare against.
|
687
751
|
#
|
688
|
-
# @return [
|
752
|
+
# @return [Integer] +1 if this node is a 'successor', 0 if equal and -1 if this node is a 'predecessor'.
|
689
753
|
def <=>(other)
|
690
754
|
return +1 if other == nil
|
691
755
|
self.name <=> other.name
|
@@ -735,19 +799,18 @@ module Tree
|
|
735
799
|
end
|
736
800
|
end
|
737
801
|
|
738
|
-
# Creates a JSON
|
739
|
-
# available, or else the operation fails with a warning message.
|
802
|
+
# Creates a JSON ready Hash for the #to_json method.
|
740
803
|
#
|
741
|
-
# @author
|
742
|
-
# @since 0.
|
804
|
+
# @author Eric Cline (https://github.com/escline)
|
805
|
+
# @since 0.8.3
|
743
806
|
#
|
744
|
-
# @return
|
807
|
+
# @return A hash based representation of the JSON
|
745
808
|
#
|
746
|
-
#
|
747
|
-
#
|
748
|
-
|
749
|
-
|
750
|
-
|
809
|
+
# Rails uses JSON in ActiveSupport, and all Rails JSON encoding goes through as_json
|
810
|
+
#
|
811
|
+
# @see Tree::TreeNode.to_json
|
812
|
+
# @see http://stackoverflow.com/a/6880638/273808
|
813
|
+
def as_json(options = {})
|
751
814
|
|
752
815
|
json_hash = {
|
753
816
|
"name" => name,
|
@@ -759,11 +822,24 @@ module Tree
|
|
759
822
|
json_hash["children"] = children
|
760
823
|
end
|
761
824
|
|
762
|
-
return json_hash
|
825
|
+
return json_hash
|
763
826
|
|
764
|
-
|
765
|
-
|
766
|
-
|
827
|
+
end
|
828
|
+
|
829
|
+
# Creates a JSON representation of this node including all it's children. This requires the JSON gem to be
|
830
|
+
# available, or else the operation fails with a warning message.
|
831
|
+
# Uses the Hash output of as_json method, defined above.
|
832
|
+
#
|
833
|
+
# @author Dirk Breuer (http://github.com/railsbros-dirk)
|
834
|
+
# @since 0.7.0
|
835
|
+
#
|
836
|
+
# @return The JSON representation of this subtree.
|
837
|
+
#
|
838
|
+
# @see Tree::TreeNode.json_create
|
839
|
+
# @see Tree::TreeNode.as_json
|
840
|
+
# @see http://flori.github.com/json
|
841
|
+
def to_json(*a)
|
842
|
+
as_json.to_json(*a)
|
767
843
|
end
|
768
844
|
|
769
845
|
# Helper method to create a Tree::TreeNode instance from the JSON hash representation. Note that this method should
|
@@ -783,35 +859,33 @@ module Tree
|
|
783
859
|
# @see #to_json
|
784
860
|
# @see http://flori.github.com/json
|
785
861
|
def self.json_create(json_hash)
|
786
|
-
begin
|
787
|
-
require 'json'
|
788
862
|
|
789
|
-
|
863
|
+
node = new(json_hash["name"], json_hash["content"])
|
790
864
|
|
791
|
-
|
792
|
-
|
793
|
-
|
865
|
+
json_hash["children"].each do |child|
|
866
|
+
node << child
|
867
|
+
end if json_hash["children"]
|
868
|
+
|
869
|
+
return node
|
794
870
|
|
795
|
-
return node
|
796
|
-
rescue LoadError => e
|
797
|
-
warn "The JSON gem couldn't be loaded. Due to this we cannot serialize the tree to a JSON representation."
|
798
|
-
end
|
799
871
|
end
|
800
872
|
|
801
|
-
#
|
873
|
+
# @!attribute [r] node_height
|
874
|
+
# Height of the (sub)tree from the receiver node. Height of a node is defined as:
|
802
875
|
#
|
803
876
|
# Height:: Length of the longest downward path to a leaf from the node.
|
804
877
|
#
|
805
878
|
# - Height from a root node is height of the entire tree.
|
806
879
|
# - The height of a leaf node is zero.
|
807
880
|
#
|
808
|
-
# @return [
|
881
|
+
# @return [Integer] Height of the node.
|
809
882
|
def node_height
|
810
883
|
return 0 if is_leaf?
|
811
884
|
1 + @children.collect { |child| child.node_height }.max
|
812
885
|
end
|
813
886
|
|
814
|
-
#
|
887
|
+
# @!attribute [r] node_depth
|
888
|
+
# Depth of the receiver node in its tree. Depth of a node is defined as:
|
815
889
|
#
|
816
890
|
# Depth:: Length of the node's path to its root. Depth of a root node is zero.
|
817
891
|
#
|
@@ -820,7 +894,7 @@ module Tree
|
|
820
894
|
#
|
821
895
|
# 'level' is an alias for this method.
|
822
896
|
#
|
823
|
-
# @return [
|
897
|
+
# @return [Integer] Depth of this node.
|
824
898
|
def node_depth
|
825
899
|
return 0 if is_root?
|
826
900
|
1 + parent.node_depth
|
@@ -838,74 +912,62 @@ module Tree
|
|
838
912
|
# For correct and conventional behavior, please use {Tree::TreeNode#node_depth} and
|
839
913
|
# {Tree::TreeNode#node_height} methods instead.
|
840
914
|
#
|
841
|
-
# @return [
|
915
|
+
# @return [Integer] depth of the node.
|
842
916
|
# @deprecated This method returns an incorrect value. Use the 'node_depth' method instead.
|
843
917
|
#
|
844
918
|
# @see #node_depth
|
845
919
|
def depth
|
846
|
-
|
847
|
-
require 'structured_warnings' # To enable a nice way of deprecating of the depth method.
|
848
|
-
warn DeprecatedMethodWarning, 'This method is deprecated. Please use node_depth() or node_height() instead (bug # 22535)'
|
849
|
-
rescue LoadError
|
850
|
-
# Oh well. Will use the standard Kernel#warn. Behavior will be identical.
|
851
|
-
warn 'Tree::TreeNode#depth() method is deprecated. Please use node_depth() or node_height() instead (bug # 22535)'
|
852
|
-
end
|
920
|
+
warn DeprecatedMethodWarning, 'This method is deprecated. Please use node_depth() or node_height() instead (bug # 22535)'
|
853
921
|
|
854
922
|
return 1 if is_leaf?
|
855
923
|
1 + @children.collect { |child| child.depth }.max
|
856
924
|
end
|
857
925
|
|
858
926
|
# Allow the deprecated CamelCase method names. Display a warning.
|
927
|
+
# :nodoc:
|
859
928
|
def method_missing(meth, *args, &blk)
|
860
929
|
if self.respond_to?(new_method_name = underscore(meth))
|
861
|
-
|
862
|
-
|
863
|
-
warn DeprecatedMethodWarning, "The camelCased methods are deprecated. Please use #{new_method_name} instead of #{meth}"
|
864
|
-
|
865
|
-
rescue LoadError
|
866
|
-
# Oh well. Will use the standard Kernel#warn. Behavior will be identical.
|
867
|
-
warn "Tree::TreeNode##{meth}() method is deprecated. Please use #{new_method_name} instead."
|
868
|
-
|
869
|
-
ensure # Invoke the method now.
|
870
|
-
return send(new_method_name, *args, &blk)
|
871
|
-
end
|
872
|
-
|
930
|
+
warn DeprecatedMethodWarning, "The camelCased methods are deprecated. Please use #{new_method_name} instead of #{meth}"
|
931
|
+
return send(new_method_name, *args, &blk)
|
873
932
|
else
|
874
933
|
super
|
875
934
|
end
|
876
935
|
end
|
877
936
|
|
878
|
-
#
|
937
|
+
# @!attribute [r] breadth
|
938
|
+
# Breadth of the tree at the receiver node's level.
|
879
939
|
# A single node without siblings has a breadth of 1.
|
880
940
|
#
|
881
941
|
# Breadth is defined to be:
|
882
942
|
# Breadth:: Number of sibling nodes to this node + 1 (this node itself),
|
883
943
|
# i.e., the number of children the parent of this node has.
|
884
944
|
#
|
885
|
-
# @return [
|
945
|
+
# @return [Integer] breadth of the node's level.
|
886
946
|
def breadth
|
887
947
|
is_root? ? 1 : parent.children.size
|
888
948
|
end
|
889
949
|
|
890
|
-
#
|
950
|
+
# @!attribute [r] in_degree
|
951
|
+
# The incoming edge-count of the receiver node.
|
891
952
|
#
|
892
953
|
# In-degree is defined as:
|
893
|
-
# In-degree::
|
954
|
+
# In-degree:: Number of edges arriving at the node (0 for root, 1 for all other nodes)
|
894
955
|
#
|
895
956
|
# - In-degree = 0 for a root or orphaned node
|
896
957
|
# - In-degree = 1 for a node which has a parent
|
897
958
|
#
|
898
|
-
# @return [
|
959
|
+
# @return [Integer] The in-degree of this node.
|
899
960
|
def in_degree
|
900
961
|
is_root? ? 0 : 1
|
901
962
|
end
|
902
963
|
|
903
|
-
#
|
964
|
+
# @!attribute [r] out_degree
|
965
|
+
# The outgoing edge-count of the receiver node.
|
904
966
|
#
|
905
967
|
# Out-degree is defined as:
|
906
|
-
# Out-degree::
|
968
|
+
# Out-degree:: Number of edges leaving the node (zero for leafs)
|
907
969
|
#
|
908
|
-
# @return [
|
970
|
+
# @return [Integer] The out-degree of this node.
|
909
971
|
def out_degree
|
910
972
|
is_leaf? ? 0 : children.size
|
911
973
|
end
|