dm-core 0.9.2 → 0.9.3

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 (84) hide show
  1. data/.autotest +26 -0
  2. data/{CHANGELOG → History.txt} +78 -77
  3. data/Manifest.txt +123 -0
  4. data/{README → README.txt} +0 -0
  5. data/Rakefile +29 -0
  6. data/SPECS +63 -0
  7. data/TODO +1 -0
  8. data/lib/dm-core.rb +6 -1
  9. data/lib/dm-core/adapters/data_objects_adapter.rb +29 -32
  10. data/lib/dm-core/adapters/mysql_adapter.rb +1 -1
  11. data/lib/dm-core/adapters/postgres_adapter.rb +1 -1
  12. data/lib/dm-core/adapters/sqlite3_adapter.rb +2 -2
  13. data/lib/dm-core/associations.rb +26 -0
  14. data/lib/dm-core/associations/many_to_many.rb +34 -25
  15. data/lib/dm-core/associations/many_to_one.rb +4 -4
  16. data/lib/dm-core/associations/one_to_many.rb +48 -13
  17. data/lib/dm-core/associations/one_to_one.rb +4 -4
  18. data/lib/dm-core/associations/relationship.rb +144 -42
  19. data/lib/dm-core/associations/relationship_chain.rb +31 -24
  20. data/lib/dm-core/auto_migrations.rb +0 -4
  21. data/lib/dm-core/collection.rb +40 -7
  22. data/lib/dm-core/dependency_queue.rb +31 -0
  23. data/lib/dm-core/hook.rb +2 -2
  24. data/lib/dm-core/is.rb +2 -2
  25. data/lib/dm-core/logger.rb +10 -10
  26. data/lib/dm-core/model.rb +94 -41
  27. data/lib/dm-core/property.rb +72 -41
  28. data/lib/dm-core/property_set.rb +8 -14
  29. data/lib/dm-core/query.rb +34 -9
  30. data/lib/dm-core/repository.rb +0 -0
  31. data/lib/dm-core/resource.rb +13 -13
  32. data/lib/dm-core/scope.rb +25 -2
  33. data/lib/dm-core/type.rb +3 -3
  34. data/lib/dm-core/types/discriminator.rb +10 -8
  35. data/lib/dm-core/types/object.rb +4 -0
  36. data/lib/dm-core/types/paranoid_boolean.rb +15 -4
  37. data/lib/dm-core/types/paranoid_datetime.rb +15 -4
  38. data/lib/dm-core/version.rb +3 -0
  39. data/script/all +5 -0
  40. data/script/performance.rb +191 -0
  41. data/script/profile.rb +86 -0
  42. data/spec/integration/association_spec.rb +288 -204
  43. data/spec/integration/association_through_spec.rb +9 -3
  44. data/spec/integration/associations/many_to_many_spec.rb +97 -31
  45. data/spec/integration/associations/many_to_one_spec.rb +41 -6
  46. data/spec/integration/associations/one_to_many_spec.rb +18 -2
  47. data/spec/integration/auto_migrations_spec.rb +0 -0
  48. data/spec/integration/collection_spec.rb +89 -42
  49. data/spec/integration/dependency_queue_spec.rb +58 -0
  50. data/spec/integration/model_spec.rb +67 -8
  51. data/spec/integration/postgres_adapter_spec.rb +19 -20
  52. data/spec/integration/property_spec.rb +17 -8
  53. data/spec/integration/query_spec.rb +273 -191
  54. data/spec/integration/resource_spec.rb +108 -10
  55. data/spec/integration/strategic_eager_loading_spec.rb +138 -0
  56. data/spec/integration/transaction_spec.rb +3 -3
  57. data/spec/integration/type_spec.rb +121 -0
  58. data/spec/lib/logging_helper.rb +18 -0
  59. data/spec/lib/model_loader.rb +91 -0
  60. data/spec/lib/publicize_methods.rb +28 -0
  61. data/spec/models/vehicles.rb +34 -0
  62. data/spec/models/zoo.rb +48 -0
  63. data/spec/spec.opts +3 -0
  64. data/spec/spec_helper.rb +25 -62
  65. data/spec/unit/adapters/data_objects_adapter_spec.rb +1 -0
  66. data/spec/unit/associations/many_to_many_spec.rb +3 -0
  67. data/spec/unit/associations/many_to_one_spec.rb +9 -1
  68. data/spec/unit/associations/one_to_many_spec.rb +12 -4
  69. data/spec/unit/associations/relationship_spec.rb +19 -15
  70. data/spec/unit/associations_spec.rb +37 -0
  71. data/spec/unit/collection_spec.rb +8 -0
  72. data/spec/unit/data_mapper_spec.rb +14 -0
  73. data/spec/unit/model_spec.rb +2 -2
  74. data/spec/unit/property_set_spec.rb +0 -13
  75. data/spec/unit/property_spec.rb +92 -21
  76. data/spec/unit/query_spec.rb +49 -4
  77. data/spec/unit/resource_spec.rb +122 -60
  78. data/spec/unit/scope_spec.rb +11 -0
  79. data/tasks/ci.rb +68 -0
  80. data/tasks/dm.rb +63 -0
  81. data/tasks/doc.rb +20 -0
  82. data/tasks/hoe.rb +38 -0
  83. data/tasks/install.rb +20 -0
  84. metadata +63 -22
