basic_tree 1.0.0 → 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gemtest +0 -0
- data/Gemfile.lock +13 -9
- data/LICENSE +1 -1
- data/README.rdoc +12 -21
- data/Rakefile +6 -1
- data/basic_tree.gemspec +5 -2
- data/lib/basic_tree/version.rb +5 -0
- data/lib/basic_tree.rb +89 -15
- data/spec/lib/basic_tree_spec.rb +122 -59
- metadata +42 -7
data/.gemtest
ADDED
File without changes
|
data/Gemfile.lock
CHANGED
@@ -1,24 +1,28 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
basic_tree (0.
|
4
|
+
basic_tree (1.0.0)
|
5
|
+
activesupport (~> 3.0.5)
|
6
|
+
i18n (~> 0.5.0)
|
5
7
|
|
6
8
|
GEM
|
7
9
|
remote: http://rubygems.org/
|
8
10
|
specs:
|
11
|
+
activesupport (3.0.5)
|
9
12
|
diff-lcs (1.1.2)
|
10
|
-
|
11
|
-
|
12
|
-
rspec-
|
13
|
-
rspec-
|
14
|
-
|
15
|
-
rspec-
|
13
|
+
i18n (0.5.0)
|
14
|
+
rspec (2.5.0)
|
15
|
+
rspec-core (~> 2.5.0)
|
16
|
+
rspec-expectations (~> 2.5.0)
|
17
|
+
rspec-mocks (~> 2.5.0)
|
18
|
+
rspec-core (2.5.1)
|
19
|
+
rspec-expectations (2.5.0)
|
16
20
|
diff-lcs (~> 1.1.2)
|
17
|
-
rspec-mocks (2.
|
21
|
+
rspec-mocks (2.5.0)
|
18
22
|
|
19
23
|
PLATFORMS
|
20
24
|
ruby
|
21
25
|
|
22
26
|
DEPENDENCIES
|
23
27
|
basic_tree!
|
24
|
-
rspec (
|
28
|
+
rspec (~> 2.5.0)
|
data/LICENSE
CHANGED
data/README.rdoc
CHANGED
@@ -18,16 +18,13 @@ A basic Ruby tree structure with nice syntax.
|
|
18
18
|
fruit.object
|
19
19
|
# "Fruit"
|
20
20
|
|
21
|
-
banana = fruit.
|
22
|
-
banana.object
|
23
|
-
# "Banana"
|
21
|
+
banana = fruit.get(2) # get the 2nd fruit
|
22
|
+
banana.object # "Banana"
|
24
23
|
|
25
|
-
plantain = banana.
|
26
|
-
plantain.object
|
27
|
-
# "Plantain"
|
24
|
+
plantain = banana.get(2) # get the 2nd banana
|
25
|
+
plantain.object # "Plantain"
|
28
26
|
|
29
|
-
plantain.parent.object
|
30
|
-
# "Banana""
|
27
|
+
plantain.parent.object # "Banana"
|
31
28
|
|
32
29
|
plantain.path.map(&:object)
|
33
30
|
# ["Fruit", "Banana", "Plantain"]
|
@@ -44,23 +41,17 @@ A basic Ruby tree structure with nice syntax.
|
|
44
41
|
banana.siblings.map(&:object)
|
45
42
|
# ["Apple", "Orange"]
|
46
43
|
|
47
|
-
plantain.root.object
|
48
|
-
# "Fruit"
|
44
|
+
plantain.root.object # "Fruit"
|
49
45
|
|
50
|
-
plantain.level
|
51
|
-
# 3
|
46
|
+
plantain.level # 3
|
52
47
|
|
53
|
-
banana.root?
|
54
|
-
# false
|
48
|
+
banana.root? # false
|
55
49
|
|
56
|
-
fruit.root?
|
57
|
-
# true
|
50
|
+
fruit.root? # true
|
58
51
|
|
59
|
-
banana.leaf?
|
60
|
-
# false
|
52
|
+
banana.leaf? # false
|
61
53
|
|
62
|
-
plantain.leaf?
|
63
|
-
# true
|
54
|
+
plantain.leaf? # true
|
64
55
|
|
65
56
|
== Note on Patches/Pull Requests
|
66
57
|
|
@@ -74,4 +65,4 @@ A basic Ruby tree structure with nice syntax.
|
|
74
65
|
|
75
66
|
== Copyright
|
76
67
|
|
77
|
-
|
68
|
+
See LICENSE for details.
|
data/Rakefile
CHANGED
data/basic_tree.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
2
|
$:.push File.expand_path("../lib", __FILE__)
|
3
|
-
require "basic_tree"
|
3
|
+
require "basic_tree/version"
|
4
4
|
|
5
5
|
Gem::Specification.new do |s|
|
6
6
|
s.name = "basic_tree"
|
@@ -19,5 +19,8 @@ Gem::Specification.new do |s|
|
|
19
19
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
20
|
s.require_paths = ["lib"]
|
21
21
|
|
22
|
-
s.add_development_dependency 'rspec', "
|
22
|
+
s.add_development_dependency 'rspec', "~> 2.5.0"
|
23
|
+
|
24
|
+
s.add_dependency 'i18n', "~> 0.5.0"
|
25
|
+
s.add_dependency 'activesupport', "~> 3.0.5"
|
23
26
|
end
|
data/lib/basic_tree.rb
CHANGED
@@ -1,22 +1,64 @@
|
|
1
|
+
require 'active_support/core_ext/object'
|
2
|
+
|
1
3
|
class BasicTree
|
2
4
|
|
3
5
|
include Enumerable
|
4
6
|
|
5
|
-
|
7
|
+
class Kids < Array
|
8
|
+
def swap!(p1, p2)
|
9
|
+
self[p1], self[p2] = self[p2], self[p1]
|
10
|
+
end
|
11
|
+
end
|
6
12
|
|
13
|
+
##################################################
|
14
|
+
|
15
|
+
# TODO: test
|
7
16
|
def initialize(object, parent = nil, &block)
|
8
17
|
self.object = object
|
9
|
-
|
10
|
-
self.parent = parent
|
11
|
-
parent.children << self
|
12
|
-
end
|
18
|
+
parent.try(:insert!, self)
|
13
19
|
instance_eval(&block) if block_given?
|
14
20
|
end
|
15
21
|
|
16
|
-
|
17
|
-
|
22
|
+
# TODO: test
|
18
23
|
def add(object, &block)
|
19
|
-
self.class
|
24
|
+
if object.is_a?(self.class)
|
25
|
+
insert!(object)
|
26
|
+
else
|
27
|
+
self.class.new(object, self, &block)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# TODO: test
|
32
|
+
def insert!(basic_tree)
|
33
|
+
raise ArgumentError, "Must be a #{self.class}" unless basic_tree.is_a?(self.class)
|
34
|
+
basic_tree.send(:parent=, self)
|
35
|
+
kids << basic_tree
|
36
|
+
end
|
37
|
+
|
38
|
+
# TODO: self
|
39
|
+
def remove!(basic_tree)
|
40
|
+
raise ArgumentError, "Must be a #{self.class}" unless basic_tree.is_a?(self.class)
|
41
|
+
raise StandardError, "Can't remove root" if root?
|
42
|
+
parent.send(:kids).delete(self)
|
43
|
+
basic_tree.send(:parent=, nil)
|
44
|
+
end
|
45
|
+
|
46
|
+
# TODO: test
|
47
|
+
def move_up!
|
48
|
+
raise "Already first" if first?
|
49
|
+
parent.send(:kids).swap!(position, position - 1)
|
50
|
+
end
|
51
|
+
|
52
|
+
# TODO: test
|
53
|
+
def move_down!
|
54
|
+
raise "Already last" if last?
|
55
|
+
parent.send(:kids).swap!(position, position + 1)
|
56
|
+
end
|
57
|
+
|
58
|
+
##################################################
|
59
|
+
|
60
|
+
def children
|
61
|
+
kids.dup
|
20
62
|
end
|
21
63
|
|
22
64
|
def path
|
@@ -28,17 +70,28 @@ class BasicTree
|
|
28
70
|
end
|
29
71
|
|
30
72
|
def descendants
|
31
|
-
|
73
|
+
d = []
|
74
|
+
kids.each { |k| d += k.descendants.unshift(k) }
|
75
|
+
d
|
32
76
|
end
|
33
77
|
|
34
78
|
def subtree
|
35
|
-
|
79
|
+
descendants.unshift(self)
|
80
|
+
end
|
81
|
+
|
82
|
+
def siblings_and_self
|
83
|
+
root? ? [self] : parent.children
|
36
84
|
end
|
37
85
|
|
38
86
|
def siblings
|
39
|
-
root? ? [] :
|
87
|
+
root? ? [] : siblings_and_self.delete_if { |s| s == self }
|
40
88
|
end
|
41
89
|
|
90
|
+
##################################################
|
91
|
+
|
92
|
+
attr_reader :parent
|
93
|
+
attr_accessor :object
|
94
|
+
|
42
95
|
def root
|
43
96
|
path.first
|
44
97
|
end
|
@@ -47,16 +100,37 @@ class BasicTree
|
|
47
100
|
path.size
|
48
101
|
end
|
49
102
|
|
103
|
+
def position
|
104
|
+
siblings_and_self.index(self)
|
105
|
+
end
|
106
|
+
|
107
|
+
##################################################
|
108
|
+
|
50
109
|
def root?
|
51
110
|
!parent
|
52
111
|
end
|
53
112
|
|
54
113
|
def leaf?
|
55
|
-
|
114
|
+
kids.empty?
|
56
115
|
end
|
57
116
|
|
58
|
-
def
|
59
|
-
|
117
|
+
def first?
|
118
|
+
root? || siblings_and_self[0] == self
|
119
|
+
end
|
120
|
+
|
121
|
+
def last?
|
122
|
+
root? || siblings_and_self.last == self
|
123
|
+
end
|
124
|
+
|
125
|
+
##################################################
|
126
|
+
private
|
127
|
+
|
128
|
+
attr_writer :parent
|
129
|
+
|
130
|
+
def kids
|
131
|
+
@kids ||= Kids.new
|
60
132
|
end
|
61
133
|
|
62
|
-
end
|
134
|
+
end
|
135
|
+
|
136
|
+
require 'basic_tree/version'
|
data/spec/lib/basic_tree_spec.rb
CHANGED
@@ -16,74 +16,137 @@ describe BasicTree do
|
|
16
16
|
@a12 = @a1.children[1]
|
17
17
|
end
|
18
18
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
@a2.path.should == [@a, @a2]
|
25
|
-
end
|
19
|
+
describe "instance methods" do
|
20
|
+
before do
|
21
|
+
@object = "soccer"
|
22
|
+
@bt = BasicTree.new(@object)
|
23
|
+
end
|
26
24
|
|
27
|
-
|
28
|
-
|
29
|
-
@a1.ancestors.should == [@a]
|
30
|
-
@a11.ancestors.should == [@a, @a1]
|
31
|
-
@a12.ancestors.should == [@a, @a1]
|
32
|
-
@a2.ancestors.should == [@a]
|
33
|
-
end
|
25
|
+
describe "#leaf?" do
|
26
|
+
context("with no children") { it { @bt.should be_leaf } }
|
34
27
|
|
35
|
-
|
36
|
-
|
37
|
-
@a1.descendants.should == [@a11, @a12]
|
38
|
-
@a11.descendants.should == []
|
39
|
-
@a12.descendants.should == []
|
40
|
-
@a2.descendants.should == []
|
41
|
-
end
|
28
|
+
context("with children") do
|
29
|
+
before { @bt.add("ball") }
|
42
30
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
@a11.subtree.should == [@a11]
|
47
|
-
@a12.subtree.should == [@a12]
|
48
|
-
@a2.subtree.should == [@a2]
|
49
|
-
end
|
31
|
+
it { @bt.should_not be_leaf }
|
32
|
+
end
|
33
|
+
end
|
50
34
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
@a2.siblings.should == [@a1]
|
57
|
-
end
|
35
|
+
describe "#root?" do
|
36
|
+
context("with no parent") { it { @bt.should be_root } }
|
37
|
+
|
38
|
+
context("as a child") do
|
39
|
+
before { BasicTree.new("sport").add(@bt) }
|
58
40
|
|
59
|
-
|
60
|
-
|
61
|
-
m.root.should == @a
|
41
|
+
it { @bt.should_not be_root }
|
42
|
+
end
|
62
43
|
end
|
63
|
-
end
|
64
44
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
end
|
45
|
+
describe "#level" do
|
46
|
+
it "returns the size of the path" do
|
47
|
+
@bt.stub!(:path => 13.times.map(&:to_i))
|
48
|
+
@bt.level.should eq(13)
|
49
|
+
end
|
50
|
+
end
|
72
51
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
52
|
+
describe "#root" do
|
53
|
+
it "returns the first item in the path" do
|
54
|
+
@bt.stub!(:path => [3, 2])
|
55
|
+
@bt.root.should eq(3)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe "#path" do
|
60
|
+
it "returns the ancestors and itself" do
|
61
|
+
@bt.stub!(:ancestors => [3, 4])
|
62
|
+
@bt.path.should eq([3, 4, @bt])
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
describe "#ancestors" do
|
67
|
+
context("when root") do
|
68
|
+
it("returns empty array") { @bt.ancestors.should eq([]) }
|
69
|
+
end
|
70
|
+
|
71
|
+
context "when not root" do
|
72
|
+
before { BasicTree.new("Fun Stuff").add("Sports").add(@bt) }
|
73
|
+
|
74
|
+
it "returns parent's path" do
|
75
|
+
@bt.ancestors.should eq(@bt.parent.path)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
describe "#children" do
|
81
|
+
context "with none" do
|
82
|
+
it "returns empty array" do
|
83
|
+
@bt.children.should eq([])
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
context "with some" do
|
88
|
+
before do
|
89
|
+
@c1 = @bt.add("c1")
|
90
|
+
@c2 = @bt.add("c2")
|
91
|
+
end
|
92
|
+
|
93
|
+
it "returns them" do
|
94
|
+
@bt.children.should eq([@c1, @c2])
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
describe "#descendants" do
|
100
|
+
context "with no children" do
|
101
|
+
it { @bt.descendants.should eq([]) }
|
102
|
+
end
|
103
|
+
|
104
|
+
context "when children exist, and some of them have children" do
|
105
|
+
before do
|
106
|
+
@ball = @bt.add("ball")
|
107
|
+
@size = @ball.add("size")
|
108
|
+
@four = @size.add("4")
|
109
|
+
@goal = @bt.add("goal")
|
110
|
+
end
|
111
|
+
|
112
|
+
it "returns array" do
|
113
|
+
@bt.descendants.should eq([@ball, @size, @four, @goal])
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
80
117
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
118
|
+
describe "#subtree" do
|
119
|
+
before do
|
120
|
+
@result = [1, 2, 3]
|
121
|
+
@bt.stub!(:descendants => @result)
|
122
|
+
end
|
123
|
+
|
124
|
+
it "should add itself to the front of descendants" do
|
125
|
+
@bt.descendants.should_receive(:unshift).with(@bt)
|
126
|
+
@bt.subtree
|
127
|
+
end
|
128
|
+
|
129
|
+
it { @bt.subtree.should eq(@result) }
|
130
|
+
end
|
131
|
+
|
132
|
+
describe "#siblings" do
|
133
|
+
context "when root" do
|
134
|
+
it { @bt.siblings.should eq([]) }
|
135
|
+
end
|
136
|
+
|
137
|
+
context "when not root" do
|
138
|
+
before do
|
139
|
+
@k1 = mock(BasicTree)
|
140
|
+
@k2 = mock(BasicTree)
|
141
|
+
|
142
|
+
@bt.stub!(:parent => mock(BasicTree, :children => [@k1, @bt, @k2]))
|
143
|
+
end
|
144
|
+
|
145
|
+
it "returns parent's children (without itself)" do
|
146
|
+
@bt.siblings.should eq([@k1, @k2])
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
87
150
|
end
|
88
151
|
|
89
152
|
end
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 1
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
version: 1.0.
|
8
|
+
- 1
|
9
|
+
version: 1.0.1
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Austin Schneider
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date:
|
17
|
+
date: 2011-03-09 00:00:00 -05:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -23,13 +23,45 @@ dependencies:
|
|
23
23
|
requirement: &id001 !ruby/object:Gem::Requirement
|
24
24
|
none: false
|
25
25
|
requirements:
|
26
|
-
- -
|
26
|
+
- - ~>
|
27
27
|
- !ruby/object:Gem::Version
|
28
28
|
segments:
|
29
29
|
- 2
|
30
|
-
|
30
|
+
- 5
|
31
|
+
- 0
|
32
|
+
version: 2.5.0
|
31
33
|
type: :development
|
32
34
|
version_requirements: *id001
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: i18n
|
37
|
+
prerelease: false
|
38
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ~>
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
segments:
|
44
|
+
- 0
|
45
|
+
- 5
|
46
|
+
- 0
|
47
|
+
version: 0.5.0
|
48
|
+
type: :runtime
|
49
|
+
version_requirements: *id002
|
50
|
+
- !ruby/object:Gem::Dependency
|
51
|
+
name: activesupport
|
52
|
+
prerelease: false
|
53
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
54
|
+
none: false
|
55
|
+
requirements:
|
56
|
+
- - ~>
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
segments:
|
59
|
+
- 3
|
60
|
+
- 0
|
61
|
+
- 5
|
62
|
+
version: 3.0.5
|
63
|
+
type: :runtime
|
64
|
+
version_requirements: *id003
|
33
65
|
description: A basic tree structure.
|
34
66
|
email:
|
35
67
|
- soccer022483@gmail.com
|
@@ -40,6 +72,7 @@ extensions: []
|
|
40
72
|
extra_rdoc_files: []
|
41
73
|
|
42
74
|
files:
|
75
|
+
- .gemtest
|
43
76
|
- .gitignore
|
44
77
|
- .rspec
|
45
78
|
- .rvmrc
|
@@ -50,6 +83,7 @@ files:
|
|
50
83
|
- Rakefile
|
51
84
|
- basic_tree.gemspec
|
52
85
|
- lib/basic_tree.rb
|
86
|
+
- lib/basic_tree/version.rb
|
53
87
|
- spec/lib/basic_tree_spec.rb
|
54
88
|
- spec/spec_helper.rb
|
55
89
|
has_rdoc: true
|
@@ -84,5 +118,6 @@ rubygems_version: 1.3.7
|
|
84
118
|
signing_key:
|
85
119
|
specification_version: 3
|
86
120
|
summary: A basic tree structure.
|
87
|
-
test_files:
|
88
|
-
|
121
|
+
test_files:
|
122
|
+
- spec/lib/basic_tree_spec.rb
|
123
|
+
- spec/spec_helper.rb
|