datamapper 0.2.5 → 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.
Files changed (121) hide show
  1. data/CHANGELOG +5 -1
  2. data/FAQ +96 -0
  3. data/QUICKLINKS +12 -0
  4. data/README +57 -155
  5. data/environment.rb +61 -43
  6. data/example.rb +30 -12
  7. data/lib/data_mapper.rb +6 -1
  8. data/lib/data_mapper/adapters/abstract_adapter.rb +0 -57
  9. data/lib/data_mapper/adapters/data_object_adapter.rb +203 -97
  10. data/lib/data_mapper/adapters/mysql_adapter.rb +4 -0
  11. data/lib/data_mapper/adapters/postgresql_adapter.rb +7 -1
  12. data/lib/data_mapper/adapters/sql/coersion.rb +3 -2
  13. data/lib/data_mapper/adapters/sql/commands/load_command.rb +29 -10
  14. data/lib/data_mapper/adapters/sql/mappings/associations_set.rb +4 -0
  15. data/lib/data_mapper/adapters/sql/mappings/column.rb +13 -9
  16. data/lib/data_mapper/adapters/sql/mappings/conditions.rb +172 -0
  17. data/lib/data_mapper/adapters/sql/mappings/table.rb +43 -17
  18. data/lib/data_mapper/adapters/sqlite3_adapter.rb +9 -2
  19. data/lib/data_mapper/associations.rb +75 -3
  20. data/lib/data_mapper/associations/belongs_to_association.rb +70 -36
  21. data/lib/data_mapper/associations/has_and_belongs_to_many_association.rb +195 -86
  22. data/lib/data_mapper/associations/has_many_association.rb +168 -61
  23. data/lib/data_mapper/associations/has_n_association.rb +23 -3
  24. data/lib/data_mapper/attributes.rb +73 -0
  25. data/lib/data_mapper/auto_migrations.rb +2 -6
  26. data/lib/data_mapper/base.rb +5 -9
  27. data/lib/data_mapper/database.rb +4 -3
  28. data/lib/data_mapper/embedded_value.rb +66 -30
  29. data/lib/data_mapper/identity_map.rb +1 -3
  30. data/lib/data_mapper/is/tree.rb +121 -0
  31. data/lib/data_mapper/migration.rb +155 -0
  32. data/lib/data_mapper/persistence.rb +532 -218
  33. data/lib/data_mapper/property.rb +306 -0
  34. data/lib/data_mapper/query.rb +164 -0
  35. data/lib/data_mapper/support/blank.rb +2 -2
  36. data/lib/data_mapper/support/connection_pool.rb +5 -6
  37. data/lib/data_mapper/support/enumerable.rb +3 -3
  38. data/lib/data_mapper/support/errors.rb +10 -1
  39. data/lib/data_mapper/support/inflector.rb +174 -238
  40. data/lib/data_mapper/support/object.rb +54 -0
  41. data/lib/data_mapper/support/serialization.rb +19 -1
  42. data/lib/data_mapper/support/string.rb +7 -16
  43. data/lib/data_mapper/support/symbol.rb +3 -15
  44. data/lib/data_mapper/support/typed_set.rb +68 -0
  45. data/lib/data_mapper/types/base.rb +44 -0
  46. data/lib/data_mapper/types/string.rb +34 -0
  47. data/lib/data_mapper/validations/number_validator.rb +40 -0
  48. data/lib/data_mapper/validations/string_validator.rb +20 -0
  49. data/lib/data_mapper/validations/validator.rb +13 -0
  50. data/performance.rb +26 -1
  51. data/profile_data_mapper.rb +1 -1
  52. data/rakefile.rb +42 -2
  53. data/spec/acts_as_tree_spec.rb +11 -3
  54. data/spec/adapters/data_object_adapter_spec.rb +31 -0
  55. data/spec/associations/belongs_to_association_spec.rb +98 -0
  56. data/spec/associations/has_and_belongs_to_many_association_spec.rb +377 -0
  57. data/spec/associations/has_many_association_spec.rb +337 -0
  58. data/spec/attributes_spec.rb +23 -1
  59. data/spec/auto_migrations_spec.rb +86 -29
  60. data/spec/callbacks_spec.rb +107 -0
  61. data/spec/column_spec.rb +5 -2
  62. data/spec/count_command_spec.rb +33 -1
  63. data/spec/database_spec.rb +18 -0
  64. data/spec/dependency_spec.rb +4 -2
  65. data/spec/embedded_value_spec.rb +8 -8
  66. data/spec/fixtures/people.yaml +1 -1
  67. data/spec/fixtures/projects.yaml +10 -1
  68. data/spec/fixtures/tasks.yaml +6 -0
  69. data/spec/fixtures/tasks_tasks.yaml +2 -0
  70. data/spec/fixtures/tomatoes.yaml +1 -0
  71. data/spec/is_a_tree_spec.rb +149 -0
  72. data/spec/load_command_spec.rb +71 -9
  73. data/spec/magic_columns_spec.rb +17 -2
  74. data/spec/migration_spec.rb +267 -0
  75. data/spec/models/animal.rb +1 -1
  76. data/spec/models/candidate.rb +8 -0
  77. data/spec/models/career.rb +1 -1
  78. data/spec/models/chain.rb +8 -0
  79. data/spec/models/comment.rb +1 -1
  80. data/spec/models/exhibit.rb +1 -1
  81. data/spec/models/fence.rb +7 -0
  82. data/spec/models/fruit.rb +2 -2
  83. data/spec/models/job.rb +8 -0
  84. data/spec/models/person.rb +2 -3
  85. data/spec/models/post.rb +1 -1
  86. data/spec/models/project.rb +21 -1
  87. data/spec/models/section.rb +1 -1
  88. data/spec/models/serializer.rb +1 -1
  89. data/spec/models/task.rb +9 -0
  90. data/spec/models/tomato.rb +27 -0
  91. data/spec/models/user.rb +8 -2
  92. data/spec/models/zoo.rb +2 -7
  93. data/spec/paranoia_spec.rb +1 -1
  94. data/spec/{base_spec.rb → persistence_spec.rb} +207 -18
  95. data/spec/postgres_spec.rb +48 -6
  96. data/spec/property_spec.rb +90 -9
  97. data/spec/query_spec.rb +71 -5
  98. data/spec/save_command_spec.rb +11 -0
  99. data/spec/spec_helper.rb +14 -11
  100. data/spec/support/blank_spec.rb +8 -0
  101. data/spec/support/inflector_spec.rb +41 -0
  102. data/spec/support/object_spec.rb +9 -0
  103. data/spec/{serialization_spec.rb → support/serialization_spec.rb} +1 -1
  104. data/spec/support/silence_spec.rb +15 -0
  105. data/spec/{support_spec.rb → support/string_spec.rb} +3 -3
  106. data/spec/support/struct_spec.rb +12 -0
  107. data/spec/support/typed_set_spec.rb +66 -0
  108. data/spec/table_spec.rb +3 -3
  109. data/spec/types/string.rb +81 -0
  110. data/spec/validates_uniqueness_of_spec.rb +17 -0
  111. data/spec/validations/number_validator.rb +59 -0
  112. data/spec/validations/string_validator.rb +14 -0
  113. metadata +59 -17
  114. data/do_performance.rb +0 -153
  115. data/lib/data_mapper/support/active_record_impersonation.rb +0 -103
  116. data/lib/data_mapper/support/weak_hash.rb +0 -46
  117. data/spec/active_record_impersonation_spec.rb +0 -129
  118. data/spec/associations_spec.rb +0 -232
  119. data/spec/conditions_spec.rb +0 -49
  120. data/spec/has_many_association_spec.rb +0 -173
  121. data/spec/models/animals_exhibit.rb +0 -8
