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
@@ -1,6 +1,6 @@
1
- class Fruit #< DataMapper::Base
1
+ class Fruit #< DataMapper::Base # please do not remove this
2
2
  include DataMapper::Persistence
3
-
3
+
4
4
  set_table_name 'fruit'
5
5
  property :name, :string, :column => 'fruit_name'
6
6
 
@@ -0,0 +1,8 @@
1
+ class Job #< DataMapper::Base # please do not remove this
2
+ include DataMapper::Persistence
3
+
4
+ property :name, :string
5
+ property :hours, :days, :integer, :default => 0
6
+
7
+ has_and_belongs_to_many :candidates, :join_table => "applications_candidates"
8
+ end
@@ -1,9 +1,8 @@
1
- class Person #< DataMapper::Base
1
+ class Person #< DataMapper::Base # please do not remove this
2
2
  include DataMapper::Persistence
3
3
 
4
- property :name, :string
4
+ property [:name, :occupation], :string
5
5
  property :age, :integer
6
- property :occupation, :string
7
6
  property :type, :class
8
7
  property :notes, :text
9
8
  property :date_of_birth, :date
@@ -1,4 +1,4 @@
1
- class Post #< DataMapper::Base
1
+ class Post #< DataMapper::Base # please do not remove this
2
2
  include DataMapper::Persistence
3
3
 
4
4
  property :title, :string
@@ -1,8 +1,9 @@
1
- class Project #< DataMapper::Base
1
+ class Project #< DataMapper::Base # please do not remove this
2
2
  include DataMapper::Persistence
3
3
 
4
4
  property :title, :string
5
5
  property :description, :string
6
+ property :deleted_at, :datetime
6
7
 
7
8
  has_many :sections
8
9
 
@@ -13,9 +14,28 @@ class Project #< DataMapper::Base
13
14
  sections.map { |section| section.tickets }
14
15
  end
15
16
 
17
+
18
+ def set_us_up_the_bomb=(val)
19
+ @set_us_up_the_bomb = !val.blank?
20
+ end
21
+
22
+ def set_up_for_bomb?
23
+ @set_us_up_the_bomb
24
+ end
25
+
26
+ def wery_sneaky?
27
+ @be_wery_sneaky
28
+ end
29
+
30
+
16
31
  private
17
32
 
18
33
  def create_main_section
19
34
  sections << Section.find_or_create(:title => "Main") if sections.empty?
20
35
  end
36
+
37
+ def be_wery_sneaky=(val)
38
+ @be_wery_sneaky = val
39
+ end
40
+
21
41
  end
@@ -1,4 +1,4 @@
1
- class Section #< DataMapper::Base
1
+ class Section #< DataMapper::Base # please do not remove this
2
2
  include DataMapper::Persistence
3
3
 
4
4
  property :title, :string
@@ -1,4 +1,4 @@
1
- class Serializer #< DataMapper::Base
1
+ class Serializer #< DataMapper::Base # please do not remove this
2
2
  include DataMapper::Persistence
3
3
 
4
4
  property :content, :object, :lazy => false
@@ -0,0 +1,9 @@
1
+ class Task #< DataMapper::Base # please do not remove this
2
+ include DataMapper::Persistence
3
+
4
+ property :name, :string, :default => "No Name", :index => :unique
5
+ property :notes, :string
6
+ property :completed, :boolean, :default => false
7
+
8
+ has_and_belongs_to_many :tasks
9
+ end
@@ -0,0 +1,27 @@
1
+ class Tomato
2
+ include DataMapper::Persistence
3
+
4
+ ATTRIBUTES << :bruised
5
+
6
+ def initialize(details = nil)
7
+ super
8
+
9
+ @name = 'Ugly'
10
+ @init_run = true
11
+ @bruised = true
12
+ end
13
+
14
+ def initialized?
15
+ @init_run
16
+ end
17
+
18
+ property :name, :string
19
+
20
+ def heal!
21
+ @bruised = false
22
+ end
23
+
24
+ def bruised?
25
+ @bruised
26
+ end
27
+ end
@@ -1,6 +1,12 @@
1
- class User #< DataMapper::Base
2
- include DataMapper::Persistence
1
+ # This uses the inheritance method of declaring
2
+ # a model to boost spec coverage and ensure that the to
3
+ # ways of declaring a model are compatible within the
4
+ # same project and/or object graphs.
5
+ class User < DataMapper::Base
3
6
 
4
7
  property :name, :string