@@ -1,6 +1,9 @@
1
1
  require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'spec_helper'))
2
2
 
3
3
  describe DataMapper::Associations::Relationship do
4
+
5
+ load_models_for_metaphor :vehicles
6
+
4
7
  it "should describe an association" do
5
8
  belongs_to = DataMapper::Associations::Relationship.new(
6
9
  :manufacturer,
@@ -11,50 +14,51 @@ describe DataMapper::Associations::Relationship do
11
14
  )
12
15
 
13
16
  belongs_to.should respond_to(:name)
14
- belongs_to.should respond_to(:repository_name)
17
+ belongs_to.should respond_to(:with_repository)
15
18
  belongs_to.should respond_to(:child_key)
16
19
  belongs_to.should respond_to(:parent_key)
17
20
  end
18
21
 
19
22
  it "should map properties explicitly when an association method passes them in its options" do
20
- repository_name = :mock
21
-
22
23
  belongs_to = DataMapper::Associations::Relationship.new(
23
24
  :manufacturer,
24
- repository_name,
25
+ :mock,
25
26
  'Vehicle',
26
27
  'Manufacturer',
27
28
  { :child_key => [ :manufacturer_id ], :parent_key => [ :id ] }
28
29
  )
29
30
 
30
31
  belongs_to.name.should == :manufacturer
31
- belongs_to.repository_name.should == repository_name
32
+ belongs_to.with_repository do |r|
33
+ r.name.should == :mock
34
+ end
32
35
 
33
36
  belongs_to.child_key.should be_a_kind_of(DataMapper::PropertySet)
34
37
  belongs_to.parent_key.should be_a_kind_of(DataMapper::PropertySet)
35
38
 
36
- belongs_to.child_key.to_a.should == Vehicle.properties(repository_name).slice(:manufacturer_id)
37
- belongs_to.parent_key.to_a.should == Manufacturer.properties(repository_name).key
39
+ belongs_to.child_key.to_a.should == Vehicle.properties(:mock).slice(:manufacturer_id)
40
+ belongs_to.parent_key.to_a.should == Manufacturer.properties(:mock).key
38
41
  end
39
42
 
40
43
  it "should infer properties when options aren't passed" do
41
- repository_name = :mock
42
-
43
44
  has_many = DataMapper::Associations::Relationship.new(
44
45
  :models,
45
- repository_name,
46
+ :mock,
46
47
  'Vehicle',
47
- 'Manufacturer'
48
+ 'Manufacturer',
49
+ { :child_key => [:model_id] }
48
50
  )
49
51
 
50
52
  has_many.name.should == :models
51
- has_many.repository_name.should == repository_name
53
+ has_many.with_repository do |r|
54
+ r.name.should == :mock
55
+ end
52
56
 
53
57
  has_many.child_key.should be_a_kind_of(DataMapper::PropertySet)
54
58
  has_many.parent_key.should be_a_kind_of(DataMapper::PropertySet)
55
-
56
- has_many.child_key.to_a.should == Vehicle.properties(repository_name).slice(:models_id)
57
- has_many.parent_key.to_a.should == Manufacturer.properties(repository_name).key
59
+ # Vehicle.has n, :models, :class_name => 'Manufacturer', :child_key => "models_id"
60
+ has_many.child_key.to_a.should == Vehicle.properties(:mock).slice(:model_id)
61
+ has_many.parent_key.to_a.should == Manufacturer.properties(:mock).key
58
62
  end
59
63
 
60
64
  it "should generate child properties with a safe subset of the parent options" do