@@ -76,4 +76,111 @@ describe DataMapper::Callbacks do
76
76
  post.instance_variable_get("@three").should eql('blue_cow')
77
77
  end
78
78
 
79
+ it "should execute materialization callbacks" do
80
+
81
+ $before_materialize = 0
82
+ $after_materialize = 0
83
+
84
+ Zoo.before_materialize do
85
+ $before_materialize += 1
86
+ end
87
+
88
+ Zoo.after_materialize do
89
+ $after_materialize += 1
90
+ end
91
+
92
+ class Zoo
93
+
94
+ # This syntax doesn't work in DM.
95
+ # Which I don't think is necessarily a bad thing...
96
+ # Just FYI -Sam
97
+ def before_materialize
98
+ $before_materialize += 1
99
+ end
100
+
101
+ def call_before_materialize
102
+ $before_materialize += 1
103
+ end
104
+
105
+ # Example of invalid syntax
106
+ def after_materialize
107
+ $after_materialize += 1
108
+ end
109
+
110
+ def call_after_materialize
111
+ $after_materialize += 1
112
+ end
113
+
114
+ end
115
+
116
+ Zoo.before_materialize :call_before_materialize
117
+ Zoo.after_materialize :call_after_materialize
118
+
119
+ Zoo.before_materialize "$before_materialize += 1"
120
+ Zoo.after_materialize "$after_materialize += 1"
121
+
122
+ Zoo.first
123
+
124
+ $before_materialize.should == 3
125
+ $after_materialize.should == 3
126
+
127
+ Zoo[1]
128
+
129
+ $before_materialize.should == 6
130
+ $after_materialize.should == 6
131
+
132
+ end
133
+
134
+ it "should execute creation callbacks" do
135
+
136
+ $before_create = 0
137
+ $after_create = 0
138
+
139
+ Zoo.before_create do
140
+ $before_create += 1
141
+ end
142
+
143
+ Zoo.after_create do
144
+ $after_create += 1
145
+ end
146
+
147
+ class Zoo
148
+
149
+ # Example of invalid syntax
150
+ def before_create
151
+ $before_create += 1
152
+ end
153
+
154
+ def call_before_create
155
+ $before_create += 1
156
+ end
157
+
158
+ # Example of invalid syntax
159
+ def after_create
160
+ $after_create += 1
161
+ end
162
+
163
+ def call_after_create
164
+ $after_create += 1
165
+ end
166
+
167
+ end
168
+
169
+ Zoo.before_create :call_before_create
170
+ Zoo.after_create :call_after_create
171
+
172
+ Zoo.before_create "$before_create += 1"
173
+ Zoo.after_create "$after_create += 1"
174
+
175
+ Zoo.create(:name => 'bob')
176
+
177
+ $before_create.should == 3
178
+ $after_create.should == 3
179
+
180
+ Zoo.new(:name => 'bob2').save
181
+
182
+ $before_create.should == 6
183
+ $after_create.should == 6
184
+ end
185
+
79
186
  end
