dm-core 0.10.2 → 1.0.0.rc1

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 (183) hide show
  1. data/.gitignore +10 -1
  2. data/Gemfile +143 -0
  3. data/Rakefile +9 -5
  4. data/VERSION +1 -1
  5. data/dm-core.gemspec +160 -57
  6. data/lib/dm-core.rb +131 -56
  7. data/lib/dm-core/adapters.rb +98 -14
  8. data/lib/dm-core/adapters/abstract_adapter.rb +24 -4
  9. data/lib/dm-core/adapters/in_memory_adapter.rb +7 -2
  10. data/lib/dm-core/associations/many_to_many.rb +19 -30
  11. data/lib/dm-core/associations/many_to_one.rb +58 -42
  12. data/lib/dm-core/associations/one_to_many.rb +33 -23
  13. data/lib/dm-core/associations/one_to_one.rb +27 -11
  14. data/lib/dm-core/associations/relationship.rb +4 -4
  15. data/lib/dm-core/collection.rb +23 -16
  16. data/lib/dm-core/core_ext/array.rb +36 -0
  17. data/lib/dm-core/core_ext/hash.rb +30 -0
  18. data/lib/dm-core/core_ext/module.rb +46 -0
  19. data/lib/dm-core/core_ext/object.rb +31 -0
  20. data/lib/dm-core/core_ext/pathname.rb +20 -0
  21. data/lib/dm-core/core_ext/string.rb +22 -0
  22. data/lib/dm-core/core_ext/try_dup.rb +44 -0
  23. data/lib/dm-core/model.rb +88 -27
  24. data/lib/dm-core/model/hook.rb +75 -18
  25. data/lib/dm-core/model/property.rb +50 -9
  26. data/lib/dm-core/model/relationship.rb +31 -31
  27. data/lib/dm-core/model/scope.rb +3 -3
  28. data/lib/dm-core/property.rb +196 -516
  29. data/lib/dm-core/property/binary.rb +7 -0
  30. data/lib/dm-core/property/boolean.rb +35 -0
  31. data/lib/dm-core/property/class.rb +24 -0
  32. data/lib/dm-core/property/date.rb +47 -0
  33. data/lib/dm-core/property/date_time.rb +48 -0
  34. data/lib/dm-core/property/decimal.rb +43 -0
  35. data/lib/dm-core/property/discriminator.rb +48 -0
  36. data/lib/dm-core/property/float.rb +24 -0
  37. data/lib/dm-core/property/integer.rb +32 -0
  38. data/lib/dm-core/property/numeric.rb +43 -0
  39. data/lib/dm-core/property/object.rb +32 -0
  40. data/lib/dm-core/property/serial.rb +8 -0
  41. data/lib/dm-core/property/string.rb +49 -0
  42. data/lib/dm-core/property/text.rb +12 -0
  43. data/lib/dm-core/property/time.rb +48 -0
  44. data/lib/dm-core/property/typecast/numeric.rb +32 -0
  45. data/lib/dm-core/property/typecast/time.rb +28 -0
  46. data/lib/dm-core/property_set.rb +10 -4
  47. data/lib/dm-core/query.rb +14 -37
  48. data/lib/dm-core/query/conditions/comparison.rb +8 -6
  49. data/lib/dm-core/query/conditions/operation.rb +33 -2
  50. data/lib/dm-core/query/operator.rb +2 -5
  51. data/lib/dm-core/query/path.rb +4 -6
  52. data/lib/dm-core/repository.rb +21 -6
  53. data/lib/dm-core/resource.rb +316 -133
  54. data/lib/dm-core/resource/state.rb +79 -0
  55. data/lib/dm-core/resource/state/clean.rb +40 -0
  56. data/lib/dm-core/resource/state/deleted.rb +30 -0
  57. data/lib/dm-core/resource/state/dirty.rb +86 -0
  58. data/lib/dm-core/resource/state/immutable.rb +34 -0
  59. data/lib/dm-core/resource/state/persisted.rb +29 -0
  60. data/lib/dm-core/resource/state/transient.rb +70 -0
  61. data/lib/dm-core/spec/lib/adapter_helpers.rb +52 -0
  62. data/lib/dm-core/spec/lib/collection_helpers.rb +20 -0
  63. data/{spec → lib/dm-core/spec}/lib/counter_adapter.rb +5 -1
  64. data/lib/dm-core/spec/lib/pending_helpers.rb +50 -0
  65. data/lib/dm-core/spec/lib/spec_helper.rb +68 -0
  66. data/lib/dm-core/spec/setup.rb +165 -0
  67. data/lib/dm-core/spec/{adapter_shared_spec.rb → shared/adapter_spec.rb} +21 -7
  68. data/{spec/public/shared/resource_shared_spec.rb → lib/dm-core/spec/shared/resource_spec.rb} +120 -83
  69. data/{spec/public/shared/sel_shared_spec.rb → lib/dm-core/spec/shared/sel_spec.rb} +5 -6
  70. data/lib/dm-core/support/assertions.rb +8 -0
  71. data/lib/dm-core/support/equalizer.rb +1 -0
  72. data/lib/dm-core/support/hook.rb +420 -0
  73. data/lib/dm-core/support/lazy_array.rb +453 -0
  74. data/lib/dm-core/support/local_object_space.rb +12 -0
  75. data/lib/dm-core/support/logger.rb +193 -6
  76. data/lib/dm-core/support/naming_conventions.rb +8 -8
  77. data/lib/dm-core/support/subject.rb +33 -0
  78. data/lib/dm-core/type.rb +4 -0
  79. data/lib/dm-core/types/boolean.rb +2 -0
  80. data/lib/dm-core/types/decimal.rb +9 -0
  81. data/lib/dm-core/types/discriminator.rb +2 -0
  82. data/lib/dm-core/types/object.rb +3 -0
  83. data/lib/dm-core/types/serial.rb +2 -0
  84. data/lib/dm-core/types/text.rb +2 -0
  85. data/lib/dm-core/version.rb +1 -1
  86. data/spec/public/associations/many_to_many/read_multiple_join_spec.rb +67 -0
  87. data/spec/public/model/hook_spec.rb +209 -0
  88. data/spec/public/model/property_spec.rb +35 -0
  89. data/spec/public/model/relationship_spec.rb +33 -20
  90. data/spec/public/model_spec.rb +142 -10
  91. data/spec/public/property/binary_spec.rb +14 -0
  92. data/spec/public/property/boolean_spec.rb +14 -0
  93. data/spec/public/property/class_spec.rb +20 -0
  94. data/spec/public/property/date_spec.rb +14 -0
  95. data/spec/public/property/date_time_spec.rb +14 -0
  96. data/spec/public/property/decimal_spec.rb +14 -0
  97. data/spec/public/{types → property}/discriminator_spec.rb +2 -12
  98. data/spec/public/property/float_spec.rb +14 -0
  99. data/spec/public/property/integer_spec.rb +14 -0
  100. data/spec/public/property/object_spec.rb +9 -17
  101. data/spec/public/property/serial_spec.rb +14 -0
  102. data/spec/public/property/string_spec.rb +14 -0
  103. data/spec/public/property/text_spec.rb +52 -0
  104. data/spec/public/property/time_spec.rb +14 -0
  105. data/spec/public/property_spec.rb +28 -87
  106. data/spec/public/resource_spec.rb +101 -0
  107. data/spec/public/sel_spec.rb +5 -15
  108. data/spec/public/shared/collection_shared_spec.rb +16 -30
  109. data/spec/public/shared/finder_shared_spec.rb +2 -4
  110. data/spec/public/shared/property_shared_spec.rb +176 -0
  111. data/spec/semipublic/adapters/abstract_adapter_spec.rb +1 -1
  112. data/spec/semipublic/adapters/in_memory_adapter_spec.rb +2 -2
  113. data/spec/semipublic/associations/many_to_many_spec.rb +89 -0
  114. data/spec/semipublic/associations/many_to_one_spec.rb +24 -1
  115. data/spec/semipublic/associations/one_to_many_spec.rb +51 -0
  116. data/spec/semipublic/associations/one_to_one_spec.rb +49 -0
  117. data/spec/semipublic/associations/relationship_spec.rb +3 -3
  118. data/spec/semipublic/associations_spec.rb +1 -1
  119. data/spec/semipublic/property/binary_spec.rb +13 -0
  120. data/spec/semipublic/property/boolean_spec.rb +65 -0
  121. data/spec/semipublic/property/class_spec.rb +33 -0
  122. data/spec/semipublic/property/date_spec.rb +43 -0
  123. data/spec/semipublic/property/date_time_spec.rb +46 -0
  124. data/spec/semipublic/property/decimal_spec.rb +82 -0
  125. data/spec/semipublic/property/discriminator_spec.rb +19 -0
  126. data/spec/semipublic/property/float_spec.rb +82 -0
  127. data/spec/semipublic/property/integer_spec.rb +82 -0
  128. data/spec/semipublic/property/serial_spec.rb +13 -0
  129. data/spec/semipublic/property/string_spec.rb +13 -0
  130. data/spec/semipublic/property/text_spec.rb +31 -0
  131. data/spec/semipublic/property/time_spec.rb +50 -0
  132. data/spec/semipublic/property_spec.rb +2 -532
  133. data/spec/semipublic/query/conditions/comparison_spec.rb +171 -169
  134. data/spec/semipublic/query/conditions/operation_spec.rb +53 -51
  135. data/spec/semipublic/query/path_spec.rb +17 -17
  136. data/spec/semipublic/query_spec.rb +47 -78
  137. data/spec/semipublic/resource/state/clean_spec.rb +88 -0
  138. data/spec/semipublic/resource/state/deleted_spec.rb +78 -0
  139. data/spec/semipublic/resource/state/dirty_spec.rb +133 -0
  140. data/spec/semipublic/resource/state/immutable_spec.rb +99 -0
  141. data/spec/semipublic/resource/state/transient_spec.rb +128 -0
  142. data/spec/semipublic/resource/state_spec.rb +226 -0
  143. data/spec/semipublic/shared/property_shared_spec.rb +143 -0
  144. data/spec/semipublic/shared/resource_shared_spec.rb +16 -15
  145. data/spec/semipublic/shared/resource_state_shared_spec.rb +78 -0
  146. data/spec/semipublic/shared/subject_shared_spec.rb +79 -0
  147. data/spec/spec_helper.rb +21 -97
  148. data/spec/support/types/huge_integer.rb +17 -0
  149. data/spec/unit/array_spec.rb +48 -0
  150. data/spec/unit/hash_spec.rb +35 -0
  151. data/spec/unit/hook_spec.rb +1234 -0
  152. data/spec/unit/lazy_array_spec.rb +1959 -0
  153. data/spec/unit/module_spec.rb +70 -0
  154. data/spec/unit/object_spec.rb +37 -0
  155. data/spec/unit/try_dup_spec.rb +45 -0
  156. data/tasks/local_gemfile.rake +18 -0
  157. data/tasks/spec.rake +0 -3
  158. metadata +197 -71
  159. data/deps.rip +0 -2
  160. data/lib/dm-core/adapters/data_objects_adapter.rb +0 -712
  161. data/lib/dm-core/adapters/mysql_adapter.rb +0 -42
  162. data/lib/dm-core/adapters/oracle_adapter.rb +0 -229
  163. data/lib/dm-core/adapters/postgres_adapter.rb +0 -22
  164. data/lib/dm-core/adapters/sqlite3_adapter.rb +0 -17
  165. data/lib/dm-core/adapters/sqlserver_adapter.rb +0 -114
  166. data/lib/dm-core/adapters/yaml_adapter.rb +0 -111
  167. data/lib/dm-core/core_ext/enumerable.rb +0 -28
  168. data/lib/dm-core/migrations.rb +0 -1427
  169. data/lib/dm-core/spec/data_objects_adapter_shared_spec.rb +0 -366
  170. data/lib/dm-core/transaction.rb +0 -508
  171. data/lib/dm-core/types/paranoid_boolean.rb +0 -42
  172. data/lib/dm-core/types/paranoid_datetime.rb +0 -41
  173. data/spec/lib/adapter_helpers.rb +0 -105
  174. data/spec/lib/collection_helpers.rb +0 -18
  175. data/spec/lib/pending_helpers.rb +0 -46
  176. data/spec/public/migrations_spec.rb +0 -503
  177. data/spec/public/transaction_spec.rb +0 -153
  178. data/spec/semipublic/adapters/mysql_adapter_spec.rb +0 -17
  179. data/spec/semipublic/adapters/oracle_adapter_spec.rb +0 -194
  180. data/spec/semipublic/adapters/postgres_adapter_spec.rb +0 -17
  181. data/spec/semipublic/adapters/sqlite3_adapter_spec.rb +0 -17
  182. data/spec/semipublic/adapters/sqlserver_adapter_spec.rb +0 -17
  183. data/spec/semipublic/adapters/yaml_adapter_spec.rb +0 -12
