ghost_dm-core 1.3.0.beta

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 (254) hide show
  1. data/.autotest +29 -0
  2. data/.document +5 -0
  3. data/.gitignore +35 -0
  4. data/.yardopts +1 -0
  5. data/Gemfile +65 -0
  6. data/LICENSE +20 -0
  7. data/README.md +269 -0
  8. data/Rakefile +4 -0
  9. data/dm-core.gemspec +24 -0
  10. data/lib/dm-core.rb +292 -0
  11. data/lib/dm-core/adapters.rb +222 -0
  12. data/lib/dm-core/adapters/abstract_adapter.rb +237 -0
  13. data/lib/dm-core/adapters/in_memory_adapter.rb +113 -0
  14. data/lib/dm-core/associations/many_to_many.rb +499 -0
  15. data/lib/dm-core/associations/many_to_one.rb +290 -0
  16. data/lib/dm-core/associations/one_to_many.rb +348 -0
  17. data/lib/dm-core/associations/one_to_one.rb +86 -0
  18. data/lib/dm-core/associations/relationship.rb +663 -0
  19. data/lib/dm-core/backwards.rb +13 -0
  20. data/lib/dm-core/collection.rb +1515 -0
  21. data/lib/dm-core/core_ext/kernel.rb +23 -0
  22. data/lib/dm-core/core_ext/pathname.rb +6 -0
  23. data/lib/dm-core/core_ext/symbol.rb +10 -0
  24. data/lib/dm-core/identity_map.rb +7 -0
  25. data/lib/dm-core/model.rb +874 -0
  26. data/lib/dm-core/model/hook.rb +103 -0
  27. data/lib/dm-core/model/is.rb +32 -0
  28. data/lib/dm-core/model/property.rb +249 -0
  29. data/lib/dm-core/model/relationship.rb +378 -0
  30. data/lib/dm-core/model/scope.rb +89 -0
  31. data/lib/dm-core/property.rb +866 -0
  32. data/lib/dm-core/property/binary.rb +21 -0
  33. data/lib/dm-core/property/boolean.rb +20 -0
  34. data/lib/dm-core/property/class.rb +17 -0
  35. data/lib/dm-core/property/date.rb +10 -0
  36. data/lib/dm-core/property/date_time.rb +10 -0
  37. data/lib/dm-core/property/decimal.rb +36 -0
  38. data/lib/dm-core/property/discriminator.rb +44 -0
  39. data/lib/dm-core/property/float.rb +16 -0
  40. data/lib/dm-core/property/integer.rb +22 -0
  41. data/lib/dm-core/property/invalid_value_error.rb +22 -0
  42. data/lib/dm-core/property/lookup.rb +27 -0
  43. data/lib/dm-core/property/numeric.rb +38 -0
  44. data/lib/dm-core/property/object.rb +34 -0
  45. data/lib/dm-core/property/serial.rb +14 -0
  46. data/lib/dm-core/property/string.rb +38 -0
  47. data/lib/dm-core/property/text.rb +9 -0
  48. data/lib/dm-core/property/time.rb +10 -0
  49. data/lib/dm-core/property_set.rb +177 -0
  50. data/lib/dm-core/query.rb +1366 -0
  51. data/lib/dm-core/query/conditions/comparison.rb +911 -0
  52. data/lib/dm-core/query/conditions/operation.rb +721 -0
  53. data/lib/dm-core/query/direction.rb +36 -0
  54. data/lib/dm-core/query/operator.rb +35 -0
  55. data/lib/dm-core/query/path.rb +114 -0
  56. data/lib/dm-core/query/sort.rb +39 -0
  57. data/lib/dm-core/relationship_set.rb +72 -0
  58. data/lib/dm-core/repository.rb +226 -0
  59. data/lib/dm-core/resource.rb +1214 -0
  60. data/lib/dm-core/resource/persistence_state.rb +75 -0
  61. data/lib/dm-core/resource/persistence_state/clean.rb +40 -0
  62. data/lib/dm-core/resource/persistence_state/deleted.rb +30 -0
  63. data/lib/dm-core/resource/persistence_state/dirty.rb +96 -0
  64. data/lib/dm-core/resource/persistence_state/immutable.rb +34 -0
  65. data/lib/dm-core/resource/persistence_state/persisted.rb +29 -0
  66. data/lib/dm-core/resource/persistence_state/transient.rb +80 -0
  67. data/lib/dm-core/spec/lib/adapter_helpers.rb +64 -0
  68. data/lib/dm-core/spec/lib/collection_helpers.rb +21 -0
  69. data/lib/dm-core/spec/lib/counter_adapter.rb +38 -0
  70. data/lib/dm-core/spec/lib/pending_helpers.rb +50 -0
  71. data/lib/dm-core/spec/lib/spec_helper.rb +74 -0
  72. data/lib/dm-core/spec/setup.rb +174 -0
  73. data/lib/dm-core/spec/shared/adapter_spec.rb +341 -0
  74. data/lib/dm-core/spec/shared/public/property_spec.rb +229 -0
  75. data/lib/dm-core/spec/shared/resource_spec.rb +1232 -0
  76. data/lib/dm-core/spec/shared/sel_spec.rb +111 -0
  77. data/lib/dm-core/spec/shared/semipublic/property_spec.rb +176 -0
  78. data/lib/dm-core/spec/shared/semipublic/query/conditions/abstract_comparison_spec.rb +261 -0
  79. data/lib/dm-core/support/assertions.rb +8 -0
  80. data/lib/dm-core/support/chainable.rb +18 -0
  81. data/lib/dm-core/support/deprecate.rb +12 -0
  82. data/lib/dm-core/support/descendant_set.rb +89 -0
  83. data/lib/dm-core/support/equalizer.rb +48 -0
  84. data/lib/dm-core/support/ext/array.rb +22 -0
  85. data/lib/dm-core/support/ext/blank.rb +25 -0
  86. data/lib/dm-core/support/ext/hash.rb +67 -0
  87. data/lib/dm-core/support/ext/module.rb +47 -0
  88. data/lib/dm-core/support/ext/object.rb +57 -0
  89. data/lib/dm-core/support/ext/string.rb +24 -0
  90. data/lib/dm-core/support/ext/try_dup.rb +12 -0
  91. data/lib/dm-core/support/hook.rb +405 -0
  92. data/lib/dm-core/support/inflections.rb +60 -0
  93. data/lib/dm-core/support/inflector/inflections.rb +211 -0
  94. data/lib/dm-core/support/inflector/methods.rb +151 -0
  95. data/lib/dm-core/support/lazy_array.rb +451 -0
  96. data/lib/dm-core/support/local_object_space.rb +13 -0
  97. data/lib/dm-core/support/logger.rb +201 -0
  98. data/lib/dm-core/support/mash.rb +176 -0
  99. data/lib/dm-core/support/naming_conventions.rb +90 -0
  100. data/lib/dm-core/support/ordered_set.rb +380 -0
  101. data/lib/dm-core/support/subject.rb +33 -0
  102. data/lib/dm-core/support/subject_set.rb +250 -0
  103. data/lib/dm-core/version.rb +3 -0
  104. data/script/performance.rb +275 -0
  105. data/script/profile.rb +218 -0
  106. data/spec/lib/rspec_immediate_feedback_formatter.rb +54 -0
  107. data/spec/public/associations/many_to_many/read_multiple_join_spec.rb +68 -0
  108. data/spec/public/associations/many_to_many_spec.rb +197 -0
  109. data/spec/public/associations/many_to_one_spec.rb +83 -0
  110. data/spec/public/associations/many_to_one_with_boolean_cpk_spec.rb +40 -0
  111. data/spec/public/associations/many_to_one_with_custom_fk_spec.rb +49 -0
  112. data/spec/public/associations/one_to_many_spec.rb +81 -0
  113. data/spec/public/associations/one_to_one_spec.rb +176 -0
  114. data/spec/public/associations/one_to_one_with_boolean_cpk_spec.rb +46 -0
  115. data/spec/public/collection_spec.rb +69 -0
  116. data/spec/public/finalize_spec.rb +76 -0
  117. data/spec/public/model/hook_spec.rb +246 -0
  118. data/spec/public/model/property_spec.rb +88 -0
  119. data/spec/public/model/relationship_spec.rb +1040 -0
  120. data/spec/public/model_spec.rb +462 -0
  121. data/spec/public/property/binary_spec.rb +41 -0
  122. data/spec/public/property/boolean_spec.rb +22 -0
  123. data/spec/public/property/class_spec.rb +28 -0
  124. data/spec/public/property/date_spec.rb +22 -0
  125. data/spec/public/property/date_time_spec.rb +22 -0
  126. data/spec/public/property/decimal_spec.rb +23 -0
  127. data/spec/public/property/discriminator_spec.rb +135 -0
  128. data/spec/public/property/float_spec.rb +22 -0
  129. data/spec/public/property/integer_spec.rb +22 -0
  130. data/spec/public/property/object_spec.rb +107 -0
  131. data/spec/public/property/serial_spec.rb +22 -0
  132. data/spec/public/property/string_spec.rb +22 -0
  133. data/spec/public/property/text_spec.rb +63 -0
  134. data/spec/public/property/time_spec.rb +22 -0
  135. data/spec/public/property_spec.rb +341 -0
  136. data/spec/public/resource_spec.rb +288 -0
  137. data/spec/public/sel_spec.rb +53 -0
  138. data/spec/public/setup_spec.rb +145 -0
  139. data/spec/public/shared/association_collection_shared_spec.rb +309 -0
  140. data/spec/public/shared/collection_finder_shared_spec.rb +267 -0
  141. data/spec/public/shared/collection_shared_spec.rb +1667 -0
  142. data/spec/public/shared/finder_shared_spec.rb +1629 -0
  143. data/spec/rcov.opts +6 -0
  144. data/spec/semipublic/adapters/abstract_adapter_spec.rb +30 -0
  145. data/spec/semipublic/adapters/in_memory_adapter_spec.rb +13 -0
  146. data/spec/semipublic/associations/many_to_many_spec.rb +94 -0
  147. data/spec/semipublic/associations/many_to_one_spec.rb +63 -0
  148. data/spec/semipublic/associations/one_to_many_spec.rb +55 -0
  149. data/spec/semipublic/associations/one_to_one_spec.rb +53 -0
  150. data/spec/semipublic/associations/relationship_spec.rb +200 -0
  151. data/spec/semipublic/associations_spec.rb +177 -0
  152. data/spec/semipublic/collection_spec.rb +110 -0
  153. data/spec/semipublic/model_spec.rb +96 -0
  154. data/spec/semipublic/property/binary_spec.rb +13 -0
  155. data/spec/semipublic/property/boolean_spec.rb +47 -0
  156. data/spec/semipublic/property/class_spec.rb +33 -0
  157. data/spec/semipublic/property/date_spec.rb +43 -0
  158. data/spec/semipublic/property/date_time_spec.rb +46 -0
  159. data/spec/semipublic/property/decimal_spec.rb +83 -0
  160. data/spec/semipublic/property/discriminator_spec.rb +19 -0
  161. data/spec/semipublic/property/float_spec.rb +82 -0
  162. data/spec/semipublic/property/integer_spec.rb +82 -0
  163. data/spec/semipublic/property/lookup_spec.rb +29 -0
  164. data/spec/semipublic/property/serial_spec.rb +13 -0
  165. data/spec/semipublic/property/string_spec.rb +13 -0
  166. data/spec/semipublic/property/text_spec.rb +31 -0
  167. data/spec/semipublic/property/time_spec.rb +50 -0
  168. data/spec/semipublic/property_spec.rb +114 -0
  169. data/spec/semipublic/query/conditions/comparison_spec.rb +1501 -0
  170. data/spec/semipublic/query/conditions/operation_spec.rb +1294 -0
  171. data/spec/semipublic/query/path_spec.rb +471 -0
  172. data/spec/semipublic/query_spec.rb +3682 -0
  173. data/spec/semipublic/resource/state/clean_spec.rb +88 -0
  174. data/spec/semipublic/resource/state/deleted_spec.rb +78 -0
  175. data/spec/semipublic/resource/state/dirty_spec.rb +162 -0
  176. data/spec/semipublic/resource/state/immutable_spec.rb +105 -0
  177. data/spec/semipublic/resource/state/transient_spec.rb +162 -0
  178. data/spec/semipublic/resource/state_spec.rb +230 -0
  179. data/spec/semipublic/resource_spec.rb +23 -0
  180. data/spec/semipublic/shared/condition_shared_spec.rb +9 -0
  181. data/spec/semipublic/shared/resource_shared_spec.rb +199 -0
  182. data/spec/semipublic/shared/resource_state_shared_spec.rb +79 -0
  183. data/spec/semipublic/shared/subject_shared_spec.rb +79 -0
  184. data/spec/spec.opts +5 -0
  185. data/spec/spec_helper.rb +38 -0
  186. data/spec/support/core_ext/hash.rb +10 -0
  187. data/spec/support/core_ext/inheritable_attributes.rb +46 -0
  188. data/spec/support/properties/huge_integer.rb +17 -0
  189. data/spec/unit/array_spec.rb +23 -0
  190. data/spec/unit/blank_spec.rb +73 -0
  191. data/spec/unit/data_mapper/ordered_set/append_spec.rb +26 -0
  192. data/spec/unit/data_mapper/ordered_set/clear_spec.rb +24 -0
  193. data/spec/unit/data_mapper/ordered_set/delete_spec.rb +28 -0
  194. data/spec/unit/data_mapper/ordered_set/each_spec.rb +19 -0
  195. data/spec/unit/data_mapper/ordered_set/empty_spec.rb +20 -0
  196. data/spec/unit/data_mapper/ordered_set/entries_spec.rb +22 -0
  197. data/spec/unit/data_mapper/ordered_set/eql_spec.rb +51 -0
  198. data/spec/unit/data_mapper/ordered_set/equal_value_spec.rb +84 -0
  199. data/spec/unit/data_mapper/ordered_set/hash_spec.rb +12 -0
  200. data/spec/unit/data_mapper/ordered_set/include_spec.rb +23 -0
  201. data/spec/unit/data_mapper/ordered_set/index_spec.rb +28 -0
  202. data/spec/unit/data_mapper/ordered_set/initialize_spec.rb +32 -0
  203. data/spec/unit/data_mapper/ordered_set/merge_spec.rb +36 -0
  204. data/spec/unit/data_mapper/ordered_set/shared/append_spec.rb +24 -0
  205. data/spec/unit/data_mapper/ordered_set/shared/clear_spec.rb +9 -0
  206. data/spec/unit/data_mapper/ordered_set/shared/delete_spec.rb +25 -0
  207. data/spec/unit/data_mapper/ordered_set/shared/each_spec.rb +17 -0
  208. data/spec/unit/data_mapper/ordered_set/shared/empty_spec.rb +9 -0
  209. data/spec/unit/data_mapper/ordered_set/shared/entries_spec.rb +9 -0
  210. data/spec/unit/data_mapper/ordered_set/shared/include_spec.rb +9 -0
  211. data/spec/unit/data_mapper/ordered_set/shared/index_spec.rb +13 -0
  212. data/spec/unit/data_mapper/ordered_set/shared/initialize_spec.rb +28 -0
  213. data/spec/unit/data_mapper/ordered_set/shared/merge_spec.rb +28 -0
  214. data/spec/unit/data_mapper/ordered_set/shared/size_spec.rb +13 -0
  215. data/spec/unit/data_mapper/ordered_set/shared/to_ary_spec.rb +11 -0
  216. data/spec/unit/data_mapper/ordered_set/size_spec.rb +27 -0
  217. data/spec/unit/data_mapper/ordered_set/to_ary_spec.rb +23 -0
  218. data/spec/unit/data_mapper/subject_set/append_spec.rb +47 -0
  219. data/spec/unit/data_mapper/subject_set/clear_spec.rb +34 -0
  220. data/spec/unit/data_mapper/subject_set/delete_spec.rb +40 -0
  221. data/spec/unit/data_mapper/subject_set/each_spec.rb +30 -0
  222. data/spec/unit/data_mapper/subject_set/empty_spec.rb +31 -0
  223. data/spec/unit/data_mapper/subject_set/entries_spec.rb +31 -0
  224. data/spec/unit/data_mapper/subject_set/get_spec.rb +34 -0
  225. data/spec/unit/data_mapper/subject_set/include_spec.rb +32 -0
  226. data/spec/unit/data_mapper/subject_set/named_spec.rb +33 -0
  227. data/spec/unit/data_mapper/subject_set/shared/append_spec.rb +18 -0
  228. data/spec/unit/data_mapper/subject_set/shared/clear_spec.rb +9 -0
  229. data/spec/unit/data_mapper/subject_set/shared/delete_spec.rb +9 -0
  230. data/spec/unit/data_mapper/subject_set/shared/each_spec.rb +9 -0
  231. data/spec/unit/data_mapper/subject_set/shared/empty_spec.rb +9 -0
  232. data/spec/unit/data_mapper/subject_set/shared/entries_spec.rb +9 -0
  233. data/spec/unit/data_mapper/subject_set/shared/get_spec.rb +9 -0
  234. data/spec/unit/data_mapper/subject_set/shared/include_spec.rb +9 -0
  235. data/spec/unit/data_mapper/subject_set/shared/named_spec.rb +9 -0
  236. data/spec/unit/data_mapper/subject_set/shared/size_spec.rb +13 -0
  237. data/spec/unit/data_mapper/subject_set/shared/to_ary_spec.rb +9 -0
  238. data/spec/unit/data_mapper/subject_set/shared/values_at_spec.rb +44 -0
  239. data/spec/unit/data_mapper/subject_set/size_spec.rb +42 -0
  240. data/spec/unit/data_mapper/subject_set/to_ary_spec.rb +34 -0
  241. data/spec/unit/data_mapper/subject_set/values_at_spec.rb +57 -0
  242. data/spec/unit/hash_spec.rb +28 -0
  243. data/spec/unit/hook_spec.rb +1235 -0
  244. data/spec/unit/inflections_spec.rb +16 -0
  245. data/spec/unit/lazy_array_spec.rb +1949 -0
  246. data/spec/unit/mash_spec.rb +312 -0
  247. data/spec/unit/module_spec.rb +71 -0
  248. data/spec/unit/object_spec.rb +38 -0
  249. data/spec/unit/try_dup_spec.rb +46 -0
  250. data/tasks/ci.rake +1 -0
  251. data/tasks/spec.rake +38 -0
  252. data/tasks/yard.rake +9 -0
  253. data/tasks/yardstick.rake +19 -0
  254. metadata +365 -0