@@ -46,13 +46,13 @@ describe DataMapper::Adapters::Sql::Mappings::Column do
46
46
  lambda { database.query("SELECT name FROM zoos") }.should_not raise_error
47
47
  lambda { database.query("SELECT moo FROM zoos") }.should raise_error
48
48
 
49
- name_column.rename!(:moo).should eql(true)
49
+ name_column = name_column.rename!(:moo)
50
50
  name_column.name.should eql(:moo)
51
51
 
52
52
  lambda { database.query("SELECT name FROM zoos") }.should raise_error
53
53
  lambda { database.query("SELECT moo FROM zoos") }.should_not raise_error
54
54
 
55
- name_column.rename!(:name)
55
+ name_column = name_column.rename!(:name)
56
56
  name_column.name.should eql(:name)
57
57
 
58
58
  lambda { database.query("SELECT name FROM zoos") }.should_not raise_error
@@ -88,6 +88,7 @@ describe DataMapper::Adapters::Sql::Mappings::Column do
88
88
 
89
89
  Zoo.send(:undef_method, :moo)
90
90
  Zoo.send(:undef_method, :moo=)
91
+ Zoo.properties.delete_if { |x| x.name == :moo }
91
92
 
92
93
  lambda { database.query("SELECT moo FROM zoos") }.should raise_error
