rooted_tree 0.2.3 → 0.3.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 +4 -4
- data/README.md +1 -1
- data/lib/rooted_tree/node.rb +69 -95
- data/lib/rooted_tree/tree.rb +25 -17
- data/lib/rooted_tree/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dfa5843433eb9461adb4ab0e2698e0429d994263
|
4
|
+
data.tar.gz: ef4f2f8a52ee1aa796e435cb767ab96dc7b563b7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cd771695cade59e40219f65827246e54534158e3d5612e8555c829b4293dafb01f2a60805cb2c36af6a8a80c1c70f5b96f7c2a616cb8af02cb568acb23e68f9e
|
7
|
+
data.tar.gz: d29de94468510ee7f2a52c2658a08e6ee8a8973d61cc1f3c6cc819f8f3751768d99fcaaae0315bc49ffe76dbcfe4b1a1e1ff41c138c798399ba0543e9f856252
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# RootedTree
|
2
2
|
|
3
|
-
[](http://badge.fury.io/rb/rooted_tree)
|
4
4
|
[](https://travis-ci.org/seblindberg/ruby-rooted_tree)
|
5
5
|
[](https://coveralls.io/github/seblindberg/ruby-rooted_tree?branch=master)
|
6
6
|
[](http://inch-ci.org/github/seblindberg/ruby-rooted_tree)
|
data/lib/rooted_tree/node.rb
CHANGED
@@ -61,16 +61,12 @@ module RootedTree
|
|
61
61
|
super
|
62
62
|
end
|
63
63
|
|
64
|
-
#
|
65
|
-
#
|
66
|
-
# A node is a leaf if it has no children.
|
64
|
+
# Returns true if this node is a leaf. A leaf is a node with no children.
|
67
65
|
|
68
66
|
def leaf?
|
69
67
|
@degree == 0
|
70
68
|
end
|
71
69
|
|
72
|
-
# Internal?
|
73
|
-
#
|
74
70
|
# Returns true if the node is internal, which is equivalent to it having
|
75
71
|
# children.
|
76
72
|
|
@@ -78,17 +74,13 @@ module RootedTree
|
|
78
74
|
!leaf?
|
79
75
|
end
|
80
76
|
|
81
|
-
#
|
82
|
-
#
|
83
|
-
# Returns true if node has no parent.
|
77
|
+
# Returns true if the node has no parent.
|
84
78
|
|
85
79
|
def root?
|
86
80
|
@parent.nil?
|
87
81
|
end
|
88
82
|
|
89
|
-
#
|
90
|
-
#
|
91
|
-
# Returns the root of the tree.
|
83
|
+
# Returns the root of the tree structure that the node is part of.
|
92
84
|
|
93
85
|
def root
|
94
86
|
return self if root?
|
@@ -98,24 +90,18 @@ module RootedTree
|
|
98
90
|
node
|
99
91
|
end
|
100
92
|
|
101
|
-
# First?
|
102
|
-
#
|
103
93
|
# Returns true if this node is the first of its siblings.
|
104
94
|
|
105
95
|
def first?
|
106
96
|
@prev.nil?
|
107
97
|
end
|
108
98
|
|
109
|
-
# Last?
|
110
|
-
#
|
111
99
|
# Returns true if this node is the last of its siblings.
|
112
100
|
|
113
101
|
def last?
|
114
102
|
@next.nil?
|
115
103
|
end
|
116
104
|
|
117
|
-
# Depth
|
118
|
-
#
|
119
105
|
# Returns the depth of the node within the tree
|
120
106
|
|
121
107
|
def depth
|
@@ -124,8 +110,6 @@ module RootedTree
|
|
124
110
|
|
125
111
|
alias level depth
|
126
112
|
|
127
|
-
# Max Depth
|
128
|
-
#
|
129
113
|
# Returns the maximum node depth under this node.
|
130
114
|
|
131
115
|
def max_depth(offset = depth)
|
@@ -134,36 +118,34 @@ module RootedTree
|
|
134
118
|
children.map { |c| c.max_depth offset + 1 }.max
|
135
119
|
end
|
136
120
|
|
137
|
-
# Max Degree
|
138
|
-
#
|
139
121
|
# Returns the highest child count of the nodes in the subtree.
|
140
122
|
|
141
123
|
def max_degree
|
142
124
|
children.map(&:degree).push(degree).max
|
143
125
|
end
|
144
126
|
|
145
|
-
# Size
|
146
|
-
#
|
147
127
|
# Calculate the size in vertecies of the subtree.
|
128
|
+
#
|
129
|
+
# Returns the number of nodes under this node, including self.
|
148
130
|
|
149
131
|
def size
|
150
132
|
children.reduce(1) { |a, e| a + e.size }
|
151
133
|
end
|
152
134
|
|
153
|
-
# Next
|
154
|
-
#
|
155
135
|
# Access the next sibling. Raises a StopIteration if this node is the last
|
156
136
|
# one.
|
137
|
+
#
|
138
|
+
# Returns the previous sibling node.
|
157
139
|
|
158
140
|
def next
|
159
141
|
raise StopIteration if last?
|
160
142
|
@next
|
161
143
|
end
|
162
144
|
|
163
|
-
# Prev(ious)
|
164
|
-
#
|
165
145
|
# Access the previous sibling. Raises a StopIteration if this node is the
|
166
146
|
# first one.
|
147
|
+
#
|
148
|
+
# Returns the previous sibling node.
|
167
149
|
|
168
150
|
def prev
|
169
151
|
raise StopIteration if first?
|
@@ -172,19 +154,19 @@ module RootedTree
|
|
172
154
|
|
173
155
|
alias previous prev
|
174
156
|
|
175
|
-
# Parent
|
176
|
-
#
|
177
157
|
# Access the parent node. Raises a StopIteration if this node is the
|
178
158
|
# root.
|
159
|
+
#
|
160
|
+
# Returns the parent node.
|
179
161
|
|
180
162
|
def parent
|
181
163
|
raise StopIteration if root?
|
182
164
|
@parent
|
183
165
|
end
|
184
166
|
|
185
|
-
# Append Sibling
|
186
|
-
#
|
187
167
|
# Insert a child between this node and the one after it.
|
168
|
+
#
|
169
|
+
# Returns self.
|
188
170
|
|
189
171
|
def append_sibling(value = nil)
|
190
172
|
raise StructureException, 'Root node can not have siblings' if root?
|
@@ -203,9 +185,9 @@ module RootedTree
|
|
203
185
|
@next = node
|
204
186
|
end
|
205
187
|
|
206
|
-
# Prepend Sibling
|
207
|
-
#
|
208
188
|
# Insert a child between this node and the one before it.
|
189
|
+
#
|
190
|
+
# Returns self.
|
209
191
|
|
210
192
|
def prepend_sibling(value = nil)
|
211
193
|
raise StructureException, 'Root node can not have siblings' if root?
|
@@ -232,9 +214,9 @@ module RootedTree
|
|
232
214
|
node.parent = self
|
233
215
|
end
|
234
216
|
|
235
|
-
# Append Child
|
236
|
-
#
|
237
217
|
# Insert a child after the last one.
|
218
|
+
#
|
219
|
+
# Returns self.
|
238
220
|
|
239
221
|
def append_child(value = nil)
|
240
222
|
if leaf?
|
@@ -247,9 +229,9 @@ module RootedTree
|
|
247
229
|
|
248
230
|
alias << append_child
|
249
231
|
|
250
|
-
# Prepend Child
|
251
|
-
#
|
252
232
|
# Insert a child before the first one.
|
233
|
+
#
|
234
|
+
# Returns self.
|
253
235
|
|
254
236
|
def prepend_child(value = nil)
|
255
237
|
if leaf?
|
@@ -259,9 +241,9 @@ module RootedTree
|
|
259
241
|
end
|
260
242
|
end
|
261
243
|
|
262
|
-
# Extract
|
263
|
-
#
|
264
244
|
# Extracts the node and its subtree from the larger structure.
|
245
|
+
#
|
246
|
+
# Returns self, now made root.
|
265
247
|
|
266
248
|
def extract
|
267
249
|
return self if root?
|
@@ -283,9 +265,9 @@ module RootedTree
|
|
283
265
|
self
|
284
266
|
end
|
285
267
|
|
286
|
-
# Delete
|
287
|
-
#
|
288
268
|
# Removes the node from the tree.
|
269
|
+
#
|
270
|
+
# Returns an array of the children to the deleted node, now made roots.
|
289
271
|
|
290
272
|
def delete
|
291
273
|
extract.children.map do |child|
|
@@ -294,12 +276,11 @@ module RootedTree
|
|
294
276
|
end
|
295
277
|
end
|
296
278
|
|
297
|
-
#
|
279
|
+
# Iterates over the nodes above this in the tree hierarchy and yields them
|
280
|
+
# to a block. If no block is given an enumerator is returned.
|
298
281
|
#
|
299
282
|
# Returns an enumerator that will iterate over the parents of this node
|
300
283
|
# until the root is reached.
|
301
|
-
#
|
302
|
-
# If a block is given it will be yielded to.
|
303
284
|
|
304
285
|
def ancestors
|
305
286
|
return to_enum(__callee__) unless block_given?
|
@@ -310,14 +291,14 @@ module RootedTree
|
|
310
291
|
end
|
311
292
|
end
|
312
293
|
|
313
|
-
#
|
314
|
-
#
|
315
|
-
#
|
316
|
-
# but by passing rtl: true the order can be reversed. If a block is not
|
317
|
-
# given an enumerator is returned.
|
294
|
+
# Yields each of the node children. The default order is left-to-right, but
|
295
|
+
# by passing rtl: true the order is reversed. If a block is not given an
|
296
|
+
# enumerator is returned.
|
318
297
|
#
|
319
298
|
# Note that the block will catch any StopIteration that is raised and
|
320
299
|
# terminate early, returning the value of the exception.
|
300
|
+
#
|
301
|
+
# rtl - reverses the iteration order if true.
|
321
302
|
|
322
303
|
def children(rtl: false)
|
323
304
|
return to_enum(__callee__, rtl: rtl) unless block_given?
|
@@ -335,9 +316,14 @@ module RootedTree
|
|
335
316
|
end
|
336
317
|
end
|
337
318
|
|
338
|
-
#
|
319
|
+
# Accessor method for any of the n children under this node. If called
|
320
|
+
# without an argument and the node has anything but exactly one child an
|
321
|
+
# exception will be raised.
|
339
322
|
#
|
340
|
-
#
|
323
|
+
# n - the n:th child to be returned. If n is negative the indexing will be
|
324
|
+
# reversed and the children counted from the last to the first.
|
325
|
+
#
|
326
|
+
# Returns the child at the n:th index.
|
341
327
|
|
342
328
|
def child(n = nil)
|
343
329
|
if n.nil?
|
@@ -362,8 +348,6 @@ module RootedTree
|
|
362
348
|
end
|
363
349
|
end
|
364
350
|
|
365
|
-
# Each
|
366
|
-
#
|
367
351
|
# Yields first to self and then to each child. If a block is not given an
|
368
352
|
# enumerator is returned.
|
369
353
|
|
@@ -373,9 +357,31 @@ module RootedTree
|
|
373
357
|
children { |v| v.each(&block) }
|
374
358
|
end
|
375
359
|
|
376
|
-
#
|
360
|
+
# Converts the tree structure to a nested array of the nodes. Each internal
|
361
|
+
# node is placed at index zero of its own array, followed by an array of its
|
362
|
+
# children. Leaf nodes are not wraped in arrays but inserted directly.
|
377
363
|
#
|
364
|
+
# flatten - flattens the array if true.
|
365
|
+
#
|
366
|
+
# Example
|
367
|
+
#
|
368
|
+
# r
|
369
|
+
# / \
|
370
|
+
# a b => [r, [[a, [c]], b]]
|
371
|
+
# |
|
372
|
+
# c
|
373
|
+
#
|
374
|
+
# Returns a nested array of nodes.
|
375
|
+
|
376
|
+
def to_a flatten: false
|
377
|
+
return super() if flatten
|
378
|
+
return self if leaf?
|
379
|
+
[self, children.map(&:to_a)]
|
380
|
+
end
|
381
|
+
|
378
382
|
# Iterates over each of the leafs.
|
383
|
+
#
|
384
|
+
# rtl - if true the iteration order is switched to right to left.
|
379
385
|
|
380
386
|
def leafs(rtl: false, &block)
|
381
387
|
return to_enum(__callee__, rtl: rtl) unless block_given?
|
@@ -383,9 +389,10 @@ module RootedTree
|
|
383
389
|
children(rtl: rtl) { |v| v.leafs(rtl: rtl, &block) }
|
384
390
|
end
|
385
391
|
|
386
|
-
#
|
392
|
+
# Iterates over each of the edges and yields the parent and the child. If no
|
393
|
+
# block is given an enumerator is returned.
|
387
394
|
#
|
388
|
-
#
|
395
|
+
# block - an optional block that will be yielded to, if given.
|
389
396
|
|
390
397
|
def edges(&block)
|
391
398
|
return to_enum(__callee__) unless block_given?
|
@@ -396,11 +403,13 @@ module RootedTree
|
|
396
403
|
end
|
397
404
|
end
|
398
405
|
|
399
|
-
# Add
|
400
|
-
#
|
401
406
|
# Add two roots together to create a larger tree. A new common root will be
|
402
407
|
# created and returned. Note that if the any of the root nodes are not
|
403
408
|
# frozen they will be modified, and as a result seize to be roots.
|
409
|
+
#
|
410
|
+
# other - a Node-like object that responds true to #root?
|
411
|
+
#
|
412
|
+
# Returns a new root with the two nodes as children.
|
404
413
|
|
405
414
|
def +(other)
|
406
415
|
unless root? && other.root?
|
@@ -414,53 +423,18 @@ module RootedTree
|
|
414
423
|
ab << a << b
|
415
424
|
end
|
416
425
|
|
417
|
-
#
|
426
|
+
# Compare one node (sub)structure with another.
|
418
427
|
#
|
419
428
|
# Returns true if the two vertecies form identical subtrees
|
420
429
|
|
421
430
|
def ==(other)
|
422
431
|
return false unless other.is_a? self.class
|
423
432
|
return false unless degree == other.degree
|
433
|
+
return false unless value == other.value
|
424
434
|
|
425
435
|
children.to_a == other.children.to_a
|
426
436
|
end
|
427
437
|
|
428
|
-
# Tree!
|
429
|
-
#
|
430
|
-
# Wraps the entire tree in a Tree object. The operation will freeze the node
|
431
|
-
# structure, making it immutable. If this node is a child the root will be
|
432
|
-
# found and passed to Tree.new.
|
433
|
-
|
434
|
-
def tree!
|
435
|
-
Tree.new root
|
436
|
-
end
|
437
|
-
|
438
|
-
# Tree
|
439
|
-
#
|
440
|
-
# Duplicates the entire tree and calls #tree! on the copy.
|
441
|
-
|
442
|
-
def tree
|
443
|
-
root.dup.tree!
|
444
|
-
end
|
445
|
-
|
446
|
-
# Subtree!
|
447
|
-
#
|
448
|
-
# Extracts this node from the larger tree and wraps it in a Tree object.
|
449
|
-
|
450
|
-
def subtree!
|
451
|
-
Tree.new extract
|
452
|
-
end
|
453
|
-
|
454
|
-
# Subtree
|
455
|
-
#
|
456
|
-
# Duplicates this node and its descendants and wraps them in a Tree object.
|
457
|
-
|
458
|
-
def subtree
|
459
|
-
Tree.new dup
|
460
|
-
end
|
461
|
-
|
462
|
-
# Inspect
|
463
|
-
#
|
464
438
|
# Visalizes the tree structure in a style very similar to the cli tool tree.
|
465
439
|
# An example of the output can be seen below. Note that the output string
|
466
440
|
# contains unicode characters.
|
data/lib/rooted_tree/tree.rb
CHANGED
@@ -1,32 +1,40 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module RootedTree
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
def initialize(node)
|
8
|
-
@root = node.root
|
9
|
-
@root.freeze
|
10
|
-
end
|
11
|
-
|
12
|
-
def tree
|
13
|
-
self
|
14
|
-
end
|
15
|
-
|
16
|
-
# Degree
|
17
|
-
#
|
18
|
-
# Returns the maximum degree (number of children) in the tree.
|
4
|
+
module Tree
|
5
|
+
# Returns the maximum degree (highest number of children) in the tree.
|
19
6
|
|
20
7
|
def degree
|
21
8
|
@degree ||= root.max_degree
|
22
9
|
end
|
23
10
|
|
24
|
-
# Depth
|
25
|
-
#
|
26
11
|
# Returns the maximum depth of the tree.
|
27
12
|
|
28
13
|
def depth
|
29
14
|
@depth ||= root.max_depth
|
30
15
|
end
|
16
|
+
|
17
|
+
# Iterates over each node in the tree. When given a block it will be yielded
|
18
|
+
# to once for each node. If no block is given an enumerator is returned.
|
19
|
+
|
20
|
+
def each_node(&block)
|
21
|
+
@root.each(&block)
|
22
|
+
end
|
23
|
+
|
24
|
+
# Iterates over each leaf in the tree. When given a block it will be yielded
|
25
|
+
# to once for leaf node. If no block is given an enumerator is returned.
|
26
|
+
|
27
|
+
def each_leaf(&block)
|
28
|
+
@root.leafs(&block)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Iterates over each edge in the tree. An edge is composed of the parent
|
32
|
+
# node and the child, always in that order. When given a block it will be
|
33
|
+
# yielded to once for each node. If no block is given an enumerator is
|
34
|
+
# returned.
|
35
|
+
|
36
|
+
def each_edge(&block)
|
37
|
+
@root.edges(&block)
|
38
|
+
end
|
31
39
|
end
|
32
40
|
end
|
data/lib/rooted_tree/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rooted_tree
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sebastian Lindberg
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-07-
|
11
|
+
date: 2016-07-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|