@@ -0,0 +1,133 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper'))
2
+
3
+ describe DataMapper::Resource::State::Dirty do
4
+ before :all do
5
+ class ::Author
6
+ include DataMapper::Resource
7
+
8
+ property :id, HugeInteger, :key => true, :default => 1
9
+ property :name, String
10
+ property :active, Boolean, :default => true
11
+ property :coding, Boolean, :default => true
12
+
13
+ belongs_to :parent, self, :required => false
14
+ has n, :children, self, :inverse => :parent
15
+ end
16
+
17
+ @model = Author
18
+ end
19
+
20
+ before do
21
+ @resource = @model.create(:name => 'Dan Kubb')
22
+ @resource.attributes = { :name => 'John Doe' }
23
+
24
+ @state = @resource.persisted_state
25
+ @state.should be_kind_of(DataMapper::Resource::State::Dirty)
26
+ end
27
+
28
+ after do
29
+ @resource.destroy
30
+ end
31
+
32
+ after do
33
+ @model.all.destroy!
34
+ end
35
+
36
+ describe '#commit' do
37
+ subject { @state.commit }
38
+
39
+ supported_by :all do
40
+ before do
41
+ @new_id = @resource.id = @resource.id.succ
42
+ end
43
+
44
+ it 'should return a Clean state' do
45
+ should eql(DataMapper::Resource::State::Clean.new(@resource))
46
+ end
47
+
48
+ it 'should update the resource' do
49
+ subject
50
+ @model.get!(*@resource.key).should == @resource
51
+ end
52
+
53
+ it 'should update the resource to the identity map if the key changed' do
54
+ identity_map = @resource.repository.identity_map(@model)
55
+ identity_map.should == { @resource.key => @resource }
56
+ subject
57
+ identity_map.should == { [ @new_id ] => @resource }
58
+ end
59
+ end
60
+ end
61
+
62
+ describe '#delete' do
63
+ subject { @state.delete }
64
+
65
+ supported_by :all do
66
+ before do
67
+ @resource.children = [ @resource.parent = @resource ]
68
+ end
69
+
70
+ it_should_behave_like 'It resets resource state'
71
+
72
+ it 'should return a Deleted state' do
73
+ should eql(DataMapper::Resource::State::Deleted.new(@resource))
74
+ end
75
+ end
76
+ end
77
+
78
+ describe '#get' do
79
+ before do
80
+ @loaded_value = 'John Doe'
81
+ end
82
+
83
+ it_should_behave_like 'Resource::State::Persisted#get'
84
+ end
85
+
86
+ describe '#rollback' do
87
+ subject { @state.rollback }
88
+
89
+ supported_by :all do
90
+ before do
91
+ @resource.children = [ @resource.parent = @resource ]
92
+ end
93
+
94
+ it_should_behave_like 'It resets resource state'
95
+
96
+ it 'should return a Clean state' do
97
+ should eql(DataMapper::Resource::State::Clean.new(@resource))
98
+ end
99
+ end
100
+ end
101
+
102
+ describe '#set' do
103
+ subject { @state.set(@key, @value) }
104
+
105
+ supported_by :all do
106
+ describe 'with attributes that keep the resource dirty' do
107
+ before do
108
+ @key = @model.properties[:name]
109
+ @value = @key.get!(@resource)
110
+ end
111
+
112
+ it_should_behave_like 'A method that delegates to the superclass #set'
113
+
114
+ it 'should return a Dirty state' do
115
+ should equal(@state)
116
+ end
117
+ end
118
+
119
+ describe 'with attributes that make the resource clean' do
120
+ before do
121
+ @key = @model.properties[:name]
122
+ @value = 'Dan Kubb'
123
+ end
124
+
125
+ it_should_behave_like 'A method that delegates to the superclass #set'
126
+
127
+ it 'should return a Clean state' do
128
+ should eql(DataMapper::Resource::State::Clean.new(@resource))
129
+ end
130
+ end
131
+ end
132
+ end
133
+ end
@@ -0,0 +1,99 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper'))
2
+
3
+ describe DataMapper::Resource::State::Immutable do
4
+ before :all do
5
+ class ::Author
6
+ include DataMapper::Resource
7
+
8
+ property :id, Serial
9
+ property :name, String
10
+ property :active, Boolean, :default => true
11
+ property :coding, Boolean, :default => true
12
+
13
+ belongs_to :parent, self, :required => false
14
+ end
15
+
16
+ @model = Author
17
+ end
18
+
19
+ before do
20
+ @parent = @model.create(:name => 'John Doe')
21
+
22
+ @resource = @model.create(:name => 'Dan Kubb', :parent => @parent)
23
+ @resource = @model.first(@model.key.zip(@resource.key).to_hash.merge(:fields => [ :name, :parent_id ]))
24
+
25
+ @state = @resource.persisted_state
26
+ @state.should be_kind_of(DataMapper::Resource::State::Immutable)
27
+ end
28
+
29
+ describe '#commit' do
30
+ subject { @state.commit }
31
+
32
+ supported_by :all do
33
+ it 'should be a no-op' do
34
+ should equal(@state)
35
+ end
36
+ end
37
+ end
38
+
39
+ describe '#delete' do
40
+ subject { @state.delete }
41
+
42
+ supported_by :all do
43
+ it 'should raise an exception' do
44
+ method(:subject).should raise_error(DataMapper::ImmutableError, 'Immutable resource cannot be deleted')
45
+ end
46
+ end
47
+ end
48
+
49
+ describe '#get' do
50
+ subject { @state.get(@key) }
51
+
52
+ supported_by :all do
53
+ describe 'with an unloaded property' do
54
+ before do
55
+ @key = @model.properties[:id]
56
+ end
57
+
58
+ it 'should raise an exception' do
59
+ method(:subject).should raise_error(DataMapper::ImmutableError, 'Immutable resource cannot be lazy loaded')
60
+ end
61
+ end
62
+
63
+ describe 'with an unloaded relationship' do
64
+ before do
65
+ @key = @model.relationships[:parent]
66
+ end
67
+
68
+ it 'should return value' do
69
+ should == @parent
70
+ end
71
+ end
72
+
73
+ describe 'with a loaded subject' do
74
+ before do
75
+ @key = @model.properties[:name]
76
+ end
77
+
78
+ it 'should return value' do
79
+ should == 'Dan Kubb'
80
+ end
81
+ end
82
+ end
83
+ end
84
+
85
+ describe '#set' do
86
+ before do
87
+ @key = @model.properties[:name]
88
+ @value = @key.get!(@resource)
89
+ end
90
+
91
+ subject { @state.set(@key, @value) }
92
+
93
+ supported_by :all do
94
+ it 'should raise an exception' do
95
+ method(:subject).should raise_error(DataMapper::ImmutableError, 'Immutable resource cannot be modified')
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,128 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper'))
2
+
3
+ describe DataMapper::Resource::State::Transient do
4
+ before :all do
5
+ class ::Author
6
+ include DataMapper::Resource
7
+
8
+ property :id, Serial
9
+ property :name, String
10
+ property :age, Integer
11
+ property :description, Text, :default => lambda { |resource, property| resource.name }
12
+ property :active, Boolean, :default => true
13
+ property :coding, Boolean, :default => true
14
+ end
15
+
16
+ @model = Author
17
+ end
18
+
19
+ before do
20
+ @resource = @model.new(:name => 'Dan Kubb', :coding => false)
21
+
22
+ @state = @resource.persisted_state
23
+ @state.should be_kind_of(DataMapper::Resource::State::Transient)
24
+ end
25
+
26
+ describe '#commit' do
27
+ subject { @state.commit }
28
+
29
+ supported_by :all do
30
+ it 'should return the expected Clean state' do
31
+ should eql(DataMapper::Resource::State::Clean.new(@resource))
32
+ end
33
+
34
+ it 'should set the serial property' do
35
+ method(:subject).should change(@resource, :id).from(nil)
36
+ end
37
+
38
+ it 'should set default values' do
39
+ method(:subject).should change { @model.properties[:active].get!(@resource) }.from(nil).to(true)
40
+ end
41
+
42
+ it 'should not set default values when they are already set' do
43
+ method(:subject).should_not change(@resource, :coding)
44
+ end
45
+
46
+ it 'should create the resource' do
47
+ subject
48
+ @model.get(*@resource.key).should == @resource
49
+ end
50
+
51
+ it 'should reset original attributes' do
52
+ expect do
53
+ @resource.persisted_state = subject
54
+ end.should change { @resource.original_attributes.dup }.from(@model.properties[:name] => nil, @model.properties[:coding] => nil).to({})
55
+ end
56
+
57
+ it 'should add the resource to the identity map' do
58
+ DataMapper.repository do |repository|
59
+ identity_map = repository.identity_map(@model)
60
+ identity_map.should be_empty
61
+ subject
62
+ identity_map.should == { @resource.key => @resource }
63
+ end
64
+ end
65
+ end
66
+ end
67
+
68
+ [ :delete, :rollback ].each do |method|
69
+ describe "##{method}" do
70
+ subject { @state.send(method) }
71
+
72
+ it 'should be a no-op' do
73
+ should equal(@state)
74
+ end
75
+ end
76
+ end
77
+
78
+ describe '#get' do
79
+ subject { @state.get(@key) }
80
+
81
+ describe 'with a set value' do
82
+ before do
83
+ @key = @model.properties[:coding]
84
+ @key.should be_loaded(@resource)
85
+ end
86
+
87
+ it 'should return value' do
88
+ should be(false)
89
+ end
90
+
91
+ it 'should be idempotent' do
92
+ should equal(subject)
93
+ end
94
+ end
95
+
96
+ describe 'with an unset value and no default value' do
97
+ before do
98
+ @key = @model.properties[:age]
99
+ @key.should_not be_loaded(@resource)
100
+ @key.should_not be_default
101
+ end
102
+
103
+ it 'should return nil' do
104
+ should be_nil
105
+ end
106
+
107
+ it 'should be idempotent' do
108
+ should equal(subject)
109
+ end
110
+ end
111
+
112
+ describe 'with an unset value and a default value' do
113
+ before do
114
+ @key = @model.properties[:description]
115
+ @key.should_not be_loaded(@resource)
116
+ @key.should be_default
117
+ end
118
+
119
+ it 'should return the name' do
120
+ should == 'Dan Kubb'
121
+ end
122
+
123
+ it 'should be idempotent' do
124
+ should equal(subject)
125
+ end
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,226 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'spec_helper'))
2
+
3
+ describe DataMapper::Resource::State do
4
+ before :all do
5
+ class ::Author
6
+ include DataMapper::Resource
7
+
8
+ property :id, Serial
9
+ property :name, String
10
+ property :private, Boolean, :accessor => :private
11
+
12
+ belongs_to :parent, self, :required => false
13
+ end
14
+
15
+ @model = Author
16
+ end
17
+
18
+ before do
19
+ @resource = @model.new(:name => 'Dan Kubb')
20
+
21
+ @state = DataMapper::Resource::State.new(@resource)
22
+ end
23
+
24
+ describe '.new' do
25
+ subject { DataMapper::Resource::State.new(@resource) }
26
+
27
+ it { should be_kind_of(DataMapper::Resource::State) }
28
+ end
29
+
30
+ describe '#==' do
31
+ subject { @state == @other }
32
+
33
+ describe 'with the same class and resource' do
34
+ before do
35
+ @other = DataMapper::Resource::State.new(@resource)
36
+ end
37
+
38
+ it { should be(true) }
39
+
40
+ it 'should be symmetric' do
41
+ should == (@other == @state)
42
+ end
43
+ end
44
+
45
+ describe 'with the same class and different resource' do
46
+ before do
47
+ @other = DataMapper::Resource::State.new(@model.new)
48
+ end
49
+
50
+ it { should be(false) }
51
+
52
+ it 'should be symmetric' do
53
+ should == (@other == @state)
54
+ end
55
+ end
56
+
57
+ describe 'with a different class and the same resource' do
58
+ before do
59
+ @other = DataMapper::Resource::State::Clean.new(@resource)
60
+ end
61
+
62
+ it 'should be true for a subclass' do
63
+ should be(true)
64
+ end
65
+
66
+ it 'should be symmetric' do
67
+ should == (@other == @state)
68
+ end
69
+ end
70
+
71
+ describe 'with a different class and different resource' do
72
+ before do
73
+ @other = DataMapper::Resource::State::Clean.new(@model.new)
74
+ end
75
+
76
+ it { should be(false) }
77
+
78
+ it 'should be symmetric' do
79
+ should == (@other == @state)
80
+ end
81
+ end
82
+ end
83
+
84
+ [ :commit, :delete, :rollback ].each do |method|
85
+ describe "##{method}" do
86
+ subject { @state.send(method) }
87
+
88
+ it 'should raise an exception' do
89
+ method(:subject).should raise_error(NotImplementedError, "DataMapper::Resource::State##{method} should be implemented")
90
+ end
91
+ end
92
+ end
93
+
94
+ describe '#eql?' do
95
+ subject { @state.eql?(@other) }
96
+
97
+ describe 'with the same class and resource' do
98
+ before do
99
+ @other = DataMapper::Resource::State.new(@resource)
100
+ end
101
+
102
+ it { should be(true) }
103
+
104
+ it 'should be symmetric' do
105
+ should == @other.eql?(@state)
106
+ end
107
+ end
108
+
109
+ describe 'with the same class and different resource' do
110
+ before do
111
+ @other = DataMapper::Resource::State.new(@model.new)
112
+ end
113
+
114
+ it { should be(false) }
115
+
116
+ it 'should be symmetric' do
117
+ should == @other.eql?(@state)
118
+ end
119
+ end
120
+
121
+ describe 'with a different class and the same resource' do
122
+ before do
123
+ @other = DataMapper::Resource::State::Clean.new(@resource)
124
+ end
125
+
126
+ it { should be(false) }
127
+
128
+ it 'should be symmetric' do
129
+ should == @other.eql?(@state)
130
+ end
131
+ end
132
+
133
+ describe 'with a different class and different resource' do
134
+ before do
135
+ @other = DataMapper::Resource::State::Clean.new(@model.new)
136
+ end
137
+
138
+ it { should be(false) }
139
+
140
+ it 'should be symmetric' do
141
+ should == @other.eql?(@state)
142
+ end
143
+ end
144
+ end
145
+
146
+ describe '#get' do
147
+ subject { @state.get(@key) }
148
+
149
+ describe 'with a Property subject' do
150
+ before do
151
+ @key = @model.properties[:name]
152
+ end
153
+
154
+ it 'should return the value' do
155
+ should == 'Dan Kubb'
156
+ end
157
+ end
158
+
159
+ describe 'with a Relationship subject' do
160
+ supported_by :all do
161
+ before do
162
+ # set the association
163
+ @resource.parent = @resource
164
+
165
+ @key = @model.relationships[:parent]
166
+ end
167
+
168
+ it 'should return the association' do
169
+ should == @resource
170
+ end
171
+ end
172
+ end
173
+ end
174
+
175
+ describe '#hash' do
176
+ subject { @state.hash }
177
+
178
+ it 'should be the object_id hash of the resource' do
179
+ should == @resource.object_id.hash
180
+ end
181
+ end
182
+
183
+ describe '#resource' do
184
+ subject { @state.resource }
185
+
186
+ it 'should return the resource' do
187
+ should equal(@resource)
188
+ end
189
+ end
190
+
191
+ describe '#set' do
192
+ subject { @state.set(@key, @value) }
193
+
194
+ describe 'with a Property subject' do
195
+ before do
196
+ @key = @model.properties[:name]
197
+ @value = 'John Doe'
198
+ end
199
+
200
+ it 'should return a state object' do
201
+ should be_kind_of(DataMapper::Resource::State)
202
+ end
203
+
204
+ it 'should change the object attributes' do
205
+ method(:subject).should change(@resource, :attributes).from(:name => 'Dan Kubb').to(:name => 'John Doe')
206
+ end
207
+ end
208
+
209
+ describe 'with a Relationship subject' do
210
+ supported_by :all do
211
+ before do
212
+ @key = @model.relationships[:parent]
213
+ @value = @resource
214
+ end
215
+
216
+ it 'should return a state object' do
217
+ should be_kind_of(DataMapper::Resource::State)
218
+ end
219
+
220
+ it 'should change the object relationship' do
221
+ method(:subject).should change(@resource, :parent).from(nil).to(@resource)
222
+ end
223
+ end
224
+ end
225
+ end
226
+ end