93
94
  end
@@ -100,6 +101,8 @@ describe DataMapper::Adapters::Sql::Mappings::Column do
100
101
  it "should be able to create a column with unique index" do
101
102
  column = table.add_column("name", :string, :index => :unique)
102
103
  column.unique?.should be_true
104
+ column.index?.should be_nil
105
+ table.to_create_index_sql.should == []
103
106
  table.to_create_sql.should match(/UNIQUE/)
104
107
  end
105
108
 
@@ -1,13 +1,45 @@
1
1
  require File.dirname(__FILE__) + "/spec_helper"
2
2
 
3
- describe DataMapper::Adapters::AbstractAdapter do
3
+ describe DataMapper::Adapters::AbstractAdapter, "count()" do
4
4
 
5
5
  before(:all) do
6
6
  fixtures(:zoos)
7
+ fixtures(:projects)
7
8
  end
8
9
 
9
10
  it "should return a count of the selected table" do
10
11
  Zoo.count.should be_a_kind_of(Integer)
11
12
  Zoo.count.should == Zoo.all.size
12
13
  end
14
+
15
+ it "should accept finder style options" do
16
+ # Hash-style (with SymbolOperators)
17
+ Zoo.count(:name => 'Dallas').should == Zoo.all(:name => 'Dallas').length
18
+ Zoo.count(:name.not => nil).should == Zoo.all(:name.not => nil).length
19
+ Zoo.count(:name.not => nil, :notes => nil).should == Zoo.all(:name.not => nil, :notes => nil).length
20
+ Zoo.count(:name.like => '%.%').should == Zoo.all(:name.like => '%.%').length
21
+
22
+ # :conditions
23
+ Zoo.count(:conditions => ["name = ?", 'Dallas']).should == Zoo.all(:conditions => ["name = ?", 'Dallas']).length
24
+
25
+ # mix and match
26
+ Zoo.count(:notes => nil, :conditions => ["name = ?", 'Dallas']).should == Zoo.all(:notes => nil, :conditions => ["name = ?", 'Dallas']).length
27
+ end
28
+
29
+ it "should respect paranoia" do
30
+ p = Project[3]
31
+ p.destroy!
32
+
33
+ Project.count.should == Project.all.length
34
+ # clean up
35
+ p.deleted_at = nil
36
+ p.save
37
+ end
38
+
39
+ #This won't work at the moment, hopefully before 0.3.0
40
+ it "should do distinct counting" do
41
+ #Zoo.count(:distinct => :name).should == Zoo.all.length # there all distinct in the fixtures
42
+ #Zoo.count(:distinct => :name, :notes.not => nil).should == Zoo.all(:notes.not => nil).length
43
+ #Zoo.count(:distinct => :name, :conditions => ["notes is not null"]).should == Zoo.all(:notes.not => nil).length
44
+ end
13
45
  end
@@ -0,0 +1,18 @@
1
+ require File.dirname(__FILE__) + "/spec_helper"
2
+
3
+ describe('Multiple Databases') do
4
+
5
+ it "should scope model creation and lookup" do
6
+ database(:secondary) do
7
+ Zoo.create :name => 'secondary'
8
+ end
9
+
10
+ Zoo.first(:name => 'secondary').should be_nil
11
+
12
+ database(:secondary) do
13
+ Zoo.first(:name => 'secondary').should_not be_nil
14
+ Zoo.first(:name => 'secondary').destroy!
15
+ end
16
+ end
17
+
18
+ end
@@ -1,6 +1,8 @@
1
1
  require File.dirname(__FILE__) + "/spec_helper"
