basic_tree 1.0.0 → 1.0.1

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/.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.1.1)
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
- rspec (2.3.0)
11
- rspec-core (~> 2.3.0)
12
- rspec-expectations (~> 2.3.0)
13
- rspec-mocks (~> 2.3.0)
14
- rspec-core (2.3.1)
15
- rspec-expectations (2.3.0)
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.3.0)
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 (>= 2)
28
+ rspec (~> 2.5.0)
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2009 Austin Schneider
1
+ Copyright (c) 2010 Austin Schneider
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
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.children[1]
22
- banana.object
23
- # "Banana"
21
+ banana = fruit.get(2) # get the 2nd fruit
22
+ banana.object # "Banana"
24
23
 
25
- plantain = banana.children[1]
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
- Copyright (c) 2010 Austin Schneider. See LICENSE for details.
68
+ See LICENSE for details.
data/Rakefile CHANGED
@@ -1,3 +1,8 @@
1
1
  require 'bundler'
2
2
 
3
- Bundler::GemHelper.install_tasks
3
+ Bundler::GemHelper.install_tasks
4
+
5
+ desc "Run tests"
6
+ task :test do
7
+ system 'rspec spec'
8
+ end
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', ">= 2"
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
@@ -0,0 +1,5 @@
1
+ class BasicTree
2
+
3
+ VERSION = "1.0.1"
4
+
5
+ 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
- VERSION = "1.0.0"
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
- if parent
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
- attr_accessor :object, :parent
17
-
22
+ # TODO: test
18
23
  def add(object, &block)
19
- self.class.new(object, self, &block)
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
- children.map { |c| [c] + c.descendants }.flatten
73
+ d = []
74
+ kids.each { |k| d += k.descendants.unshift(k) }
75
+ d
32
76
  end
33
77
 
34
78
  def subtree
35
- [self] + descendants
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? ? [] : parent.children.select { |child| child != self }
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
- children.empty?
114
+ kids.empty?
56
115
  end
57
116
 
58
- def children
59
- @children ||= []
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'
@@ -16,74 +16,137 @@ describe BasicTree do
16
16
  @a12 = @a1.children[1]
17
17
  end
18
18
 
19
- it "path" do
20
- @a.path.should == [@a]
21
- @a1.path.should == [@a, @a1]
22
- @a11.path.should == [@a, @a1, @a11]
23
- @a12.path.should == [@a, @a1, @a12]
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
- it "ancestors" do
28
- @a.ancestors.should == []
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
- it "descendants" do
36
- @a.descendants.should == [@a1, @a11, @a12, @a2]
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
- it "subtree" do
44
- @a.subtree.should == [@a, @a1, @a11, @a12, @a2]
45
- @a1.subtree.should == [@a1, @a11, @a12]
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
- it "siblings" do
52
- @a.siblings.should == []
53
- @a1.siblings.should == [@a2]
54
- @a11.siblings.should == [@a12]
55
- @a12.siblings.should == [@a11]
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
- it "root" do
60
- [@a, @a1, @a11, @a12, @a2].each do |m|
61
- m.root.should == @a
41
+ it { @bt.should_not be_root }
42
+ end
62
43
  end
63
- end
64
44
 
65
- it "level" do
66
- @a.level.should == 1
67
- @a1.level.should == 2
68
- @a11.level.should == 3
69
- @a12.level.should == 3
70
- @a2.level.should == 2
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
- it "root?" do
74
- @a.root?.should be_true
75
- @a1.root?.should be_false
76
- @a11.root?.should be_false
77
- @a12.root?.should be_false
78
- @a2.root?.should be_false
79
- end
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
- it "leaf?" do
82
- @a.leaf?.should be_false
83
- @a1.leaf?.should be_false
84
- @a11.leaf?.should be_true
85
- @a12.leaf?.should be_true
86
- @a2.leaf?.should be_true
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
- - 0
9
- version: 1.0.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: 2010-12-21 00:00:00 -05:00
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
- version: "2"
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