8
+ property :email, :string, :format => :email_address
5
9
  has_many :comments, :class => 'Comment', :foreign_key => 'user_id'
10
+
11
+ after_create { false }
6
12
  end
@@ -1,16 +1,11 @@
1
- class Zoo #< DataMapper::Base
1
+ class Zoo #< DataMapper::Base # please do not remove this
2
2
  include DataMapper::Persistence
3
3
 
4
- property :name, :string
4
+ property :name, :string, :nullable => false, :default => "Zoo"
5
5
  property :notes, :text
6
6
  property :updated_at, :datetime
7
7
 
8
8
  has_many :exhibits
9
- begin
10
- validates_presence_of :name
11
- rescue ArgumentError => e
12
- throw e unless e.message =~ /specify a unique key/
13
- end
14
9
 
15
10
  def name=(val)
16
11
  @name = (val == "Colorado Springs") ? "Cheyenne Mountain" : val
@@ -3,7 +3,7 @@ require File.dirname(__FILE__) + "/spec_helper"
3
3
  describe 'Paranoia' do
4
4
 
5
5
  before(:all) do
6
- class Scared
6
+ class Scared #< DataMapper::Base # please do not remove this
7
7
  include DataMapper::Persistence
8
8
 
9
9
  property :name, :string
@@ -1,6 +1,146 @@
1
1
  require File.dirname(__FILE__) + "/spec_helper"
2
2
 
3
- describe DataMapper::Persistence do
3
+ describe "DataMapper::Persistence::ConvenienceMethods::ClassMethods" do
4
+
5
+ before(:all) do
6
+ fixtures(:animals)
7
+ fixtures(:exhibits)
8
+ end
9
+
10
+ describe 'A record' do
11
+ it 'should save and return true if validations pass' do
12
+ count = Exhibit.count
13
+ bugs_and_more_bugs = Exhibit.new(:name => 'Bugs And More Bugs')
14
+ bugs_and_more_bugs.save.should be_true
15
+ Exhibit.count.should == count + 1
16
+ end
17
+
18
+ it 'should return false on save if validations fail' do
19
+ count = Exhibit.count
20
+ bugs_and_more_bugs = Exhibit.new
21
+ bugs_and_more_bugs.save.should be_false
22
+ Exhibit.count.should == count
23
+ end
24
+
25
+ it 'should reload its attributes' do
26
+ frog = Animal.first(:name => 'Frog')
27
+ frog.name = 'MegaFrog'
28
+ frog.name.should == 'MegaFrog'
29
+ frog.reload!
30
+ frog.name.should == 'Frog'
31
+ end
32
+
33
+ it "should prepare it's associations for reload" do
34
+ chippy = Animal.first(:name => 'Cup')
35
+ amazonia = Exhibit.first(:name => 'Amazonia')
36
+ amazonia.animals << chippy
37
+ amazonia.animals.should include(chippy)
38
+ amazonia.reload!
39
+ amazonia.animals.should_not include(chippy)
40
+ end
41
+
42
+ it 'should be destroyed!' do
43
+ capybara = Animal.create(:name => 'Capybara')
44
+ count = Animal.count
45
+ capybara.destroy!
46
+ Animal.first(:name => 'Capybara').should be_nil
47
+ Animal.count.should == count - 1
48
+ end
49
+ end
50
+
51
+ it 'should return the first match using find_or_create' do
52
+ count = Animal.count
53
+ frog = Animal.find_or_create(:name => 'Frog')
54
+ frog.name.should == 'Frog'
55
+ Animal.count.should == count
56
+ end
57
+
58
+ it 'should create a record if a match is not found with find_or_create' do
59
+ count = Animal.count
60
+ capybara = Animal.find_or_create(:name => 'Capybara')
61
+ capybara.name.should == 'Capybara'
62
+ Animal.count.should == count + 1
63
+ end
64
+
65
+ it 'should return all records' do
66
+ all_animals = Animal.all
67
+ all_animals.length.should == Animal.count
68
+ all_animals.each do |animal|
69
+ animal.class.should == Animal
70
+ end
71
+ end
72
+
73
+ it 'should return the first record' do
74
+ Animal.first.should == Animal.find(:first)
75
+ end
76
+
77
+ it 'should return a count of the records' do
78
+ Animal.count.should == Animal.find_by_sql("SELECT COUNT(*) FROM animals")[0]
79
+ end
80
+
81
+ it 'should delete all records' do
82
+ Animal.delete_all
83
+ Animal.count.should == 0
84
+
85
+ fixtures(:animals)
86
+ end
87
+
88
+ #it 'should be truncated' do
89
+ # Animal.truncate!
90
+ # Animal.count.should == 0
91
+ #
92
+ # fixtures(:animals)
93
+ #end
94
+
95
+ it 'should find a matching record given an id' do
96
+ Animal.find(1).name.should == 'Frog'
97
+ end
98
+
99
+ it 'should find all records' do
100
+ Animal.find(:all).length.should == Animal.count
101
+ end
102
+
103
+ it 'should find all matching records given some condition' do
104
+ Animal.find(:all, :conditions => ["name = ?", "Frog"])[0].name.should == 'Frog'
105
+ end
106
+
107
+ it 'should find the first matching record' do
108
+ Animal.find(:first).name.should == 'Frog'
109
+ end
110
+
111
+ it 'should find the first matching record given some condition' do
112
+ Animal.find(:first, :conditions => ["name = ?", "Frog"]).name.should == 'Frog'
113
+ end
114
+
115
+ it 'should select records using the supplied sql fragment' do
116
+ Animal.find_by_sql("SELECT name FROM animals WHERE name='Frog'")[0].should == 'Frog'
117
+ end
118
+
119
+ it 'should retrieve the indexed element' do
120
+ Animal[1].id.should == 1
121
+ end
122
+
123
+ it 'should create a new record' do
124
+ count = Animal.count
125
+ capybara = Animal.create(:name => 'Capybara')
126
+ capybara.name.should == 'Capybara'
127
+ Animal.count.should == count + 1
128
+ end
129
+ end
130
+
131
+
132
+ # Can't describe DataMapper::Persistence because
133
+ # rspec will include it for some crazy reason!
134
+ describe "DataMapper::Persistence" do
135
+
136
+ it "should raise ObjectNotFoundError for missing objects with the indexer finder" do
137
+ # pending "http://wm.lighthouseapp.com/projects/4819-datamapper/tickets/111-should-raise-objectnotfounderror-on-the-indexer-finder"
138
+ lambda { Zoo[900] }.should raise_error(DataMapper::ObjectNotFoundError)
139
+ end
140
+
141
+ it "should raise IncompleteModelDefinitionError for a model with no properties" do
142
+ lambda { class IncompleteZoo; include DataMapper::Persistence; end; IncompleteZoo.new }.should raise_error(DataMapper::Persistence::IncompleteModelDefinitionError)
143
+ end
4
144
 