2
2
 
3
- describe DataMapper::Persistence do
3
+ # Can't describe DataMapper::Persistence because
4
+ # rspec will include it for some crazy reason!
5
+ describe "DataMapper::Persistence" do
4
6
 
5
7
  it "should be able to add a dependency for a class not yet defined" do
6
8
 
@@ -12,7 +14,7 @@ describe DataMapper::Persistence do
12
14
  $happy_cow_defined = true
13
15
  end
14
16
 
15
- class HappyCow
17
+ class HappyCow #< DataMapper::Base # please do not remove this
16
18
  include DataMapper::Persistence
17
19
 
18
20
  property :name, :string, :key => true
@@ -19,7 +19,7 @@ describe DataMapper::EmbeddedValue do
19
19
  end
20
20
 
21
21
  it 'should not require prefix' do
22
- class PointyHeadedBoss
22
+ class PointyHeadedBoss #< DataMapper::Base # please do not remove this
23
23
  include DataMapper::Persistence
24
24
 
25
25
  set_table_name 'people'
@@ -38,7 +38,7 @@ describe DataMapper::EmbeddedValue do
38
38
  end
39
39
 
40
40
  it 'should add convenience methods to the non-embedded base' do
41
- class Employee
41
+ class Employee #< DataMapper::Base # please do not remove this
42
42
  include DataMapper::Persistence
43
43
 
44
44
  set_table_name 'people'
@@ -55,7 +55,7 @@ describe DataMapper::EmbeddedValue do
55
55
  end
56
56
 
57
57
  it 'should support lazy loading of embedded properties' do
58
- class Human
58
+ class Human #< DataMapper::Base # please do not remove this
59
59
  include DataMapper::Persistence
60
60
 
61
61
  set_table_name 'people'
@@ -72,7 +72,7 @@ describe DataMapper::EmbeddedValue do
72
72
  end
73
73
 
74
74
  it 'should default to public method visibility for all' do
75
- class SoftwareEngineer
75
+ class SoftwareEngineer #< DataMapper::Base # please do not remove this
76
76
  include DataMapper::Persistence
77
77
 
78
78
  set_table_name 'people'
@@ -89,7 +89,7 @@ describe DataMapper::EmbeddedValue do
89
89
  end
90
90
 
91
91
  it 'should respect protected property options for all' do
92
- class SanitationEngineer
92
+ class SanitationEngineer #< DataMapper::Base # please do not remove this
93
93
  include DataMapper::Persistence
94
94
 
95
95
  set_table_name 'people'
@@ -107,7 +107,7 @@ describe DataMapper::EmbeddedValue do
107
107
  end
108
108
 
109
109
  it 'should respect private property options for all' do
110
- class ElectricalEngineer
110
+ class ElectricalEngineer #< DataMapper::Base # please do not remove this
111
111
  include DataMapper::Persistence
112
112
 
113
113
  set_table_name 'people'
@@ -125,7 +125,7 @@ describe DataMapper::EmbeddedValue do
125
125
  end
126
126
 
127
127
  it 'should set both reader and writer visibiliy for all when accessor option is passed' do
128
- class TrainEngineer
128
+ class TrainEngineer #< DataMapper::Base # please do not remove this
129
129
  include DataMapper::Persistence
130
130
 
131
131
  set_table_name 'people'
@@ -142,7 +142,7 @@ describe DataMapper::EmbeddedValue do
142
142
  end
143
143
 
144
144
  it 'should allow individual properties to override method visibility options passed on the block' do
145
- class ChemicalEngineer
145
+ class ChemicalEngineer #< DataMapper::Base # please do not remove this
146
146
  include DataMapper::Persistence
147
147
 
148
148
  set_table_name 'people'
@@ -31,7 +31,7 @@
31
31
  address_street: 123 Happy Ln.