@@ -1,6 +1,9 @@
1
1
  require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
2
2
 
3
3
  describe "DataMapper::Associations" do
4
+
5
+ load_models_for_metaphor :vehicles
6
+
4
7
  before do
5
8
  @relationship = mock(DataMapper::Associations::Relationship)
6
9
  @n = 1.0/0
@@ -8,6 +11,40 @@ describe "DataMapper::Associations" do
8
11
  Manufacturer.mock_relationship = Vehicle.mock_relationship = @relationship
9
12
  end
10
13
 
14
+ describe "#many_to_one_relationships" do
15
+ before :all do
16
+ module MTORelationships
17
+ class A
18
+ include DataMapper::Resource
19
+ def self.default_repository_name
20
+ :a_db
21
+ end
22
+ repository(:b_db) do
23
+ belongs_to :b
24
+ end
25
+ repository(:c_db) do
26
+ belongs_to :c
27
+ end
28
+ end
29
+ class B
30
+ include DataMapper::Resource
31
+ def self.default_repository_name
32
+ :b_db
33
+ end
34
+ end
35
+ class C
36
+ include DataMapper::Resource
37
+ def self.default_repository_name
38
+ :c_db
39
+ end
40
+ end
41
+ end
42
+ end
43
+ it "should list all relationships that are one-to-many" do
44
+ MTORelationships::A.many_to_one_relationships.sort_by { |r| r.name.to_s }.should == [MTORelationships::A.relationships(:b_db)[:b], MTORelationships::A.relationships(:c_db)[:c]]
45
+ end
46
+ end
47
+
11
48
  describe ".relationships" do
12
49
  class B
13
50
  include DataMapper::Resource
@@ -24,6 +24,10 @@ describe DataMapper::Collection do
24
24
  @collection.should respond_to(:at)
25
25
  end
26
26
 
27
+ it 'should provide #build' do
28
+ @collection.should respond_to(:build)
29
+ end
30
+
27
31
  it 'should provide #clear' do
28
32
  @collection.should respond_to(:clear)
29
33
  end
@@ -72,6 +76,10 @@ describe DataMapper::Collection do
72
76
  @collection.should respond_to(:first)
73
77
  end
74
78
 
79
+ it 'should provide #freeze' do
80
+ @collection.should respond_to(:freeze)
81
+ end
82
+
75
83
  it 'should provide #get' do
76
84
  @collection.should respond_to(:get)
77
85
  end
@@ -1,6 +1,20 @@
1
1
  require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
2
2
 
3
3
  describe DataMapper do
4
+ describe ".dependency_queue" do
5
+ before(:all) do
6
+ @q = DataMapper.dependency_queue
7
+ end
8
+
9
+ it "should return a dependency queue" do
10
+ @q.should be_a_kind_of(DataMapper::DependencyQueue)
11
+ end
12
+
13
+ it "should only create one dependency queue" do
14
+ @q.should == DataMapper.dependency_queue
15
+ end
16
+ end
17
+
4
18
  describe ".prepare" do
5
19
  it "should pass the default repository to the block if no argument is given" do
6
20
  DataMapper.should_receive(:repository).with(no_args).and_return :default_repo
@@ -205,11 +205,11 @@ describe 'DataMapper::Model' do
205
205
  @standard_resource_inclusions = DataMapper::Resource.instance_variable_get('@extra_inclusions')
206
206
  @standard_model_extensions = DataMapper::Model.instance_variable_get('@extra_extensions')
207
207
  end
208
-
208
+
209
209
  before(:each) do
210
210
  DataMapper::Resource.instance_variable_set('@extra_inclusions', [])
211
211
  DataMapper::Model.instance_variable_set('@extra_extensions', [])
212
-
212
+
213
213
  @module = Module.new do
214
214
  def greet
215
215
  hi_mom!
@@ -79,18 +79,5 @@ describe DataMapper::PropertySet do
79
79
  @properties.instance_variable_get("@property_for").should_not be_empty
80
80
  @properties.dup.instance_variable_get("@property_for").should be_empty
81
81
  end
82
-
83
- it 'should be able to retarget a new model' do
84
- copy = Icon.properties.dup(Boat)
85
- copy.should have(4).entries
86
-
87
- copy.each do |property|
88
- property.model.should == Boat
89
- end
90
-
91
- copy << DataMapper::Property.new(Icon, :z_index, Integer, {})
92
- copy.should have(5).entries
93
- Icon.properties.should have(4).entries
94
- end
95
82
  end