5
145
  it "attributes method should load all lazy-loaded values" do
6
146
  Animal.first(:name => 'Cup').attributes[:notes].should == 'I am a Cup!'
@@ -69,13 +209,14 @@ describe DataMapper::Persistence do
69
209
  p1.should == p2
70
210
  end
71
211
 
72
- it "should not be equal if attributes have changed" do
73
- p1 = Person.create(:name => 'Sam')
74
- p2 = Person[p1.id]
75
- p2.name = "Paul"
76
-
77
- p1.should_not == p2
78
- end
212
+ # This is unnecessary. Use #dirty? to check for changes.
213
+ # it "should not be equal if attributes have changed" do
214
+ # p1 = Person.create(:name => 'Sam')
215
+ # p2 = Person[p1.id]
216
+ # p2.name = "Paul"
217
+ #
218
+ # p1.should_not == p2
219
+ # end
79
220
 
80
221
  end
81
222
 
@@ -165,7 +306,7 @@ end
165
306
  describe 'Properties' do
166
307
 
167
308
  it 'should default to public method visibility' do
168
- class SoftwareEngineer
309
+ class SoftwareEngineer #< DataMapper::Base # please do not remove this
169
310
  include DataMapper::Persistence
170
311
 
171
312
  set_table_name 'people'
@@ -177,7 +318,7 @@ describe 'Properties' do
177
318
  end
178
319
 
179
320
  it 'should respect protected property options' do
180
- class SanitationEngineer
321
+ class SanitationEngineer #< DataMapper::Base # please do not remove this
181
322
  include DataMapper::Persistence
182
323
 
183
324
  set_table_name 'people'
@@ -190,7 +331,7 @@ describe 'Properties' do
190
331
  end
191
332
 
192
333
  it 'should respect private property options' do
193
- class ElectricalEngineer
334
+ class ElectricalEngineer #< DataMapper::Base # please do not remove this
194
335
  include DataMapper::Persistence
195
336
 
196
337
  set_table_name 'people'
