rooted_tree 0.3.3 → 0.3.4
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/.gitignore +0 -1
- data/.rubocop.yml +65 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +54 -0
- data/README.md +3 -5
- data/Rakefile +19 -5
- data/bin/console +4 -3
- data/examples/filesystem_tree.rb +5 -7
- data/lib/rooted_tree/mutable.rb +69 -0
- data/lib/rooted_tree/node.rb +102 -365
- data/lib/rooted_tree/tree.rb +11 -29
- data/lib/rooted_tree/version.rb +2 -1
- data/lib/rooted_tree.rb +7 -0
- data/rooted_tree.gemspec +28 -16
- metadata +70 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4500aef4d9f3aaa7483ec8908d63c594d2b1f8c9
|
4
|
+
data.tar.gz: c45b17013a6aa680e023a86e8b927841d22259b8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 88bbe928aa3515c11a0c11d150c17286ca38e4bf4e69331eb1c4e4847743262978fd59ce4e1d126f898ab252fe6214ee7b21cf93be94666e6aa563f53ad5c03f
|
7
|
+
data.tar.gz: 568e6025fb468c1f7477a6425c140e506564ba4b84500f92fce9dd8fb174f77cdaae98f5d725b5f12a07ccaee359392a01bb0f339a9db6fb5fb725c6c175604d
|
data/.gitignore
CHANGED
data/.rubocop.yml
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
AllCops:
|
2
|
+
Exclude:
|
3
|
+
- 'vendor/**/*'
|
4
|
+
- 'tmp/**/*'
|
5
|
+
TargetRubyVersion: 2.4
|
6
|
+
|
7
|
+
Style/FrozenStringLiteralComment:
|
8
|
+
EnforcedStyle: always
|
9
|
+
|
10
|
+
Layout/EndOfLine:
|
11
|
+
EnforcedStyle: lf
|
12
|
+
|
13
|
+
Layout/ClassStructure:
|
14
|
+
Enabled: true
|
15
|
+
Categories:
|
16
|
+
module_inclusion:
|
17
|
+
- include
|
18
|
+
- prepend
|
19
|
+
- extend
|
20
|
+
ExpectedOrder:
|
21
|
+
- module_inclusion
|
22
|
+
- constants
|
23
|
+
- public_class_methods
|
24
|
+
- initializer
|
25
|
+
- instance_methods
|
26
|
+
- protected_methods
|
27
|
+
- private_methods
|
28
|
+
|
29
|
+
Layout/IndentHeredoc:
|
30
|
+
EnforcedStyle: squiggly
|
31
|
+
|
32
|
+
Lint/AmbiguousBlockAssociation:
|
33
|
+
Exclude:
|
34
|
+
- 'test/**/*.rb'
|
35
|
+
|
36
|
+
Lint/InterpolationCheck:
|
37
|
+
Exclude:
|
38
|
+
- 'test/**/*.rb'
|
39
|
+
|
40
|
+
Metrics/BlockLength:
|
41
|
+
Exclude:
|
42
|
+
- 'Rakefile'
|
43
|
+
- '**/*.rake'
|
44
|
+
- 'test/**/*.rb'
|
45
|
+
- '*.gemspec'
|
46
|
+
|
47
|
+
Metrics/ModuleLength:
|
48
|
+
Exclude:
|
49
|
+
- 'test/**/*.rb'
|
50
|
+
|
51
|
+
Metrics/ParameterLists:
|
52
|
+
CountKeywordArgs: false
|
53
|
+
|
54
|
+
Naming/UncommunicativeMethodParamName:
|
55
|
+
AllowedNames:
|
56
|
+
- x
|
57
|
+
- y
|
58
|
+
- i
|
59
|
+
- p
|
60
|
+
- n
|
61
|
+
- r
|
62
|
+
- g
|
63
|
+
- b
|
64
|
+
- to
|
65
|
+
- '_'
|
data/Gemfile
CHANGED
data/Gemfile.lock
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
rooted_tree (0.3.4)
|
5
|
+
linked (~> 0.1.1)
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: https://rubygems.org/
|
9
|
+
specs:
|
10
|
+
ast (2.4.0)
|
11
|
+
docile (1.3.1)
|
12
|
+
jaro_winkler (1.5.1)
|
13
|
+
json (2.1.0)
|
14
|
+
linked (0.1.3)
|
15
|
+
minitest (5.9.0)
|
16
|
+
parallel (1.12.1)
|
17
|
+
parser (2.5.1.2)
|
18
|
+
ast (~> 2.4.0)
|
19
|
+
powerpack (0.1.2)
|
20
|
+
rainbow (3.0.0)
|
21
|
+
rake (10.5.0)
|
22
|
+
redcarpet (3.4.0)
|
23
|
+
rubocop (0.58.2)
|
24
|
+
jaro_winkler (~> 1.5.1)
|
25
|
+
parallel (~> 1.10)
|
26
|
+
parser (>= 2.5, != 2.5.1.1)
|
27
|
+
powerpack (~> 0.1)
|
28
|
+
rainbow (>= 2.2.2, < 4.0)
|
29
|
+
ruby-progressbar (~> 1.7)
|
30
|
+
unicode-display_width (~> 1.0, >= 1.0.1)
|
31
|
+
ruby-progressbar (1.9.0)
|
32
|
+
simplecov (0.16.1)
|
33
|
+
docile (~> 1.1)
|
34
|
+
json (>= 1.8, < 3)
|
35
|
+
simplecov-html (~> 0.10.0)
|
36
|
+
simplecov-html (0.10.2)
|
37
|
+
unicode-display_width (1.4.0)
|
38
|
+
yard (0.9.15)
|
39
|
+
|
40
|
+
PLATFORMS
|
41
|
+
ruby
|
42
|
+
|
43
|
+
DEPENDENCIES
|
44
|
+
bundler (~> 1.16)
|
45
|
+
minitest (~> 5.0)
|
46
|
+
rake (~> 10.0)
|
47
|
+
redcarpet (~> 3.4)
|
48
|
+
rooted_tree!
|
49
|
+
rubocop (~> 0.52)
|
50
|
+
simplecov (~> 0.16)
|
51
|
+
yard (~> 0.9)
|
52
|
+
|
53
|
+
BUNDLED WITH
|
54
|
+
1.16.3
|
data/README.md
CHANGED
@@ -1,13 +1,11 @@
|
|
1
|
-
# RootedTree
|
1
|
+
# 🌳 RootedTree
|
2
2
|
|
3
3
|
[](http://badge.fury.io/rb/rooted_tree)
|
4
4
|
[](https://travis-ci.org/seblindberg/ruby-rooted_tree)
|
5
|
-
[](https://coveralls.io/github/seblindberg/ruby-rooted_tree?branch=master)
|
6
5
|
[](http://inch-ci.org/github/seblindberg/ruby-rooted_tree)
|
6
|
+
[](http://www.rubydoc.info/gems/rooted_tree/)
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
This gem technically implements a _rooted, ordered tree_, but that name is a mouthful. It is ment to be used as a building block when working with any tree shaped data. For a brief recap of the terminology please see below.
|
8
|
+
This gem implements a _rooted, ordered tree_, but that name is a bit of a mouthful. It is ment to be used as a building block when working with any tree shaped data. For a brief recap of the terminology please see below. Please refer to https://en.wikipedia.org/wiki/Tree_structure for a more in depth description.
|
11
9
|
|
12
10
|
A A is the root.
|
13
11
|
┌────┼──┐ B, C and D are all children of A.
|
data/Rakefile
CHANGED
@@ -1,10 +1,24 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/gem_tasks'
|
4
|
+
require 'rake/testtask'
|
5
|
+
require 'rubocop/rake_task'
|
6
|
+
require 'yard'
|
3
7
|
|
4
8
|
Rake::TestTask.new(:test) do |t|
|
5
|
-
t.libs <<
|
6
|
-
t.libs <<
|
9
|
+
t.libs << 'test'
|
10
|
+
t.libs << 'lib'
|
7
11
|
t.test_files = FileList['test/**/*_test.rb']
|
8
12
|
end
|
9
13
|
|
10
|
-
|
14
|
+
RuboCop::RakeTask.new(:rubocop)
|
15
|
+
|
16
|
+
YARD::Rake::YardocTask.new(:yard) do |t|
|
17
|
+
t.stats_options = %w[--list-undoc]
|
18
|
+
t.files = ['lib/**/*.rb', '-', 'CHANGELOG.md']
|
19
|
+
end
|
20
|
+
|
21
|
+
desc 'Generate Ruby documentation'
|
22
|
+
task doc: %w[yard]
|
23
|
+
|
24
|
+
task default: %w[test rubocop:auto_correct]
|
data/bin/console
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
2
3
|
|
3
|
-
require
|
4
|
-
require
|
4
|
+
require 'bundler/setup'
|
5
|
+
require 'rooted_tree'
|
5
6
|
|
6
7
|
# You can add fixtures and/or initialization code here to make experimenting
|
7
8
|
# with your gem easier. You can also use a different console, if you like.
|
@@ -10,5 +11,5 @@ require "rooted_tree"
|
|
10
11
|
# require "pry"
|
11
12
|
# Pry.start
|
12
13
|
|
13
|
-
require
|
14
|
+
require 'irb'
|
14
15
|
IRB.start
|
data/examples/filesystem_tree.rb
CHANGED
@@ -1,20 +1,18 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
2
3
|
|
3
4
|
require 'rooted_tree'
|
4
5
|
|
5
|
-
# FileSystemItem
|
6
|
-
#
|
7
6
|
# Maps the entries in the file system to `Node` objects via .map_to_path. The
|
8
7
|
# Node#inspect method is then exploited in #display to show the resulting tree
|
9
8
|
# structure. The name of each entry in the filesystem is stored in the value
|
10
9
|
# field of the Node.
|
11
|
-
|
12
10
|
class FileSystemItem < RootedTree::Node
|
13
11
|
def display
|
14
|
-
inspect
|
12
|
+
inspect(&:value)
|
15
13
|
end
|
16
|
-
|
17
|
-
def self.map_to_path
|
14
|
+
|
15
|
+
def self.map_to_path(path = '.', root: new(path))
|
18
16
|
# Iterate over all of the files in the directory
|
19
17
|
Dir[path + '/*'].each do |entry|
|
20
18
|
# Create a new FileSystemItem for the entry
|
@@ -24,7 +22,7 @@ class FileSystemItem < RootedTree::Node
|
|
24
22
|
# entry, if it is a directory
|
25
23
|
map_to_path entry, root: item unless File.file? entry
|
26
24
|
end
|
27
|
-
|
25
|
+
|
28
26
|
root
|
29
27
|
end
|
30
28
|
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RootedTree
|
4
|
+
# This module contains methods for mutating a tree node.
|
5
|
+
module Mutable
|
6
|
+
# Insert a child between this node and the one after it.
|
7
|
+
#
|
8
|
+
# @raise [StructureException] if this node has no parent.
|
9
|
+
#
|
10
|
+
# @param value [Object] the value of the new sibling.
|
11
|
+
# @return [self]
|
12
|
+
def append_sibling(value = nil)
|
13
|
+
raise StructureException, 'Root node can not have siblings' if root?
|
14
|
+
|
15
|
+
append value
|
16
|
+
self
|
17
|
+
end
|
18
|
+
|
19
|
+
# Insert a child between this node and the one before it.
|
20
|
+
#
|
21
|
+
# @raise [StructureException] if this node has no parent.
|
22
|
+
#
|
23
|
+
# @param value [Object] the value of the new sibling.
|
24
|
+
# @return [self]
|
25
|
+
def prepend_sibling(value = nil)
|
26
|
+
raise StructureException, 'Root node can not have siblings' if root?
|
27
|
+
|
28
|
+
prepend value
|
29
|
+
self
|
30
|
+
end
|
31
|
+
|
32
|
+
# Insert a child after the last one.
|
33
|
+
#
|
34
|
+
# @param value [Object] the value of the new sibling.
|
35
|
+
# @return [self]
|
36
|
+
def append_child(value = nil)
|
37
|
+
push value
|
38
|
+
end
|
39
|
+
|
40
|
+
# @see #append_child.
|
41
|
+
alias << append_child
|
42
|
+
|
43
|
+
# Insert a child before the first one.
|
44
|
+
#
|
45
|
+
# @param value [Object] the value of the new sibling.
|
46
|
+
# @return [self]
|
47
|
+
def prepend_child(value = nil)
|
48
|
+
unshift value
|
49
|
+
end
|
50
|
+
|
51
|
+
# Extracts the node and its subtree from the larger structure.
|
52
|
+
#
|
53
|
+
# @return [self] the node will now be root.
|
54
|
+
def extract
|
55
|
+
return self if root?
|
56
|
+
|
57
|
+
method(:delete).super_method.call
|
58
|
+
self
|
59
|
+
end
|
60
|
+
|
61
|
+
# Removes the node from the tree.
|
62
|
+
#
|
63
|
+
# @return [Array<Node>] an array of the children to the deleted node, now
|
64
|
+
# made roots.
|
65
|
+
def delete
|
66
|
+
extract.children.to_a.each(&:extract)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
data/lib/rooted_tree/node.rb
CHANGED
@@ -1,335 +1,111 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# Node
|
4
|
-
#
|
5
|
-
# Nodes are mutable by default, since creating anyting but simple leafs would
|
6
|
-
# otherwise be imposible. Calling #freeze on a node makes the entire subtree
|
7
|
-
# immutable. This is used by the Tree class which only operates on frozen node
|
8
|
-
# structures.
|
9
|
-
#
|
10
|
-
# The following is an example of a rooted tree with maximum depth 2.
|
11
|
-
#
|
12
|
-
# r - r, a, b, c, and d are internal vertices
|
13
|
-
# +--+---+ - vertices e, f, g, h, i, and j are leaves
|
14
|
-
# a b c - vertices g, h, and i are siblings
|
15
|
-
# +++ | +-+-+ - node a is an ancestor of j
|
16
|
-
# d e f g h i - j is a descendant of a
|
17
|
-
# |
|
18
|
-
# j
|
19
|
-
#
|
20
|
-
# The terminology is mostly referenced from
|
21
|
-
# http://www.cs.columbia.edu/~cs4203/files/GT-Lec4.pdf.
|
22
|
-
|
23
3
|
module RootedTree
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
4
|
+
# rubocop:disable Metrics/ClassLength
|
5
|
+
|
6
|
+
# Nodes are mutable by default, since creating anyting but simple leafs would
|
7
|
+
# otherwise be imposible. Calling #freeze on a node makes the entire subtree
|
8
|
+
# immutable. This is used by the Tree class which only operates on frozen node
|
9
|
+
# structures.
|
10
|
+
#
|
11
|
+
# The following is an example of a rooted tree with maximum depth 2.
|
12
|
+
#
|
13
|
+
# r - r, a, b, c, and d are internal vertices
|
14
|
+
# +--+---+ - vertices e, f, g, h, i, and j are leaves
|
15
|
+
# a b c - vertices g, h, and i are siblings
|
16
|
+
# +++ | +-+-+ - node a is an ancestor of j
|
17
|
+
# d e f g h i - j is a descendant of a
|
18
|
+
# |
|
19
|
+
# j
|
20
|
+
#
|
21
|
+
# The terminology is mostly referenced from
|
22
|
+
# http://www.cs.columbia.edu/~cs4203/files/GT-Lec4.pdf.
|
23
|
+
class Node < Linked::Item
|
24
|
+
extend Forwardable
|
25
|
+
include Linked::List
|
26
|
+
include Mutable
|
33
27
|
|
34
28
|
# Creates a new node with the given object as its value, unless a Node is
|
35
29
|
# passed, in which case it will be returned.
|
36
30
|
#
|
37
|
-
# value
|
38
|
-
#
|
39
|
-
#
|
40
|
-
|
31
|
+
# @param value [Object] the object to be used as value for a new Node, or a
|
32
|
+
# Node object.
|
33
|
+
# @return [Node] a Node object.
|
41
34
|
def self.[](value = nil)
|
42
35
|
return value if value.is_a? self
|
43
36
|
new value
|
44
37
|
end
|
45
|
-
|
46
|
-
# Create a new, unconnected Node object with an optional value. The value is
|
47
|
-
# owned by the Node instance and will be duped along with it.
|
48
|
-
#
|
49
|
-
# value - arbitrary object that is owned by the Node instance.
|
50
|
-
|
51
|
-
def initialize(value = nil)
|
52
|
-
@parent = nil
|
53
|
-
@next = nil
|
54
|
-
@prev = nil
|
55
|
-
@first_child = nil
|
56
|
-
@last_child = nil
|
57
|
-
@degree = 0
|
58
|
-
@value = value
|
59
|
-
end
|
60
|
-
|
61
|
-
# When copying a node the child nodes are copied as well, along with the
|
62
|
-
# value.
|
63
|
-
|
64
|
-
def initialize_dup(source)
|
65
|
-
# Dup each child and link them to the new parent
|
66
|
-
duped_children = source.children.map do |child|
|
67
|
-
child.dup.tap { |n| n.parent = self }
|
68
|
-
end
|
69
|
-
|
70
|
-
# Connect each child to its adjecent siblings
|
71
|
-
duped_children.each_cons(2) { |a, b| a.next, b.prev = b, a }
|
72
|
-
|
73
|
-
@parent = nil
|
74
|
-
@first_child = duped_children.first
|
75
|
-
@last_child = duped_children.last
|
76
|
-
@value = begin
|
77
|
-
source.value.dup
|
78
|
-
rescue TypeError
|
79
|
-
source.value
|
80
|
-
end
|
81
|
-
|
82
|
-
super
|
83
|
-
end
|
84
|
-
|
85
|
-
# Freezes the value as well as each of the children, outside of the normal
|
86
|
-
# behaviour.
|
87
|
-
|
88
|
-
def freeze
|
89
|
-
@value.freeze
|
90
|
-
children.each(&:freeze)
|
91
|
-
super
|
92
|
-
end
|
93
38
|
|
94
|
-
#
|
39
|
+
# @return [Integer] the number of children of the node.
|
40
|
+
alias degree count
|
95
41
|
|
96
|
-
|
97
|
-
|
98
|
-
end
|
42
|
+
# @return [Integer] see #degree.
|
43
|
+
alias arity degree
|
99
44
|
|
100
|
-
#
|
101
|
-
|
45
|
+
# @return [Node] the first child.
|
46
|
+
alias first_child first
|
102
47
|
|
103
|
-
|
104
|
-
|
105
|
-
end
|
48
|
+
# @return [Node] the last child.
|
49
|
+
alias last_child last
|
106
50
|
|
107
|
-
#
|
51
|
+
# @return [true] if this node has no children.
|
52
|
+
# @return [false] otherwise.
|
53
|
+
def_delegator :degree, :zero?, :leaf?
|
108
54
|
|
109
|
-
|
110
|
-
|
111
|
-
|
55
|
+
# @return [true] if the node has children.
|
56
|
+
# @return [false] otherwise.
|
57
|
+
def_delegator :degree, :positive?, :internal?
|
112
58
|
|
113
|
-
#
|
59
|
+
# @return [true] if the node has no parent.
|
60
|
+
# @return [false] otherwise.
|
61
|
+
def_delegator :list, :nil?, :root?
|
114
62
|
|
63
|
+
# @return [Node] the root of the tree structure that the node is part of.
|
115
64
|
def root
|
116
65
|
return self if root?
|
117
|
-
|
118
|
-
node = self
|
119
|
-
loop { node = node.parent }
|
120
|
-
node
|
121
|
-
end
|
122
|
-
|
123
|
-
# Returns true if this node is the first of its siblings.
|
124
|
-
|
125
|
-
def first?
|
126
|
-
@prev.nil?
|
127
|
-
end
|
128
|
-
|
129
|
-
# Returns true if this node is the last of its siblings.
|
130
|
-
|
131
|
-
def last?
|
132
|
-
@next.nil?
|
66
|
+
loop.reduce(self) { |node,| node.parent }
|
133
67
|
end
|
134
68
|
|
135
|
-
#
|
136
|
-
|
137
|
-
def depth
|
138
|
-
ancestors.count
|
139
|
-
end
|
69
|
+
# @return [Integer] the depth of the node within the tree.
|
70
|
+
def_delegator :ancestors, :count, :depth
|
140
71
|
|
141
72
|
alias level depth
|
142
73
|
|
143
|
-
#
|
144
|
-
|
74
|
+
# @return [Integer] the maximum node depth under this node.
|
145
75
|
def max_depth(offset = depth)
|
146
76
|
return offset if leaf?
|
147
77
|
|
148
78
|
children.map { |c| c.max_depth offset + 1 }.max
|
149
79
|
end
|
150
80
|
|
151
|
-
#
|
152
|
-
|
81
|
+
# @return [Integer] the highest child count of the nodes in the subtree.
|
153
82
|
def max_degree
|
154
83
|
children.map(&:degree).push(degree).max
|
155
84
|
end
|
156
85
|
|
157
86
|
# Calculate the size in vertecies of the subtree.
|
158
87
|
#
|
159
|
-
#
|
160
|
-
|
88
|
+
# @return [Integer] the number of nodes under this node, including self.
|
161
89
|
def size
|
162
90
|
children.reduce(1) { |a, e| a + e.size }
|
163
91
|
end
|
164
92
|
|
165
|
-
# Access the next sibling. Raises a StopIteration if this node is the last
|
166
|
-
# one.
|
167
|
-
#
|
168
|
-
# Returns the next sibling node.
|
169
|
-
|
170
|
-
def next
|
171
|
-
raise StopIteration if last?
|
172
|
-
@next
|
173
|
-
end
|
174
|
-
|
175
|
-
# Dangerous accessor of the next sibling. Unlike the regular #next this
|
176
|
-
# method will return nil if this node is the last one.
|
177
|
-
#
|
178
|
-
# Returns the next sibling node or nil if this node is last.
|
179
|
-
|
180
|
-
def next!
|
181
|
-
@next
|
182
|
-
end
|
183
|
-
|
184
|
-
# Access the previous sibling. Raises a StopIteration if this node is the
|
185
|
-
# first one.
|
186
|
-
#
|
187
|
-
# Returns the previous sibling node.
|
188
|
-
|
189
|
-
def prev
|
190
|
-
raise StopIteration if first?
|
191
|
-
@prev
|
192
|
-
end
|
193
|
-
|
194
|
-
alias previous prev
|
195
|
-
|
196
|
-
# Dangerous accessor of the previous sibling. Unlike the regular #prev this
|
197
|
-
# method will return nil if this node is the first one.
|
198
|
-
|
199
|
-
def prev!
|
200
|
-
@prev
|
201
|
-
end
|
202
|
-
|
203
|
-
alias previous! prev!
|
204
|
-
|
205
93
|
# Access the parent node. Raises a StopIteration if this node is the
|
206
94
|
# root.
|
207
95
|
#
|
208
|
-
#
|
209
|
-
|
96
|
+
# @raise [StopIteration] if this node is the root.
|
97
|
+
#
|
98
|
+
# @return [Node] the parent node.
|
210
99
|
def parent
|
211
100
|
raise StopIteration if root?
|
212
|
-
|
213
|
-
end
|
214
|
-
|
215
|
-
# Insert a child between this node and the one after it.
|
216
|
-
#
|
217
|
-
# Returns self.
|
218
|
-
|
219
|
-
def append_sibling(value = nil)
|
220
|
-
raise StructureException, 'Root node can not have siblings' if root?
|
221
|
-
|
222
|
-
node = self.class[value]
|
223
|
-
node.next = @next
|
224
|
-
node.prev = self
|
225
|
-
node.parent = @parent
|
226
|
-
@parent.degree += 1
|
227
|
-
|
228
|
-
if @next
|
229
|
-
@next.prev = node
|
230
|
-
else
|
231
|
-
@parent.last_child = node
|
232
|
-
end
|
233
|
-
@next = node
|
234
|
-
end
|
235
|
-
|
236
|
-
# Insert a child between this node and the one before it.
|
237
|
-
#
|
238
|
-
# Returns self.
|
239
|
-
|
240
|
-
def prepend_sibling(value = nil)
|
241
|
-
raise StructureException, 'Root node can not have siblings' if root?
|
242
|
-
|
243
|
-
node = self.class[value]
|
244
|
-
node.next = self
|
245
|
-
node.prev = @prev
|
246
|
-
node.parent = @parent
|
247
|
-
@parent.degree += 1
|
248
|
-
|
249
|
-
if @prev
|
250
|
-
@prev.next = node
|
251
|
-
else
|
252
|
-
@parent.first_child = node
|
253
|
-
end
|
254
|
-
@prev = node
|
255
|
-
end
|
256
|
-
|
257
|
-
private def add_child_to_leaf(value)
|
258
|
-
node = self.class[value]
|
259
|
-
@first_child = @last_child = node
|
260
|
-
node.next = node.prev = nil
|
261
|
-
@degree = 1
|
262
|
-
node.parent = self
|
263
|
-
end
|
264
|
-
|
265
|
-
# Insert a child after the last one.
|
266
|
-
#
|
267
|
-
# Returns self.
|
268
|
-
|
269
|
-
def append_child(value = nil)
|
270
|
-
if leaf?
|
271
|
-
add_child_to_leaf value
|
272
|
-
else
|
273
|
-
@last_child.append_sibling value
|
274
|
-
end
|
275
|
-
self
|
276
|
-
end
|
277
|
-
|
278
|
-
alias << append_child
|
279
|
-
|
280
|
-
# Insert a child before the first one.
|
281
|
-
#
|
282
|
-
# Returns self.
|
283
|
-
|
284
|
-
def prepend_child(value = nil)
|
285
|
-
if leaf?
|
286
|
-
add_child_to_leaf value
|
287
|
-
else
|
288
|
-
@first_child.prepend_sibling value
|
289
|
-
end
|
290
|
-
end
|
291
|
-
|
292
|
-
# Extracts the node and its subtree from the larger structure.
|
293
|
-
#
|
294
|
-
# Returns self, now made root.
|
295
|
-
|
296
|
-
def extract
|
297
|
-
return self if root?
|
298
|
-
|
299
|
-
if last?
|
300
|
-
parent.last_child = @prev
|
301
|
-
else
|
302
|
-
@next.prev = @prev
|
303
|
-
end
|
304
|
-
|
305
|
-
if first?
|
306
|
-
parent.first_child = @next
|
307
|
-
else
|
308
|
-
@prev.next = @next
|
309
|
-
end
|
310
|
-
|
311
|
-
@parent.degree -= 1
|
312
|
-
@prev = @next = @parent = nil
|
313
|
-
self
|
314
|
-
end
|
315
|
-
|
316
|
-
# Removes the node from the tree.
|
317
|
-
#
|
318
|
-
# Returns an array of the children to the deleted node, now made roots.
|
319
|
-
|
320
|
-
def delete
|
321
|
-
extract.children.to_a.each do |child|
|
322
|
-
child.parent = nil
|
323
|
-
child.next = child.prev = nil
|
324
|
-
end
|
101
|
+
list
|
325
102
|
end
|
326
103
|
|
327
104
|
# Iterates over the nodes above this in the tree hierarchy and yields them
|
328
105
|
# to a block. If no block is given an enumerator is returned.
|
329
106
|
#
|
330
|
-
#
|
331
|
-
#
|
332
|
-
|
107
|
+
# @yield [Node] each parent node.
|
108
|
+
# @return [Enumerator] if no block is given.
|
333
109
|
def ancestors
|
334
110
|
return to_enum(__callee__) unless block_given?
|
335
111
|
node = self
|
@@ -346,59 +122,41 @@ module RootedTree
|
|
346
122
|
# Note that the block will catch any StopIteration that is raised and
|
347
123
|
# terminate early, returning the value of the exception.
|
348
124
|
#
|
349
|
-
# rtl
|
350
|
-
|
351
|
-
def children(rtl: false)
|
352
|
-
|
353
|
-
return if leaf?
|
354
|
-
|
355
|
-
child, advance = if rtl
|
356
|
-
[@last_child, :prev]
|
357
|
-
else
|
358
|
-
[@first_child, :next]
|
359
|
-
end
|
360
|
-
|
361
|
-
loop do
|
362
|
-
yield child
|
363
|
-
child = child.send advance
|
364
|
-
end
|
125
|
+
# @param rtl [true, false] reverses the iteration order if true.
|
126
|
+
# @return see #each_item
|
127
|
+
def children(rtl: false, &block)
|
128
|
+
rtl ? reverse_each_item(&block) : each_item(&block)
|
365
129
|
end
|
366
130
|
|
367
131
|
# Accessor method for any of the n children under this node. If called
|
368
132
|
# without an argument and the node has anything but exactly one child an
|
369
133
|
# exception will be raised.
|
370
134
|
#
|
371
|
-
#
|
372
|
-
#
|
373
|
-
#
|
374
|
-
#
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
raise ArgumentError, 'No argument given for node with degree != 1'
|
380
|
-
end
|
381
|
-
return @first_child
|
135
|
+
# @param index [Integer] the n:th child to be returned. If the index is
|
136
|
+
# negative the indexing will be reversed and the children counted from the
|
137
|
+
# last to the first.
|
138
|
+
# @return [Node] the child at the n:th index.
|
139
|
+
def child(index = nil)
|
140
|
+
unless index
|
141
|
+
raise ArgumentError, 'No index for node with degree != 1' if degree != 1
|
142
|
+
return first
|
382
143
|
end
|
383
144
|
|
384
|
-
rtl =
|
385
|
-
n = -1 - n
|
386
|
-
true
|
387
|
-
else
|
388
|
-
false
|
389
|
-
end
|
145
|
+
rtl, index = wrap_index index
|
390
146
|
|
391
|
-
raise RangeError, 'Child index out of range' if
|
147
|
+
raise RangeError, 'Child index out of range' if index >= degree
|
392
148
|
|
393
149
|
children(rtl: rtl).each do |c|
|
394
|
-
break c if
|
395
|
-
|
150
|
+
break c if index.zero?
|
151
|
+
index -= 1
|
396
152
|
end
|
397
153
|
end
|
398
154
|
|
399
|
-
|
400
|
-
# enumerator is returned.
|
155
|
+
alias [] child
|
401
156
|
|
157
|
+
# @yield [Node] first self is yielded and then the children who in turn
|
158
|
+
# yield their children.
|
159
|
+
# @return [Enumerator] if no block is given.
|
402
160
|
def each(&block)
|
403
161
|
return to_enum(__callee__) unless block_given?
|
404
162
|
yield self
|
@@ -409,9 +167,7 @@ module RootedTree
|
|
409
167
|
# node is placed at index zero of its own array, followed by an array of its
|
410
168
|
# children. Leaf nodes are not wraped in arrays but inserted directly.
|
411
169
|
#
|
412
|
-
#
|
413
|
-
#
|
414
|
-
# Example
|
170
|
+
# == Example
|
415
171
|
#
|
416
172
|
# r
|
417
173
|
# / \
|
@@ -419,29 +175,28 @@ module RootedTree
|
|
419
175
|
# |
|
420
176
|
# c
|
421
177
|
#
|
422
|
-
#
|
423
|
-
|
424
|
-
def to_a
|
425
|
-
return
|
178
|
+
# @param flatten [true, false] the array is flattened if true.
|
179
|
+
# @return [Array<Node, Array>] a nested array of nodes.
|
180
|
+
def to_a(flatten: false)
|
181
|
+
return each.to_a if flatten
|
426
182
|
return self if leaf?
|
427
183
|
[self, children.map(&:to_a)]
|
428
184
|
end
|
429
185
|
|
430
186
|
# Iterates over each of the leafs.
|
431
187
|
#
|
432
|
-
# rtl
|
433
|
-
|
188
|
+
# @param rtl [true, false] if true the iteration order is switched to right
|
189
|
+
# to left.
|
434
190
|
def leafs(rtl: false, &block)
|
435
191
|
return to_enum(__callee__, rtl: rtl) unless block_given?
|
436
192
|
return yield self if leaf?
|
437
193
|
children(rtl: rtl) { |v| v.leafs(rtl: rtl, &block) }
|
438
194
|
end
|
439
195
|
|
440
|
-
# Iterates over each
|
441
|
-
# block is given an enumerator is returned.
|
196
|
+
# Iterates over each edge in the tree.
|
442
197
|
#
|
443
|
-
#
|
444
|
-
|
198
|
+
# @yield [Array<Node>] each connected node pair.
|
199
|
+
# @return [Enumerator] if no block is given.
|
445
200
|
def edges(&block)
|
446
201
|
return to_enum(__callee__) unless block_given?
|
447
202
|
|
@@ -455,10 +210,8 @@ module RootedTree
|
|
455
210
|
# created and returned. Note that if the any of the root nodes are not
|
456
211
|
# frozen they will be modified, and as a result seize to be roots.
|
457
212
|
#
|
458
|
-
# other
|
459
|
-
#
|
460
|
-
# Returns a new root with the two nodes as children.
|
461
|
-
|
213
|
+
# @param other [Node] a Node-like object that responds true to #root?
|
214
|
+
# @return [Node] a new root with the two nodes as children.
|
462
215
|
def +(other)
|
463
216
|
unless root? && other.root?
|
464
217
|
raise StructureException, 'Only roots can be added'
|
@@ -473,8 +226,9 @@ module RootedTree
|
|
473
226
|
|
474
227
|
# Compare one node (sub)structure with another.
|
475
228
|
#
|
476
|
-
#
|
477
|
-
|
229
|
+
# @param other [Object]
|
230
|
+
# @return [true] if the two vertecies form identical subtrees.
|
231
|
+
# @reutrn [false] otherwise.
|
478
232
|
def ==(other)
|
479
233
|
return false unless other.is_a? self.class
|
480
234
|
return false unless degree == other.degree
|
@@ -483,36 +237,19 @@ module RootedTree
|
|
483
237
|
children.to_a == other.children.to_a
|
484
238
|
end
|
485
239
|
|
486
|
-
|
487
|
-
# An example of the output can be seen below. Note that the output string
|
488
|
-
# contains unicode characters.
|
489
|
-
#
|
490
|
-
# Node:0x3ffd64c22abc
|
491
|
-
# |--Node:0x3ffd64c1fd30
|
492
|
-
# | |--Node:0x3ffd64c1f86c
|
493
|
-
# | +--Node:0x3ffd64c1f63c
|
494
|
-
# +--Node:0x3ffd64c1f40c
|
495
|
-
#
|
496
|
-
# By passing `as_array: true` the method will instead return an array
|
497
|
-
# containing each of the output lines. The method also accepts a block
|
498
|
-
# which, if given, will be yielded to once for every node, and the output
|
499
|
-
# will be used as node labels instead of the default identifier.
|
500
|
-
|
501
|
-
def inspect(as_array: false, &block)
|
502
|
-
unless block_given?
|
503
|
-
block = proc { |v| format '%s:0x%0x', v.class.name, v.object_id }
|
504
|
-
end
|
505
|
-
|
506
|
-
res = [block.call(self)]
|
240
|
+
private
|
507
241
|
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
242
|
+
def wrap_index(index)
|
243
|
+
if index.negative?
|
244
|
+
[true, -1 - index]
|
245
|
+
else
|
246
|
+
[false, index]
|
513
247
|
end
|
514
|
-
|
515
|
-
as_array ? res : res.join("\n")
|
516
248
|
end
|
249
|
+
|
250
|
+
protected :first, :last, :each_item
|
251
|
+
private :push, :unshift, :list, :count
|
517
252
|
end
|
253
|
+
|
254
|
+
# rubocop:enable Metrics/ClassLength
|
518
255
|
end
|
data/lib/rooted_tree/tree.rb
CHANGED
@@ -1,54 +1,36 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# Tree
|
4
|
-
#
|
5
|
-
# Include this module in any object that responds to #root with a Node
|
6
|
-
# structure. The mixin provides some methods for describing the tree as well as
|
7
|
-
# direct access to some of the iteration methods in Node.
|
8
|
-
|
9
3
|
module RootedTree
|
4
|
+
# Include this module in any object that responds to #root with a Node
|
5
|
+
# structure. The mixin provides some methods for describing the tree as well
|
6
|
+
# as direct access to some of the iteration methods in Node.
|
10
7
|
module Tree
|
11
|
-
|
8
|
+
extend Forwardable
|
9
|
+
|
12
10
|
# Freezes the node structure that is part of the tree.
|
13
|
-
|
14
11
|
def freeze
|
15
12
|
root.freeze
|
16
13
|
super
|
17
14
|
end
|
18
|
-
|
19
|
-
# Returns the maximum degree (highest number of children) in the tree.
|
20
15
|
|
21
|
-
|
22
|
-
|
23
|
-
end
|
16
|
+
# Returns the maximum degree (highest number of children) in the tree.
|
17
|
+
def_delegator :root, :max_degree, :degree
|
24
18
|
|
25
19
|
# Returns the maximum depth of the tree.
|
26
|
-
|
27
|
-
def depth
|
28
|
-
root.max_depth
|
29
|
-
end
|
20
|
+
def_delegator :root, :max_depth, :depth
|
30
21
|
|
31
22
|
# Iterates over each node in the tree. When given a block it will be yielded
|
32
23
|
# to once for each node. If no block is given an enumerator is returned.
|
33
|
-
|
34
|
-
def each_node(&block)
|
35
|
-
root.each(&block)
|
36
|
-
end
|
24
|
+
def_delegator :root, :each, :each_node
|
37
25
|
|
38
26
|
# Iterates over each leaf in the tree. When given a block it will be yielded
|
39
27
|
# to once for leaf node. If no block is given an enumerator is returned.
|
40
|
-
|
41
|
-
def each_leaf(&block)
|
42
|
-
root.leafs(&block)
|
43
|
-
end
|
28
|
+
def_delegator :root, :leafs, :each_leaf
|
44
29
|
|
45
30
|
# Iterates over each edge in the tree. An edge is composed of the parent
|
46
31
|
# node and the child, always in that order. When given a block it will be
|
47
32
|
# yielded to once for each node. If no block is given an enumerator is
|
48
33
|
# returned.
|
49
|
-
|
50
|
-
def each_edge(&block)
|
51
|
-
root.edges(&block)
|
52
|
-
end
|
34
|
+
def_delegator :root, :edges, :each_edge
|
53
35
|
end
|
54
36
|
end
|
data/lib/rooted_tree/version.rb
CHANGED
data/lib/rooted_tree.rb
CHANGED
@@ -1,9 +1,16 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'forwardable'
|
4
|
+
require 'linked'
|
5
|
+
|
3
6
|
require 'rooted_tree/version'
|
7
|
+
require 'rooted_tree/mutable'
|
4
8
|
require 'rooted_tree/node'
|
5
9
|
require 'rooted_tree/tree'
|
6
10
|
|
11
|
+
# A basic implementation of a tree data structure.
|
7
12
|
module RootedTree
|
8
13
|
class StructureException < StandardError; end
|
14
|
+
|
15
|
+
private_constant :Mutable
|
9
16
|
end
|
data/rooted_tree.gemspec
CHANGED
@@ -1,26 +1,38 @@
|
|
1
|
-
#
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
lib = File.expand_path('lib', __dir__)
|
3
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
5
|
require 'rooted_tree/version'
|
5
6
|
|
6
7
|
Gem::Specification.new do |spec|
|
7
|
-
spec.name =
|
8
|
+
spec.name = 'rooted_tree'
|
8
9
|
spec.version = RootedTree::VERSION
|
9
|
-
spec.authors = [
|
10
|
-
spec.email = [
|
10
|
+
spec.authors = ['Sebastian Lindberg']
|
11
|
+
spec.email = ['seb.lindberg@gmail.com']
|
12
|
+
|
13
|
+
spec.summary = 'A basic implementation of a tree data structure.'
|
14
|
+
spec.description = 'This gem implements a rooted, ordered tree, with a ' \
|
15
|
+
'focus on easy iteration over nodes and access to ' \
|
16
|
+
'basic tree properties.'
|
17
|
+
spec.homepage = 'https://github.com/seblindberg/ruby-rooted_tree'
|
18
|
+
spec.license = 'MIT'
|
11
19
|
|
12
|
-
spec.
|
13
|
-
|
14
|
-
|
15
|
-
|
20
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
21
|
+
`git ls-files -z`.split("\x0")
|
22
|
+
.reject { |f| f.match(%r{^(test|spec|features)/}) }
|
23
|
+
end
|
16
24
|
|
17
|
-
spec.
|
18
|
-
spec.bindir = "exe"
|
25
|
+
spec.bindir = 'exe'
|
19
26
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
20
|
-
spec.require_paths = [
|
27
|
+
spec.require_paths = ['lib']
|
28
|
+
|
29
|
+
spec.add_dependency 'linked', '~> 0.1.1'
|
21
30
|
|
22
|
-
spec.add_development_dependency
|
23
|
-
spec.add_development_dependency
|
24
|
-
spec.add_development_dependency
|
25
|
-
spec.add_development_dependency
|
31
|
+
spec.add_development_dependency 'bundler', '~> 1.16'
|
32
|
+
spec.add_development_dependency 'minitest', '~> 5.0'
|
33
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
34
|
+
spec.add_development_dependency 'redcarpet', '~> 3.4'
|
35
|
+
spec.add_development_dependency 'rubocop', '~> 0.52'
|
36
|
+
spec.add_development_dependency 'simplecov', '~> 0.16'
|
37
|
+
spec.add_development_dependency 'yard', '~> 0.9'
|
26
38
|
end
|
metadata
CHANGED
@@ -1,29 +1,57 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rooted_tree
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sebastian Lindberg
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-07-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: linked
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.1.1
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.1.1
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: bundler
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
16
30
|
requirements:
|
17
31
|
- - "~>"
|
18
32
|
- !ruby/object:Gem::Version
|
19
|
-
version: '1.
|
33
|
+
version: '1.16'
|
20
34
|
type: :development
|
21
35
|
prerelease: false
|
22
36
|
version_requirements: !ruby/object:Gem::Requirement
|
23
37
|
requirements:
|
24
38
|
- - "~>"
|
25
39
|
- !ruby/object:Gem::Version
|
26
|
-
version: '1.
|
40
|
+
version: '1.16'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: minitest
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '5.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '5.0'
|
27
55
|
- !ruby/object:Gem::Dependency
|
28
56
|
name: rake
|
29
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -39,33 +67,61 @@ dependencies:
|
|
39
67
|
- !ruby/object:Gem::Version
|
40
68
|
version: '10.0'
|
41
69
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
70
|
+
name: redcarpet
|
43
71
|
requirement: !ruby/object:Gem::Requirement
|
44
72
|
requirements:
|
45
73
|
- - "~>"
|
46
74
|
- !ruby/object:Gem::Version
|
47
|
-
version: '
|
75
|
+
version: '3.4'
|
48
76
|
type: :development
|
49
77
|
prerelease: false
|
50
78
|
version_requirements: !ruby/object:Gem::Requirement
|
51
79
|
requirements:
|
52
80
|
- - "~>"
|
53
81
|
- !ruby/object:Gem::Version
|
54
|
-
version: '
|
82
|
+
version: '3.4'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rubocop
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0.52'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0.52'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: simplecov
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0.16'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0.16'
|
55
111
|
- !ruby/object:Gem::Dependency
|
56
|
-
name:
|
112
|
+
name: yard
|
57
113
|
requirement: !ruby/object:Gem::Requirement
|
58
114
|
requirements:
|
59
115
|
- - "~>"
|
60
116
|
- !ruby/object:Gem::Version
|
61
|
-
version: '0.
|
117
|
+
version: '0.9'
|
62
118
|
type: :development
|
63
119
|
prerelease: false
|
64
120
|
version_requirements: !ruby/object:Gem::Requirement
|
65
121
|
requirements:
|
66
122
|
- - "~>"
|
67
123
|
- !ruby/object:Gem::Version
|
68
|
-
version: '0.
|
124
|
+
version: '0.9'
|
69
125
|
description: This gem implements a rooted, ordered tree, with a focus on easy iteration
|
70
126
|
over nodes and access to basic tree properties.
|
71
127
|
email:
|
@@ -75,8 +131,10 @@ extensions: []
|
|
75
131
|
extra_rdoc_files: []
|
76
132
|
files:
|
77
133
|
- ".gitignore"
|
134
|
+
- ".rubocop.yml"
|
78
135
|
- ".travis.yml"
|
79
136
|
- Gemfile
|
137
|
+
- Gemfile.lock
|
80
138
|
- LICENSE.txt
|
81
139
|
- README.md
|
82
140
|
- Rakefile
|
@@ -84,6 +142,7 @@ files:
|
|
84
142
|
- bin/setup
|
85
143
|
- examples/filesystem_tree.rb
|
86
144
|
- lib/rooted_tree.rb
|
145
|
+
- lib/rooted_tree/mutable.rb
|
87
146
|
- lib/rooted_tree/node.rb
|
88
147
|
- lib/rooted_tree/tree.rb
|
89
148
|
- lib/rooted_tree/version.rb
|
@@ -108,7 +167,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
108
167
|
version: '0'
|
109
168
|
requirements: []
|
110
169
|
rubyforge_project:
|
111
|
-
rubygems_version: 2.
|
170
|
+
rubygems_version: 2.6.11
|
112
171
|
signing_key:
|
113
172
|
specification_version: 4
|
114
173
|
summary: A basic implementation of a tree data structure.
|