96
83
  end
@@ -52,6 +52,25 @@ describe DataMapper::Property do
52
52
  end
53
53
  end
54
54
 
55
+ it 'should provide #field' do
56
+ @property.should respond_to(:field)
57
+ end
58
+
59
+ describe '#field' do
60
+ it 'should accept a custom field' do
61
+ property = DataMapper::Property.new(Zoo, :location, String, :field => 'City')
62
+ property.field.should == 'City'
63
+ end
64
+
65
+ it 'should use repository name if passed in' do
66
+ @property.field(:default).should == 'name'
67
+ end
68
+
69
+ it 'should return default field if no repository name passed in' do
70
+ @property.field.should == 'name'
71
+ end
72
+ end
73
+
55
74
  it 'should provide #get' do
56
75
  @property.should respond_to(:get)
57
76
  end
@@ -105,7 +124,7 @@ describe DataMapper::Property do
105
124
  describe '#set' do
106
125
  before do
107
126
  @original_values = {}
108
- @resource = mock('resource', :kind_of? => true, :original_values => @original_values)
127
+ @resource = mock('resource', :kind_of? => true, :original_values => @original_values, :new_record? => true)
109
128
  end
110
129
 
111
130
  it 'should typecast the value' do
@@ -199,18 +218,56 @@ describe DataMapper::Property do
199
218
  property.default_for(resource).should == 'Tomato'
200
219
  end
201
220
 
202
- it "should determine visibility of readers and writers" do
203
- name = DataMapper::Property.new(Tomato,:botanical_name,String,{})
204
- name.reader_visibility.should == :public
205
- name.writer_visibility.should == :public
206
-
207
- seeds = DataMapper::Property.new(Tomato,:seeds,TrueClass,{:accessor=>:private})
208
- seeds.reader_visibility.should == :private
209
- seeds.writer_visibility.should == :private
221
+ describe "reader and writer visibility" do
222
+ # parameter passed to Property.new # reader | writer visibility
223
+ {
224
+ {} => [:public, :public],
225
+ { :accessor => :public } => [:public, :public],
226
+ { :accessor => :protected } => [:protected, :protected],
227
+ { :accessor => :private } => [:private, :private],
228
+ { :reader => :public } => [:public, :public],
229
+ { :reader => :protected } => [:protected, :public],
230
+ { :reader => :private } => [:private, :public],
231
+ { :writer => :public } => [:public, :public],
232
+ { :writer => :protected } => [:public, :protected],
233
+ { :writer => :private } => [:public, :private],
234
+ { :reader => :public, :writer => :public } => [:public, :public],
235
+ { :reader => :public, :writer => :protected } => [:public, :protected],
236
+ { :reader => :public, :writer => :private } => [:public, :private],
237
+ { :reader => :protected, :writer => :public } => [:protected, :public],
238
+ { :reader => :protected, :writer => :protected } => [:protected, :protected],
239
+ { :reader => :protected, :writer => :private } => [:protected, :private],
240
+ { :reader => :private, :writer => :public } => [:private, :public],
241
+ { :reader => :private, :writer => :protected } => [:private, :protected],
242
+ { :reader => :private, :writer => :private } => [:private, :private],
243
+ }.each do |input, output|
244
+ it "#{input.inspect} should make reader #{output[0]} and writer #{output[1]}" do
245
+ property = DataMapper::Property.new(Tomato, :botanical_name, String, input)
246
+ property.reader_visibility.should == output[0]
247
+ property.writer_visibility.should == output[1]
248
+ end
249
+ end
210
250
 
211
- family = DataMapper::Property.new(Tomato,:family,String,{:reader => :public, :writer => :private })
212
- family.reader_visibility.should == :public
213
- family.writer_visibility.should == :private
251
+ [
252
+ { :accessor => :junk },
253
+ { :reader => :junk },
254
+ { :writer => :junk },
255
+ { :reader => :public, :writer => :junk },
256
+ { :reader => :protected, :writer => :junk },
257
+ { :reader => :private, :writer => :junk },
258
+ { :reader => :junk, :writer => :public },
259
+ { :reader => :junk, :writer => :protected },
260
+ { :reader => :junk, :writer => :private },
261
+ { :reader => :junk, :writer => :junk },
262
+ { :reader => :junk, :writer => :junk },
263
+ { :reader => :junk, :writer => :junk },
264
+ ].each do |input|
265
+ it "#{input.inspect} should raise ArgumentError" do
266
+ lambda {
267
+ property = DataMapper::Property.new(Tomato, :family, String, input)
268
+ }.should raise_error(ArgumentError)
269
+ end
270
+ end
214
271
  end