@@ -203,7 +344,7 @@ describe 'Properties' do
203
344
  end
204
345
 
205
346
  it 'should set both reader and writer visibiliy when accessor option is passed' do
206
- class TrainEngineer
347
+ class TrainEngineer #< DataMapper::Base # please do not remove this
207
348
  include DataMapper::Persistence
208
349
 
209
350
  property :name, :string, :accessor => :private
@@ -214,7 +355,7 @@ describe 'Properties' do
214
355
  end
215
356
 
216
357
  it 'should only be listed in attributes if they have public getters' do
217
- class SalesEngineer
358
+ class SalesEngineer #< DataMapper::Base # please do not remove this
218
359
  include DataMapper::Persistence
219
360
 
220
361
  set_table_name 'people'
@@ -228,7 +369,7 @@ describe 'Properties' do
228
369
  end
229
370
 
230
371
  it 'should not allow mass assignment if private or protected' do
231
- class ChemicalEngineer
372
+ class ChemicalEngineer #< DataMapper::Base # please do not remove this
232
373
  include DataMapper::Persistence
233
374
 
234
375
  set_table_name 'people'
@@ -243,7 +384,7 @@ describe 'Properties' do
243
384
  end
244
385
 
245
386
  it 'should allow :protected to be passed as an alias for a public reader, protected writer' do
246
- class CivilEngineer
387
+ class CivilEngineer #< DataMapper::Base # please do not remove this
247
388
  include DataMapper::Persistence
248
389
 
249
390
  set_table_name 'people'
@@ -255,7 +396,7 @@ describe 'Properties' do
255
396
  end
256
397
 
257
398
  it 'should allow :private to be passed as an alias for a public reader, private writer' do
258
- class AudioEngineer
399
+ class AudioEngineer #< DataMapper::Base # please do not remove this
259
400
  include DataMapper::Persistence
260
401
 
261
402
  set_table_name 'people'
@@ -268,7 +409,7 @@ describe 'Properties' do
268
409
 
269
410
  it 'should raise an error when invalid options are passsed' do
270
411
  lambda do
271
- class JumpyCow
412
+ class JumpyCow #< DataMapper::Base # please do not remove this
272
413
  include DataMapper::Persistence
273
414
 
274
415
  set_table_name 'animals'
@@ -279,7 +420,7 @@ describe 'Properties' do
279
420
 
280
421
  it 'should raise an error when the first argument to index isnt an array' do
281
422
  lambda do
282
- class JumpyCow
423
+ class JumpyCow #< DataMapper::Base # please do not remove this
283
424
  include DataMapper::Persistence
284
425
 
285
426
  set_table_name 'animals'
@@ -287,4 +428,52 @@ describe 'Properties' do
287
428
  end
288
429
  end.should raise_error(ArgumentError)
289
430
  end
431
+
432
+ it "should return true on saving a new record" do
433
+ bob = User.new(:name => 'bob', :email => 'bob@example.com')
434
+ bob.save!.should == true
435
+ bob.destroy!
436
+ end
437
+
438
+ it "should assign to public setters" do
439
+ x = Project.new
440
+ x.attributes = { :set_us_up_the_bomb => true }
441
+ x.should be_set_up_for_bomb
442
+ end
443
+
444
+ it "should protect private setters" do
445
+ x = Project.new
446
+ x.attributes = { :be_wery_sneaky => true }
447
+ x.should_not be_wery_sneaky
448
+ end
449
+
450
+ it "should not call initialize on materialization" do
451
+ # pending "http://wm.lighthouseapp.com/projects/4819-datamapper/tickets/113-use-allocate-to-materialize-objects"
452
+ x = Tomato.new
453
+ x.should be_initialized
454
+ x.save!
455
+ x.name.should eql('Ugly')
456
+ x.should be_bruised
457
+
458
+ x.name = 'Bob'
459
+ x.save!
460
+
461
+ x2 = Tomato.first(:name => 'Bob')
462
+ x2.should_not be_bruised
463
+ x2.heal!
464
+ x2.should == x
465
+ x2.name.should eql('Bob')
466
+ x2.should_not be_initialized
467
+
468
+ x3 = Tomato.get(x.key)
469
+ x3.should_not be_bruised
470
+ x3.heal!
471
+ x3.should == x
472
+ x3.name.should eql('Bob')
473
+ x3.should_not be_initialized
474
+ end
475
+
476
+ it "should report persistence" do
477
+ Tomato.should be_persistent
478
+ end
290
479
  end