@@ -0,0 +1,88 @@
1
+ require 'spec_helper'
2
+ describe DataMapper::Resource::PersistenceState::Clean do
3
+ before :all do
4
+ class ::Author
5
+ include DataMapper::Resource
6
+
7
+ property :id, HugeInteger, :key => true, :default => 1
8
+ property :name, String
9
+ property :active, Boolean, :default => true
10
+ property :coding, Boolean, :default => true
11
+
12
+ belongs_to :parent, self, :required => false
13
+ has n, :children, self, :inverse => :parent
14
+ end
15
+ DataMapper.finalize
16
+
17
+ @model = Author
18
+ end
19
+
20
+ before do
21
+ @resource = @model.create(:name => 'Dan Kubb')
22
+
23
+ @state = @resource.persistence_state
24
+ @state.should be_kind_of(DataMapper::Resource::PersistenceState::Clean)
25
+ end
26
+
27
+ after do
28
+ @model.destroy!
29
+ end
30
+
31
+ [ :commit, :rollback ].each do |method|
32
+ describe "##{method}" do
33
+ subject { @state.send(method) }
34
+
35
+ supported_by :all do
36
+ it 'should be a no-op' do
37
+ should equal(@state)
38
+ end
39
+ end
40
+ end
41
+ end
42
+
43
+ describe '#delete' do
44
+ subject { @state.delete }
45
+
46
+ supported_by :all do
47
+ it 'should return a Deleted state' do
48
+ should eql(DataMapper::Resource::PersistenceState::Deleted.new(@resource))
49
+ end
50
+ end
51
+ end
52
+
53
+ describe '#get' do
54
+ it_should_behave_like 'Resource::PersistenceState::Persisted#get'
55
+ end
56
+
57
+ describe '#set' do
58
+ subject { @state.set(@key, @value) }
59
+
60
+ supported_by :all do
61
+ describe 'with attributes that make the resource dirty' do
62
+ before do
63
+ @key = @model.properties[:name]
64
+ @value = nil
65
+ end
66
+
67
+ it_should_behave_like 'A method that delegates to the superclass #set'
68
+
69
+ it 'should return a Dirty state' do
70
+ should eql(DataMapper::Resource::PersistenceState::Dirty.new(@resource))
71
+ end
72
+ end
73
+
74
+ describe 'with attributes that keep the resource clean' do
75
+ before do
76
+ @key = @model.properties[:name]
77
+ @value = 'Dan Kubb'
78
+ end
79
+
80
+ it_should_behave_like 'A method that does not delegate to the superclass #set'
81
+
82
+ it 'should return a Clean state' do
83
+ should equal(@state)
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,78 @@
1
+ require 'spec_helper'
2
+ describe DataMapper::Resource::PersistenceState::Deleted do
3
+ before :all do
4
+ class ::Author
5
+ include DataMapper::Resource
6
+
7
+ property :id, HugeInteger, :key => true, :default => 1
8
+ property :name, String
9
+ property :active, Boolean, :default => true
10
+ property :coding, Boolean, :default => true
11
+
12
+ belongs_to :parent, self, :required => false
13
+ has n, :children, self, :inverse => :parent
14
+ end
15
+
16
+ DataMapper.finalize
17
+ @model = Author
18
+ end
19
+
20
+ before do
21
+ @resource = @model.create(:name => 'Dan Kubb')
22
+
23
+ @state = DataMapper::Resource::PersistenceState::Deleted.new(@resource)
24
+ end
25
+
26
+ after do
27
+ @model.destroy!
28
+ end
29
+
30
+ describe '#commit' do
31
+ subject { @state.commit }
32
+
33
+ supported_by :all do
34
+ it 'should return an Immutable state' do
35
+ should eql(DataMapper::Resource::PersistenceState::Immutable.new(@resource))
36
+ end
37
+
38
+ it 'should delete the resource' do
39
+ subject
40
+ @model.get(*@resource.key).should be_nil
41
+ end
42
+
43
+ it 'should remove the resource from the identity map' do
44
+ identity_map = @resource.repository.identity_map(@model)
45
+ method(:subject).should change { identity_map.dup }.from(@resource.key => @resource).to({})
46
+ end
47
+ end
48
+ end
49
+
50
+ describe '#delete' do
51
+ subject { @state.delete }
52
+
53
+ supported_by :all do
54
+ it 'should be a no-op' do
55
+ should equal(@state)
56
+ end
57
+ end
58
+ end
59
+
60
+ describe '#get' do
61
+ it_should_behave_like 'Resource::PersistenceState::Persisted#get'
62
+ end
63
+
64
+ describe '#set' do
65
+ subject { @state.set(@key, @value) }
66
+
67
+ supported_by :all do
68
+ before do
69
+ @key = @model.properties[:name]
70
+ @value = @key.get!(@resource)
71
+ end
72
+
73
+ it 'should raise an exception' do
74
+ method(:subject).should raise_error(DataMapper::ImmutableDeletedError, 'Deleted resource cannot be modified')
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,162 @@
1
+ require 'spec_helper'
2
+ describe DataMapper::Resource::PersistenceState::Dirty do
3
+ before :all do
4
+ class ::Author
5
+ include DataMapper::Resource
6
+
7
+ property :id, HugeInteger, :key => true, :default => 1
8
+ property :name, String
9
+ property :active, Boolean, :default => true
10
+ property :coding, Boolean, :default => true
11
+
12
+ belongs_to :parent, self, :required => false
13
+ has n, :children, self, :inverse => :parent
14
+ end
15
+
16
+ DataMapper.finalize
17
+
18
+ @model = Author
19
+ end
20
+
21
+ before do
22
+ @parent = @model.create(:name => 'Jane Doe')
23
+
24
+ @resource = @model.create(:id => 2, :name => 'Dan Kubb', :parent => @parent)
25
+ @resource.attributes = { :name => 'John Doe' }
26
+
27
+ @state = @resource.persistence_state
28
+ @state.should be_kind_of(DataMapper::Resource::PersistenceState::Dirty)
29
+ end
30
+
31
+ after do
32
+ @model.destroy!
33
+ end
34
+
35
+ describe '#commit' do
36
+ subject { @state.commit }
37
+
38
+ supported_by :all do
39
+ context 'with valid attributes' do
40
+ let(:state) { @state }
41
+
42
+ before do
43
+ @new_id = @resource.id = @resource.id.succ
44
+ end
45
+
46
+ it 'should return a Clean state' do
47
+ should eql(DataMapper::Resource::PersistenceState::Clean.new(@resource))
48
+ end
49
+
50
+ it 'should set the child key if the parent key changes' do
51
+ original_id = @parent.id
52
+ @parent.update(:id => 42).should be(true)
53
+ method(:subject).should change(@resource, :parent_id).from(original_id).to(42)
54
+ end
55
+
56
+ it 'should update the resource' do
57
+ subject
58
+ @model.get!(*@resource.key).should == @resource
59
+ end
60
+
61
+ it 'should update the resource to the identity map if the key changed' do
62
+ identity_map = @resource.repository.identity_map(@model)
63
+ identity_map.should == { @resource.key => @resource }
64
+ subject
65
+ identity_map.should == { [ @new_id ] => @resource }
66
+ end
67
+ end
68
+
69
+ context 'with invalid attributes' do
70
+ before do
71
+ @resource.coding = 'invalid'
72
+ end
73
+
74
+ it 'should raise InvalidValueError' do
75
+ expect { subject }.to(raise_error(DataMapper::Property::InvalidValueError) do |error|
76
+ error.property.should == Author.coding
77
+ end)
78
+ end
79
+
80
+ it 'should not change the identity map' do
81
+ identity_map = @resource.repository.identity_map(@model).dup
82
+ expect { subject }.to raise_error
83
+ identity_map.should == @resource.repository.identity_map(@model)
84
+ end
85
+ end
86
+ end
87
+ end
88
+
89
+ describe '#delete' do
90
+ subject { @state.delete }
91
+
92
+ supported_by :all do
93
+ before do
94
+ @resource.children = [ @resource.parent = @resource ]
95
+ end
96
+
97
+ it_should_behave_like 'It resets resource state'
98
+
99
+ it 'should return a Deleted state' do
100
+ should eql(DataMapper::Resource::PersistenceState::Deleted.new(@resource))
101
+ end
102
+ end
103
+ end
104
+
105
+ describe '#get' do
106
+ before do
107
+ @loaded_value = 'John Doe'
108
+ end
109
+
110
+ it_should_behave_like 'Resource::PersistenceState::Persisted#get'
111
+ end
112
+
113
+ describe '#rollback' do
114
+ subject { @state.rollback }
115
+
116
+ supported_by :all do
117
+ before do
118
+ @resource.children = [ @resource.parent = @resource ]
119
+ end
120
+
121
+ it_should_behave_like 'It resets resource state'
122
+
123
+ it 'should return a Clean state' do
124
+ should eql(DataMapper::Resource::PersistenceState::Clean.new(@resource))
125
+ end
126
+ end
127
+ end
128
+
129
+ describe '#set' do
130
+ subject { @state.set(@key, @value) }
131
+
132
+ supported_by :all do
133
+ describe 'with attributes that keep the resource dirty' do
134
+ before do
135
+ @key = @model.properties[:id]
136
+ @value = @key.get!(@resource)
137
+ end
138
+
139
+ it_should_behave_like 'A method that delegates to the superclass #set'
140
+
141
+ it 'should return a Dirty state' do
142
+ should equal(@state)
143
+ end
144
+
145
+ its(:original_attributes) { should == { @model.properties[:name] => 'Dan Kubb' } }
146
+ end
147
+
148
+ describe 'with attributes that make the resource clean' do
149
+ before do
150
+ @key = @model.properties[:name]
151
+ @value = 'Dan Kubb'
152
+ end
153
+
154
+ it_should_behave_like 'A method that delegates to the superclass #set'
155
+
156
+ it 'should return a Clean state' do
157
+ should eql(DataMapper::Resource::PersistenceState::Clean.new(@resource))
158
+ end
159
+ end
160
+ end
161
+ end
162
+ end
@@ -0,0 +1,105 @@
1
+ require 'spec_helper'
2
+ describe DataMapper::Resource::PersistenceState::Immutable do
3
+ before :all do
4
+ class ::Author
5
+ include DataMapper::Resource
6
+
7
+ property :id, Serial
8
+ property :name, String
9
+ property :active, Boolean, :default => true
10
+ property :coding, Boolean, :default => true
11
+
12
+ belongs_to :parent, self, :required => false
13
+ end
14
+
15
+ DataMapper.finalize
16
+
17
+ @model = Author
18
+ end
19
+
20
+ before do
21
+ @parent = @model.create(:name => 'John Doe')
22
+
23
+ @resource = @model.create(:name => 'Dan Kubb', :parent => @parent)
24
+ attributes = Hash[ @model.key.zip(@resource.key) ]
25
+ @resource = @model.first(attributes.merge(:fields => [ :name, :parent_id ]))
26
+
27
+ @state = @resource.persistence_state
28
+ @state.should be_kind_of(DataMapper::Resource::PersistenceState::Immutable)
29
+ end
30
+
31
+ after do
32
+ @model.destroy!
33
+ end
34
+
35
+ describe '#commit' do
36
+ subject { @state.commit }
37
+
38
+ supported_by :all do
39
+ it 'should be a no-op' do
40
+ should equal(@state)
41
+ end
42
+ end
43
+ end
44
+
45
+ describe '#delete' do
46
+ subject { @state.delete }
47
+
48
+ supported_by :all do
49
+ it 'should raise an exception' do
50
+ method(:subject).should raise_error(DataMapper::ImmutableError, 'Immutable resource cannot be deleted')
51
+ end
52
+ end
53
+ end
54
+
55
+ describe '#get' do
56
+ subject { @state.get(@key) }
57
+
58
+ supported_by :all do
59
+ describe 'with an unloaded property' do
60
+ before do
61
+ @key = @model.properties[:id]
62
+ end
63
+
64
+ it 'should raise an exception' do
65
+ method(:subject).should raise_error(DataMapper::ImmutableError, 'Immutable resource cannot be lazy loaded')
66
+ end
67
+ end
68
+
69
+ describe 'with an unloaded relationship' do
70
+ before do
71
+ @key = @model.relationships[:parent]
72
+ end
73
+
74
+ it 'should return value' do
75
+ should == @parent
76
+ end
77
+ end
78
+
79
+ describe 'with a loaded subject' do
80
+ before do
81
+ @key = @model.properties[:name]
82
+ end
83
+
84
+ it 'should return value' do
85
+ should == 'Dan Kubb'
86
+ end
87
+ end
88
+ end
89
+ end
90
+
91
+ describe '#set' do
92
+ before do
93
+ @key = @model.properties[:name]
94
+ @value = @key.get!(@resource)
95
+ end
96
+
97
+ subject { @state.set(@key, @value) }
98
+
99
+ supported_by :all do
100
+ it 'should raise an exception' do
101
+ method(:subject).should raise_error(DataMapper::ImmutableError, 'Immutable resource cannot be modified')
102
+ end
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,162 @@
1
+ require 'spec_helper'
2
+ describe DataMapper::Resource::PersistenceState::Transient do
3
+ before :all do
4
+ class ::Author
5
+ include DataMapper::Resource
6
+
7
+ property :id, Serial
8
+ property :name, String
9
+ property :age, Integer
10
+ property :description, Text, :default => lambda { |resource, property| resource.name }
11
+ property :active, Boolean, :default => true
12
+ property :coding, Boolean, :default => true
13
+
14
+ belongs_to :parent, self, :required => false
15
+ has n, :children, self, :inverse => :parent
16
+
17
+ belongs_to :with_default, self, :required => false, :default => proc { first(:name => 'John Doe') }
18
+ end
19
+
20
+ DataMapper.finalize
21
+
22
+ @model = Author
23
+ end
24
+
25
+ before do
26
+ @parent = @model.create(:name => 'John Doe')
27
+ @resource = @model.new(:name => 'Dan Kubb', :coding => false, :parent => @parent)
28
+
29
+ @state = @resource.persistence_state
30
+ @state.should be_kind_of(DataMapper::Resource::PersistenceState::Transient)
31
+ end
32
+
33
+ after do
34
+ @model.destroy!
35
+ end
36
+
37
+ describe '#commit' do
38
+ subject { @state.commit }
39
+
40
+ supported_by :all do
41
+ it 'should return the expected Clean state' do
42
+ should eql(DataMapper::Resource::PersistenceState::Clean.new(@resource))
43
+ end
44
+
45
+ it 'should set the serial property' do
46
+ method(:subject).should change(@resource, :id).from(nil)
47
+ end
48
+
49
+ it 'should set the child key if the parent key changes' do
50
+ # SqlServer does not allow updating IDENTITY columns.
51
+ if defined?(DataMapper::Adapters::SqlserverAdapter) &&
52
+ @adapter.kind_of?(DataMapper::Adapters::SqlserverAdapter)
53
+ return
54
+ end
55
+
56
+ original_id = @parent.id
57
+ @parent.update(:id => 42).should be(true)
58
+ method(:subject).should change(@resource, :parent_id).from(original_id).to(42)
59
+ end
60
+
61
+ it 'should set default values' do
62
+ method(:subject).should change { @model.relationships[:with_default].get!(@resource) }.from(nil).to(@parent)
63
+ end
64
+
65
+ it 'should not set default values when they are already set' do
66
+ method(:subject).should_not change(@resource, :coding)
67
+ end
68
+
69
+ it 'should create the resource' do
70
+ subject
71
+ @model.get(*@resource.key).should == @resource
72
+ end
73
+
74
+ it 'should reset original attributes' do
75
+ original_attributes = {
76
+ @model.properties[:name] => nil,
77
+ @model.properties[:coding] => nil,
78
+ @model.properties[:parent_id] => nil,
79
+ @model.relationships[:parent] => nil,
80
+ }
81
+
82
+ expect do
83
+ @resource.persistence_state = subject
84
+ end.should change { @resource.original_attributes.dup }.from(original_attributes).to({})
85
+ end
86
+
87
+ it 'should add the resource to the identity map' do
88
+ DataMapper.repository do |repository|
89
+ identity_map = repository.identity_map(@model)
90
+ identity_map.should be_empty
91
+ subject
92
+ identity_map.should == { @parent.key => @parent, @resource.key => @resource }
93
+ end
94
+ end
95
+ end
96
+ end
97
+
98
+ [ :delete, :rollback ].each do |method|
99
+ describe "##{method}" do
100
+ subject { @state.send(method) }
101
+
102
+ supported_by :all do
103
+ it 'should be a no-op' do
104
+ should equal(@state)
105
+ end
106
+ end
107
+ end
108
+ end
109
+
110
+ describe '#get' do
111
+ subject { @state.get(@key) }
112
+
113
+ supported_by :all do
114
+ describe 'with a set value' do
115
+ before do
116
+ @key = @model.properties[:coding]
117
+ @key.should be_loaded(@resource)
118
+ end
119
+
120
+ it 'should return value' do
121
+ should be(false)
122
+ end
123
+
124
+ it 'should be idempotent' do
125
+ should equal(subject)
126
+ end
127
+ end
128
+
129
+ describe 'with an unset value and no default value' do
130
+ before do
131
+ @key = @model.properties[:age]
132
+ @key.should_not be_loaded(@resource)
133
+ @key.should_not be_default
134
+ end
135
+
136
+ it 'should return nil' do
137
+ should be_nil
138
+ end
139
+
140
+ it 'should be idempotent' do
141
+ should equal(subject)
142
+ end
143
+ end
144
+
145
+ describe 'with an unset value and a default value' do
146
+ before do
147
+ @key = @model.properties[:description]
148
+ @key.should_not be_loaded(@resource)
149
+ @key.should be_default
150
+ end
151
+
152
+ it 'should return the name' do
153
+ should == 'Dan Kubb'
154
+ end
155
+
156
+ it 'should be idempotent' do
157
+ should equal(subject)
158
+ end
159
+ end
160
+ end
161
+ end
162
+ end