215
272
 
216
273
  it "should return an instance variable name" do
@@ -263,8 +320,8 @@ describe DataMapper::Property do
263
320
  end
264
321
 
265
322
  it "should set the field to the correct field_naming_convention" do
266
- DataMapper::Property.new(Zoo, :species, String, {}).field.should == 'species'
267
- DataMapper::Property.new(Tomato, :genetic_history, DataMapper::Types::Text, {}).field.should == "genetic_history"
323
+ DataMapper::Property.new(Zoo, :species, String, {}).field(:default).should == 'species'
324
+ DataMapper::Property.new(Tomato, :genetic_history, DataMapper::Types::Text, {}).field(:default).should == "genetic_history"
268
325
  end
269
326
 
270
327
  it "should provide the primitive mapping" do
@@ -340,6 +397,13 @@ describe DataMapper::Property do
340
397
  end
341
398
  end
342
399
 
400
+ { '-8' => -8, '-8.0' => -8, -8 => -8, -8.0 => -8, BigDecimal('8.0') => 8 }.each do |value,expected|
401
+ it "should typecast #{format(value)} to #{format(expected)} for an Integer property" do
402
+ property = DataMapper::Property.new(Zoo, :integer, Integer)
403
+ property.typecast(value).should == expected
404
+ end
405
+ end
406
+
343
407
  { '0' => 0, '0.0' => 0, 0 => 0, 0.0 => 0, BigDecimal('0.0') => 0 }.each do |value,expected|
344
408
  it "should typecast #{format(value)} to #{format(expected)} for an Integer property" do
345
409
  property = DataMapper::Property.new(Zoo, :integer, Integer)
@@ -347,6 +411,20 @@ describe DataMapper::Property do
347
411
  end
348
412
  end
349
413
 
414
+ { '5' => 5, '5.0' => 5, 5 => 5, 5.0 => 5, BigDecimal('5.0') => 5 }.each do |value,expected|
415
+ it "should typecast #{format(value)} to #{format(expected)} for an Integer property" do
416
+ property = DataMapper::Property.new(Zoo, :integer, Integer)
417
+ property.typecast(value).should == expected
418
+ end
419
+ end
420
+
421
+ { 'none' => nil, 'almost 5' => nil, '-3 change' => -3, '9 items' => 9 }.each do |value,expected|
422
+ it "should typecast #{format(value)} to #{format(expected)} for an Integer property" do
423
+ property = DataMapper::Property.new(Zoo, :integer, Integer)
424
+ property.typecast(value).should == expected
425
+ end
426
+ end
427
+
350
428
  { '0' => BigDecimal('0'), '0.0' => BigDecimal('0.0'), 0.0 => BigDecimal('0.0'), BigDecimal('0.0') => BigDecimal('0.0') }.each do |value,expected|
351
429
  it "should typecast #{format(value)} to #{format(expected)} for a BigDecimal property" do
352
430
  property = DataMapper::Property.new(Zoo, :big_decimal, BigDecimal)
@@ -434,13 +512,6 @@ describe DataMapper::Property do
434
512
  DataMapper::Property.new(Zoo, :name, String).should respond_to(:inspect)
435
513
  end
436
514
 
437
- it "should use the Repository of its @model" do
438
- p = DataMapper::Property.new(Zoo, :name, String)
439
- repo = mock("repository")
440
- Zoo.should_receive(:repository).and_return(repo)
441
- p.repository.should == repo
442
- end
443
-
444
515
  it 'should return an abbreviated representation of the property when inspected' do
445
516
  DataMapper::Property.new(Zoo, :name, String).inspect.should == '#<Property:Zoo:name>'
446
517
  end