32
32
  address_city: Dallas
33
33
  address_state: TX
34
- address_zip_code: 75000
34
+ address_zip_code: "75000"
35
35
  type: SalesPerson
36
36
  commission: 40
37
37
  career_name: Peon
@@ -1,4 +1,13 @@
1
1
  ---
2
2
  - id: 1
3
3
  title: Test
4
- description:
4
+ description: test
5
+ - id: 2
6
+ title: The Empire State Building
7
+ description: "The Empire State Building is a 102-story Art Deco skyscraper in New York City, New York"
8
+ - id: 3
9
+ title: World Trade Center
10
+ description: "The World Trade Center in New York City, United States"
11
+ - id: 4
12
+ title: The Statue Of Liberty
13
+ description: "Liberty Enlightening the World (French: La liberte eclairant le monde), known more commonly as the Statue of Liberty"
@@ -0,0 +1,6 @@
1
+ - name: task_relax
2
+ notes: I am the relaxed task an should be related to task_vacation
3
+ - name: task_drink_heartily
4
+ notes: I am the drink heartily task and should be related to task_relax
5
+ - name: task_vacation
6
+ notes: I am the vacation task and should be related to task_relax
@@ -0,0 +1,2 @@
1
+ - task_id: 1
2
+ related_task_id: 2
@@ -0,0 +1 @@
1
+ --- []
@@ -0,0 +1,149 @@
1
+ require File.dirname(__FILE__) + "/spec_helper"
2
+
3
+ class DataMapper::MockBase
4
+ include DataMapper::Is::Tree
5
+ end
6
+
7
+ class DefaultTree < DataMapper::MockBase
8
+ end
9
+
10
+ describe "DataMapper::Is::Tree receiving various is_a_tree configurations" do
11
+ setup do
12
+ DefaultTree.stub!(:has_many)
13
+ DefaultTree.stub!(:belongs_to)
14
+ end
15
+
16
+ it "should setup a belongs_to relationship with the parent with the default configurations" do
17
+ DefaultTree.should_receive(:belongs_to).with(:parent, :foreign_key => "parent_id", :counter_cache => nil,
18
+ :class_name => "DefaultTree")
19
+ DefaultTree.send(:is_a_tree)
20
+ end
21
+
22
+ it "should setup a has_many relationship with the children with default configurations" do
23
+ DefaultTree.should_receive(:has_many).with(:children, :foreign_key => "parent_id", :order => nil,
24
+ :class_name => "DefaultTree")
25
+ DefaultTree.send(:is_a_tree)
26
+ end
27
+
28
+ it "should setup a belongs_to relationship with the correct foreign key" do
29
+ DefaultTree.should_receive(:belongs_to).with(:parent, :foreign_key => "something_id", :counter_cache => nil,
30
+ :class_name => "DefaultTree")
31
+ DefaultTree.send(:is_a_tree, :foreign_key => "something_id")
32
+ end
33
+
34
+ it "should setup a has_many relationship with the children with the correct foreign key" do
35
+ DefaultTree.should_receive(:has_many).with(:children, :foreign_key => "something_id", :order => nil,
36
+ :class_name => "DefaultTree")
37
+ DefaultTree.send(:is_a_tree, :foreign_key => "something_id")
38
+ end
39
+
40
+ it "should setup a has_many relationship with the children with the correct order" do
41
+ DefaultTree.should_receive(:has_many).with(:children, :foreign_key => "parent_id", :order => 'position',
42
+ :class_name => "DefaultTree")
43
+ DefaultTree.send(:is_a_tree, :order => 'position')
44
+ end
45
+ end
46
+
47
+ describe "Default DataMapper::Is::Tree class methods" do
48
+ setup do
49
+ DefaultTree.stub!(:has_many)
50
+ DefaultTree.stub!(:belongs_to)
51
+ DefaultTree.send(:can_has_tree)
52
+ DefaultTree.stub!(:all).and_return([])
53
+ DefaultTree.stub!(:first).and_return(nil)
54
+ end
55
+
56
+ it "should return an empty array for .roots" do
57
+ DefaultTree.roots.should == []
58
+ end
59
+
60
+ it "should find with the correct options on .roots" do
61
+ DefaultTree.should_receive(:all).with(:parent_id => nil, :order => nil)
62
+ DefaultTree.roots
63
+ end
64
+
65
+ it "should return nil for .first_root" do
66
+ DefaultTree.root.should be_nil
67
+ end
68
+
69
+ it "should find with the correct options on .first_root" do
70
+ DefaultTree.should_receive(:first).with(:parent_id => nil, :order => nil)
71
+ DefaultTree.first_root
72
+ end
73
+ end
74
+
75
+ describe "Configured DataMapper::Is::Tree class methods" do
76
+ setup do
77
+ DefaultTree.stub!(:has_many)
78
+ DefaultTree.stub!(:belongs_to)
79
+ DefaultTree.send(:can_has_tree, :foreign_key => 'mew_id', :order => 'mew')
80
+ DefaultTree.stub!(:all).and_return([])
81
+ DefaultTree.stub!(:first).and_return(nil)
82
+ end
83
+
84
+ it "should return an empty array for .roots" do
85
+ DefaultTree.roots.should == []
86
+ end
87
+
88
+ it "should find with the correct options on .roots" do
89
+ DefaultTree.should_receive(:all).with(:mew_id => nil, :order => 'mew')
90
+ DefaultTree.roots
91
+ end
92
+
93
+ it "should return nil for .first_root" do
94
+ DefaultTree.root.should be_nil
95
+ end
96
+
97
+ it "should find with the correct options on .first_root" do
98
+ DefaultTree.should_receive(:first).with(:mew_id => nil, :order => 'mew')
99
+ DefaultTree.first_root
100
+ end
101
+ end
102
+
103
+ describe "Default DataMapper::Is::Tree instance methods" do
104
+ setup do
105
+ DefaultTree.stub!(:has_many)
106
+ DefaultTree.stub!(:belongs_to)
107
+ DefaultTree.send(:is_a_tree)
108
+ @root = DefaultTree.new
109
+ @child = DefaultTree.new
110
+ @grandchild1 = DefaultTree.new
111
+ @grandchild2 = DefaultTree.new
112
+
113
+ # Mocking the belongs_to & has_many relationships (part of the not-needing-a-db-to-test plan)
114
+ @root.stub!(:parent).and_return nil
115
+ @child.stub!(:parent).and_return @root
116
+ @grandchild1.stub!(:parent).and_return(@child)
117
+ @grandchild2.stub!(:parent).and_return(@child)
118
+ @child.stub!(:children).and_return([@grandchild1, @grandchild2])
119
+ @root.stub!(:children).and_return([@child])
120
+ @grandchild1.stub!(:children).and_return []
121
+ @grandchild2.stub!(:children).and_return []
122
+ end
123
+
124
+ it "should return an array of parents, furthest parent first, for #ancestors" do
125
+ @grandchild1.ancestors.should == [@root, @child]
126
+ end
127
+
128
+ it "should return an array of siblings for #siblings" do
129
+ @grandchild1.siblings.should == [@grandchild2]
130
+ end
131
+
132
+ it "should return all children of the node's parent for #generation" do
133
+ @grandchild1.generation.should == [@grandchild1, @grandchild2]
134
+ end
135
+
136
+ it "should return roots on #generation when there is no parent" do
137
+ DefaultTree.should_receive(:roots).and_return [@root]
138
+ @root.generation.should == [@root]
139
+ end
140
+
141
+ it "should return the top-most parent on #root" do
142
+ @grandchild1.root.should == @root
143
+ end
144
+
145
+ it "should return self on #root if self has no parent" do
146
+ @root.root.should == @root
147
+ end
148
+
149
+ end