@@ -17,8 +17,8 @@ BAD_OPTIONS = {
17
17
  :reload => 'true',
18
18
  :offset => -1,
19
19
  :limit => 0,
20
- :order => [],
21
- :fields => [],
20
+ # :order => [], # TODO: spec conditions where :order may be empty
21
+ # :fields => [], # TODO: spec conditions where :fields may be empty
22
22
  :links => [],
23
23
  :includes => [],
24
24
  :conditions => [],
@@ -110,7 +110,7 @@ describe DataMapper::Query do
110
110
  query.conditions.should == [ [ :eql, Article.properties[:author], 'dkubb' ] ]
111
111
  end
112
112
 
113
- it 'when a Symbol::Operator object is a key' do
113
+ it 'when a Query::Operator object is a key' do
114
114
  query = DataMapper::Query.new(@repository, Article, :author.like => /\Ad(?:an\.)kubb\z/)
115
115
  query.conditions.should == [ [ :like, Article.properties[:author], /\Ad(?:an\.)kubb\z/ ] ]
116
116
  end
@@ -161,7 +161,7 @@ describe DataMapper::Query do
161
161
  end
162
162
  end
163
163
 
164
- it 'when unknown options use something that is not a Symbol::Operator, Symbol or String is a key' do
164
+ it 'when unknown options use something that is not a Query::Operator, Symbol or String is a key' do
165
165
  lambda {
166
166
  DataMapper::Query.new(@repository, Article, nil => nil)
167
167
  }.should raise_error(ArgumentError)
@@ -483,3 +483,48 @@ describe DataMapper::Query do
483
483
  end
484
484
  end
485
485
  end
486
+
487
+ describe DataMapper::Query::Operator do
488
+ before do
489
+ @operator = :thing.gte
490
+ end
491
+
492
+ it 'should provide #==' do
493
+ @operator.should respond_to(:==)
494
+ end
495
+
496
+ describe '#==' do
497
+ describe 'should be equal' do
498
+ it 'when other is same object' do
499
+ @operator.should == @operator
500
+ end
501
+
502
+ it 'when other has the same target and operator' do
503
+ other = :thing.gte
504
+ @operator.target.should == other.target
505
+ @operator.operator.should == other.operator
506
+ @operator.should == other
507
+ end
508
+ end
509
+
510
+ describe 'should be different' do
511
+ it 'when other class is not a descendant of self.class' do
512
+ other = :thing
513
+ other.class.should_not be_kind_of(@operator.class)
514
+ @operator.should_not == other
515
+ end
516
+
517
+ it 'when other has a different target' do
518
+ other = :other.gte
519
+ @operator.target.should_not == other.target
520
+ @operator.should_not == other
521
+ end
522
+
523
+ it 'when other has a different operator' do
524
+ other = :thing.gt
525
+ @operator.operator.should_not == other.operator
526
+ @operator.should_not == other
527
+ end
528
+ end
529
+ end
530
+ end
@@ -1,5 +1,52 @@
1
1
  require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
2
2
 
3
+ # rSpec completely FUBARs everything if you give it a Module here.
4
+ # So we give it a String of the module name instead.
5
+ # DO NOT CHANGE THIS!
6
+ describe "DataMapper::Resource" do
7
+
8
+ load_models_for_metaphor :zoo
9
+
10
+ describe '#attributes' do
11
+ it 'should return a hash of attribute-names and values' do
12
+ zoo = Zoo.new
13
+ zoo.name = "San Francisco"
14
+ zoo.description = "This is a pretty awesome zoo"
15
+ zoo.attributes.should == {
16
+ :name => "San Francisco", :description => "This is a pretty awesome zoo",
17
+ :id => nil, :inception => nil, :open => false, :size => nil
18
+ }
19
+ end
20
+
21
+ it "should return a hash with all nil values if the instance is new and has no default values" do
22
+ Species.new.attributes.should == { :id => nil, :name => nil }
23
+ end
24
+
25
+ it 'should not include private attributes' do
26
+ Species.new.attributes.should == { :id => nil, :name => nil }
27
+ end
28
+ end
29
+
30
+ # ---------- REPOSITORY WRITE METHODS ---------------
31
+
32
+ describe '#save' do
33
+
34
+ describe 'with a new resource' do
35
+ it 'should set defaults before create'
36
+ it 'should create when dirty'
37
+ it 'should create when non-dirty, and it has a serial key'
38
+ end
39
+
40
+ describe 'with an existing resource' do
41
+ it 'should update'
42
+ end
43
+
44
+ end
45
+ end
46
+
47
+
48
+ # ---------- Old specs... BOOOOOOOOOO ---------------
49
+
3
50
  class Planet
4
51
  include DataMapper::Resource
5
52
 
@@ -8,7 +55,7 @@ class Planet
8
55
  property :id, Integer, :key => true
9
56
  property :name, String
10
57
  property :age, Integer
11
- property :core, String, :private => true
58
+ property :core, String, :accessor => :private
12
59
  property :type, Discriminator
13
60
  property :data, Object
14
61
 
@@ -25,9 +72,6 @@ class Planet
25
72
  end
26
73
  end
27
74
 
28
- class Moon
29
- end
30
-
31
75
  class BlackHole
32
76
  include DataMapper::Resource
33
77
 
@@ -74,54 +118,16 @@ class Banana < Fruit
74
118
  property :type, Discriminator
75
119
  end
76
120
 
121
+ class Cyclist
122
+ include DataMapper::Resource
123
+ property :id, Integer, :serial => true
124
+ property :victories, Integer
125
+ end
126
+
77
127
  # rSpec completely FUBARs everything if you give it a Module here.
78
128
  # So we give it a String of the module name instead.
79
129
  # DO NOT CHANGE THIS!
80
130
  describe "DataMapper::Resource" do
81
- it 'should provide #attribute_get' do
82
- Planet.new.should respond_to(:attribute_get)
83
- end
84
-
85
- describe '#attribute_get' do
86
- it 'should delegate to Property#get' do
87
- planet = Planet.new
88
- Planet.properties[:age].should_receive(:get).with(planet).and_return(1)
89
- planet.age.should == 1
90
- end
91
- end
92
-
93
- it 'should provide #attribute_set' do
94
- Planet.new.should respond_to(:attribute_set)
95
- end
96
-
97
- describe '#attribute_set' do
98
- it 'should typecast the value' do
99
- Planet.properties[:age].should_receive(:typecast).with('1').and_return(1)
100
- planet = Planet.new
101
- planet.age = '1'
102
- planet.age.should == 1
103
- end
104
-
105
- it 'should delegate to Property#set' do
106
- planet = Planet.new
107
- Planet.properties[:age].should_receive(:set).with(planet, 1).and_return(1)
108
- planet.age = 1
109
- end
110
- end
111
-
112
- describe '#attributes' do
113
- it 'should return a hash of attribute-names and values' do
114
- vegetable = Vegetable.new
115
- vegetable.attributes.should == {:name => nil, :id => nil}
116
- vegetable.name = "carot"
117
- vegetable.attributes.should == {:name => "carot", :id => nil}
118
- end
119
-
120
- it 'should not include private attributes' do
121
- hole = BlackHole.new
122
- hole.attributes.should == {:id => nil}
123
- end
124
- end
125
131
 
126
132
  it 'should provide #save' do
127
133
  Planet.new.should respond_to(:save)
@@ -181,6 +187,46 @@ describe "DataMapper::Resource" do
181
187
 
182
188
  resource.save.should be_false
183
189
  end
190
+
191
+ describe 'for integer fields' do
192
+
193
+ it "should save strings without digits as nil" do
194
+ resource = Cyclist.new
195
+ resource.victories = "none"
196
+ resource.save.should be_true
197
+ resource.victories.should be_nil
198
+ end
199
+
200
+ it "should save strings beginning with non-digits as nil" do
201
+ resource = Cyclist.new
202
+ resource.victories = "almost 5"
203
+ resource.save.should be_true
204
+ resource.victories.should be_nil
205
+ end
206
+
207
+ it 'should save strings beginning with negative numbers as that number' do
208
+ resource = Cyclist.new
209
+ resource.victories = "-4 victories"
210
+ resource.save.should be_true
211
+ resource.victories.should == -4
212
+ end
213
+
214
+ it 'should save strings beginning with 0 as 0' do
215
+ resource = Cyclist.new
216
+ resource.victories = "0 victories"
217
+ resource.save.should be_true
218
+ resource.victories.should == 0
219
+ end
220
+
221
+ it 'should save strings beginning with positive numbers as that number' do
222
+ resource = Cyclist.new
223
+ resource.victories = "23 victories"
224
+ resource.save.should be_true
225
+ resource.victories.should == 23
226
+ end
227
+
228
+ end
229
+
184
230
  end
185
231
 
186
232
  describe 'with an existing resource' do
@@ -245,7 +291,7 @@ describe "DataMapper::Resource" do
245
291
  end
246
292
 
247
293
  it "should return an instance of the created object" do
248
- Planet.create!(:name => 'Venus', :age => 1_000_000, :core => nil, :id => 42).should be_a_kind_of(Planet)
294
+ Planet.create(:name => 'Venus', :age => 1_000_000, :id => 42).should be_a_kind_of(Planet)
249
295
  end
250
296
 
251
297
  it 'should provide persistance methods' do
@@ -256,31 +302,47 @@ describe "DataMapper::Resource" do
256
302
  end
257
303
 
258
304
  it "should have attributes" do
259
- attributes = { :name => 'Jupiter', :age => 1_000_000, :core => nil, :id => 42, :type => Planet, :data => nil }
305
+ attributes = { :name => 'Jupiter', :age => 1_000_000, :id => 42, :type => Planet, :data => nil }
260
306
  jupiter = Planet.new(attributes)
261
307
  jupiter.attributes.should == attributes
262
308
  end
263
309
 
264
310
  it "should be able to set attributes" do
265
- attributes = { :name => 'Jupiter', :age => 1_000_000, :core => nil, :id => 42, :type => Planet, :data => nil }
311
+ attributes = { :name => 'Jupiter', :age => 1_000_000, :id => 42, :type => Planet, :data => nil }
266
312
  jupiter = Planet.new(attributes)
267
313
  jupiter.attributes.should == attributes
268
- jupiter.attributes = attributes.merge(:core => 'Magma')
314
+
315
+ new_attributes = attributes.merge( :age => 2_500_000 )
316
+ jupiter.attributes = new_attributes
317
+ jupiter.attributes.should == new_attributes
318
+ end
319
+
320
+ it "should be able to set attributes using update_attributes" do
321
+ attributes = { :name => 'Jupiter', :age => 1_000_000, :id => 42, :type => Planet, :data => nil }
322
+ jupiter = Planet.new(attributes)
269
323
  jupiter.attributes.should == attributes
270
324
 
271
- jupiter.update_attributes({ :core => "Toast", :type => "Bob" }, :core).should be_true
272
- jupiter.core.should == "Toast"
273
- jupiter.type.should_not == "Bob"
325
+ new_age = { :age => 3_700_000 }
326
+ jupiter.update_attributes(new_age).should be_true
327
+ jupiter.age.should == 3_700_000
328
+ jupiter.attributes.should == attributes.merge(new_age)
329
+ end
330
+
331
+ # :core is a private accessor so Ruby should raise NameError
332
+ it "should not be able to set private attributes" do
333
+ lambda {
334
+ jupiter = Planet.new({ :core => "Molten Metal" })
335
+ }.should raise_error(NameError)
274
336
  end
275
337
 
276
- it "should not mark attributes dirty if there similar after update" do
277
- jupiter = Planet.new(:name => 'Jupiter', :age => 1_000_000, :core => nil, :id => 42, :data => { :a => "Yeah!" })
338
+ it "should not mark attributes dirty if they are similar after update" do
339
+ jupiter = Planet.new(:name => 'Jupiter', :age => 1_000_000, :id => 42, :data => { :a => "Yeah!" })
278
340
  jupiter.save.should be_true
279
341
 
280
342
  # discriminator will be set automatically
281
343
  jupiter.type.should == Planet
282
344
 
283
- jupiter.attributes = { :name => 'Jupiter', :age => 1_000_000, :core => nil, :data => { :a => "Yeah!" } }
345
+ jupiter.attributes = { :name => 'Jupiter', :age => 1_000_000, :data => { :a => "Yeah!" } }
284
346
 
285
347
  jupiter.attribute_dirty?(:name).should be_false
286
348
  jupiter.attribute_dirty?(:age).should be_false
@@ -291,7 +353,7 @@ describe "DataMapper::Resource" do
291
353
  end
292
354
 
293
355
  it "should not mark attributes dirty if they are similar after typecasting" do
294
- jupiter = Planet.new(:name => 'Jupiter', :age => 1_000_000, :core => nil, :id => 42, :type => nil)
356
+ jupiter = Planet.new(:name => 'Jupiter', :age => 1_000_000, :id => 42, :type => nil)
295
357
  jupiter.save.should be_true
296
358
  jupiter.dirty?.should be_false
297
359
 
@@ -378,7 +440,7 @@ describe "DataMapper::Resource" do
378
440
 
379
441
  it 'should store and retrieve default values' do
380
442
  Planet.property(:satellite_count, Integer, :default => 0)
381
- # stupid example but it's realiable and works
443
+ # stupid example but it's reliable and works
382
444
  Planet.property(:orbit_period, Float, :default => lambda { |r,p| p.name.to_s.length })
383
445
  earth = Planet.new(:name => 'Earth')
384
446
  earth.satellite_count.should == 0