sbf-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 (259) hide show
  1. checksums.yaml +7 -0
  2. data/.autotest +29 -0
  3. data/.document +5 -0
  4. data/.gitignore +44 -0
  5. data/.rspec +1 -0
  6. data/.rubocop.yml +468 -0
  7. data/.travis.yml +57 -0
  8. data/.yardopts +1 -0
  9. data/Gemfile +70 -0
  10. data/LICENSE +20 -0
  11. data/README.md +269 -0
  12. data/Rakefile +4 -0
  13. data/dm-core.gemspec +21 -0
  14. data/lib/dm-core/adapters/abstract_adapter.rb +233 -0
  15. data/lib/dm-core/adapters/in_memory_adapter.rb +110 -0
  16. data/lib/dm-core/adapters.rb +249 -0
  17. data/lib/dm-core/associations/many_to_many.rb +477 -0
  18. data/lib/dm-core/associations/many_to_one.rb +282 -0
  19. data/lib/dm-core/associations/one_to_many.rb +332 -0
  20. data/lib/dm-core/associations/one_to_one.rb +84 -0
  21. data/lib/dm-core/associations/relationship.rb +650 -0
  22. data/lib/dm-core/backwards.rb +11 -0
  23. data/lib/dm-core/collection.rb +1486 -0
  24. data/lib/dm-core/core_ext/kernel.rb +21 -0
  25. data/lib/dm-core/core_ext/pathname.rb +4 -0
  26. data/lib/dm-core/core_ext/symbol.rb +10 -0
  27. data/lib/dm-core/identity_map.rb +6 -0
  28. data/lib/dm-core/model/hook.rb +99 -0
  29. data/lib/dm-core/model/is.rb +30 -0
  30. data/lib/dm-core/model/property.rb +244 -0
  31. data/lib/dm-core/model/relationship.rb +366 -0
  32. data/lib/dm-core/model/scope.rb +87 -0
  33. data/lib/dm-core/model.rb +876 -0
  34. data/lib/dm-core/property/binary.rb +19 -0
  35. data/lib/dm-core/property/boolean.rb +35 -0
  36. data/lib/dm-core/property/class.rb +23 -0
  37. data/lib/dm-core/property/date.rb +45 -0
  38. data/lib/dm-core/property/date_time.rb +44 -0
  39. data/lib/dm-core/property/decimal.rb +47 -0
  40. data/lib/dm-core/property/discriminator.rb +40 -0
  41. data/lib/dm-core/property/float.rb +27 -0
  42. data/lib/dm-core/property/integer.rb +32 -0
  43. data/lib/dm-core/property/invalid_value_error.rb +17 -0
  44. data/lib/dm-core/property/lookup.rb +26 -0
  45. data/lib/dm-core/property/numeric.rb +35 -0
  46. data/lib/dm-core/property/object.rb +33 -0
  47. data/lib/dm-core/property/serial.rb +13 -0
  48. data/lib/dm-core/property/string.rb +47 -0
  49. data/lib/dm-core/property/text.rb +12 -0
  50. data/lib/dm-core/property/time.rb +46 -0
  51. data/lib/dm-core/property/typecast/numeric.rb +32 -0
  52. data/lib/dm-core/property/typecast/time.rb +33 -0
  53. data/lib/dm-core/property.rb +856 -0
  54. data/lib/dm-core/property_set.rb +177 -0
  55. data/lib/dm-core/query/conditions/comparison.rb +886 -0
  56. data/lib/dm-core/query/conditions/operation.rb +710 -0
  57. data/lib/dm-core/query/direction.rb +33 -0
  58. data/lib/dm-core/query/operator.rb +34 -0
  59. data/lib/dm-core/query/path.rb +113 -0
  60. data/lib/dm-core/query/sort.rb +38 -0
  61. data/lib/dm-core/query.rb +1352 -0
  62. data/lib/dm-core/relationship_set.rb +69 -0
  63. data/lib/dm-core/repository.rb +226 -0
  64. data/lib/dm-core/resource/persistence_state/clean.rb +36 -0
  65. data/lib/dm-core/resource/persistence_state/deleted.rb +26 -0
  66. data/lib/dm-core/resource/persistence_state/dirty.rb +91 -0
  67. data/lib/dm-core/resource/persistence_state/immutable.rb +32 -0
  68. data/lib/dm-core/resource/persistence_state/persisted.rb +25 -0
  69. data/lib/dm-core/resource/persistence_state/transient.rb +87 -0
  70. data/lib/dm-core/resource/persistence_state.rb +70 -0
  71. data/lib/dm-core/resource.rb +1220 -0
  72. data/lib/dm-core/spec/lib/adapter_helpers.rb +63 -0
  73. data/lib/dm-core/spec/lib/collection_helpers.rb +21 -0
  74. data/lib/dm-core/spec/lib/counter_adapter.rb +38 -0
  75. data/lib/dm-core/spec/lib/pending_helpers.rb +50 -0
  76. data/lib/dm-core/spec/lib/spec_helper.rb +74 -0
  77. data/lib/dm-core/spec/setup.rb +164 -0
  78. data/lib/dm-core/spec/shared/adapter_spec.rb +366 -0
  79. data/lib/dm-core/spec/shared/public/property_spec.rb +229 -0
  80. data/lib/dm-core/spec/shared/resource_spec.rb +1221 -0
  81. data/lib/dm-core/spec/shared/sel_spec.rb +111 -0
  82. data/lib/dm-core/spec/shared/semipublic/property_spec.rb +184 -0
  83. data/lib/dm-core/spec/shared/semipublic/query/conditions/abstract_comparison_spec.rb +261 -0
  84. data/lib/dm-core/support/assertions.rb +8 -0
  85. data/lib/dm-core/support/chainable.rb +18 -0
  86. data/lib/dm-core/support/deprecate.rb +12 -0
  87. data/lib/dm-core/support/descendant_set.rb +89 -0
  88. data/lib/dm-core/support/equalizer.rb +48 -0
  89. data/lib/dm-core/support/ext/array.rb +22 -0
  90. data/lib/dm-core/support/ext/blank.rb +25 -0
  91. data/lib/dm-core/support/ext/hash.rb +67 -0
  92. data/lib/dm-core/support/ext/module.rb +47 -0
  93. data/lib/dm-core/support/ext/object.rb +57 -0
  94. data/lib/dm-core/support/ext/string.rb +24 -0
  95. data/lib/dm-core/support/ext/try_dup.rb +12 -0
  96. data/lib/dm-core/support/hook.rb +388 -0
  97. data/lib/dm-core/support/inflections.rb +60 -0
  98. data/lib/dm-core/support/inflector/inflections.rb +211 -0
  99. data/lib/dm-core/support/inflector/methods.rb +151 -0
  100. data/lib/dm-core/support/lazy_array.rb +451 -0
  101. data/lib/dm-core/support/local_object_space.rb +13 -0
  102. data/lib/dm-core/support/logger.rb +201 -0
  103. data/lib/dm-core/support/mash.rb +176 -0
  104. data/lib/dm-core/support/naming_conventions.rb +109 -0
  105. data/lib/dm-core/support/ordered_set.rb +381 -0
  106. data/lib/dm-core/support/subject.rb +33 -0
  107. data/lib/dm-core/support/subject_set.rb +251 -0
  108. data/lib/dm-core/version.rb +3 -0
  109. data/lib/dm-core.rb +274 -0
  110. data/script/performance.rb +275 -0
  111. data/script/profile.rb +218 -0
  112. data/spec/lib/rspec_immediate_feedback_formatter.rb +54 -0
  113. data/spec/public/associations/many_to_many/read_multiple_join_spec.rb +69 -0
  114. data/spec/public/associations/many_to_many_spec.rb +197 -0
  115. data/spec/public/associations/many_to_one_spec.rb +83 -0
  116. data/spec/public/associations/many_to_one_with_boolean_cpk_spec.rb +40 -0
  117. data/spec/public/associations/many_to_one_with_custom_fk_spec.rb +49 -0
  118. data/spec/public/associations/one_to_many_spec.rb +81 -0
  119. data/spec/public/associations/one_to_one_spec.rb +176 -0
  120. data/spec/public/associations/one_to_one_with_boolean_cpk_spec.rb +46 -0
  121. data/spec/public/collection_spec.rb +69 -0
  122. data/spec/public/finalize_spec.rb +77 -0
  123. data/spec/public/model/hook_spec.rb +245 -0
  124. data/spec/public/model/property_spec.rb +91 -0
  125. data/spec/public/model/relationship_spec.rb +1040 -0
  126. data/spec/public/model_spec.rb +456 -0
  127. data/spec/public/property/binary_spec.rb +43 -0
  128. data/spec/public/property/boolean_spec.rb +21 -0
  129. data/spec/public/property/class_spec.rb +27 -0
  130. data/spec/public/property/date_spec.rb +21 -0
  131. data/spec/public/property/date_time_spec.rb +21 -0
  132. data/spec/public/property/decimal_spec.rb +23 -0
  133. data/spec/public/property/discriminator_spec.rb +134 -0
  134. data/spec/public/property/float_spec.rb +22 -0
  135. data/spec/public/property/integer_spec.rb +22 -0
  136. data/spec/public/property/object_spec.rb +117 -0
  137. data/spec/public/property/serial_spec.rb +22 -0
  138. data/spec/public/property/string_spec.rb +21 -0
  139. data/spec/public/property/text_spec.rb +62 -0
  140. data/spec/public/property/time_spec.rb +21 -0
  141. data/spec/public/property_spec.rb +333 -0
  142. data/spec/public/resource/state_spec.rb +72 -0
  143. data/spec/public/resource_spec.rb +289 -0
  144. data/spec/public/sel_spec.rb +53 -0
  145. data/spec/public/setup_spec.rb +145 -0
  146. data/spec/public/shared/association_collection_shared_spec.rb +309 -0
  147. data/spec/public/shared/collection_finder_shared_spec.rb +267 -0
  148. data/spec/public/shared/collection_shared_spec.rb +1637 -0
  149. data/spec/public/shared/finder_shared_spec.rb +1647 -0
  150. data/spec/semipublic/adapters/abstract_adapter_spec.rb +30 -0
  151. data/spec/semipublic/adapters/in_memory_adapter_spec.rb +13 -0
  152. data/spec/semipublic/associations/many_to_many_spec.rb +94 -0
  153. data/spec/semipublic/associations/many_to_one_spec.rb +63 -0
  154. data/spec/semipublic/associations/one_to_many_spec.rb +55 -0
  155. data/spec/semipublic/associations/one_to_one_spec.rb +53 -0
  156. data/spec/semipublic/associations/relationship_spec.rb +200 -0
  157. data/spec/semipublic/associations_spec.rb +177 -0
  158. data/spec/semipublic/collection_spec.rb +110 -0
  159. data/spec/semipublic/model_spec.rb +96 -0
  160. data/spec/semipublic/property/binary_spec.rb +13 -0
  161. data/spec/semipublic/property/boolean_spec.rb +47 -0
  162. data/spec/semipublic/property/class_spec.rb +33 -0
  163. data/spec/semipublic/property/date_spec.rb +43 -0
  164. data/spec/semipublic/property/date_time_spec.rb +46 -0
  165. data/spec/semipublic/property/decimal_spec.rb +83 -0
  166. data/spec/semipublic/property/discriminator_spec.rb +19 -0
  167. data/spec/semipublic/property/float_spec.rb +82 -0
  168. data/spec/semipublic/property/integer_spec.rb +82 -0
  169. data/spec/semipublic/property/lookup_spec.rb +29 -0
  170. data/spec/semipublic/property/serial_spec.rb +13 -0
  171. data/spec/semipublic/property/string_spec.rb +13 -0
  172. data/spec/semipublic/property/text_spec.rb +31 -0
  173. data/spec/semipublic/property/time_spec.rb +50 -0
  174. data/spec/semipublic/property_spec.rb +114 -0
  175. data/spec/semipublic/query/conditions/comparison_spec.rb +1502 -0
  176. data/spec/semipublic/query/conditions/operation_spec.rb +1296 -0
  177. data/spec/semipublic/query/path_spec.rb +471 -0
  178. data/spec/semipublic/query_spec.rb +3665 -0
  179. data/spec/semipublic/resource/state/clean_spec.rb +89 -0
  180. data/spec/semipublic/resource/state/deleted_spec.rb +79 -0
  181. data/spec/semipublic/resource/state/dirty_spec.rb +163 -0
  182. data/spec/semipublic/resource/state/immutable_spec.rb +107 -0
  183. data/spec/semipublic/resource/state/transient_spec.rb +163 -0
  184. data/spec/semipublic/resource/state_spec.rb +230 -0
  185. data/spec/semipublic/resource_spec.rb +23 -0
  186. data/spec/semipublic/shared/condition_shared_spec.rb +9 -0
  187. data/spec/semipublic/shared/resource_shared_spec.rb +198 -0
  188. data/spec/semipublic/shared/resource_state_shared_spec.rb +91 -0
  189. data/spec/semipublic/shared/subject_shared_spec.rb +79 -0
  190. data/spec/spec_helper.rb +34 -0
  191. data/spec/support/core_ext/hash.rb +10 -0
  192. data/spec/support/core_ext/inheritable_attributes.rb +46 -0
  193. data/spec/support/properties/huge_integer.rb +17 -0
  194. data/spec/unit/array_spec.rb +23 -0
  195. data/spec/unit/blank_spec.rb +73 -0
  196. data/spec/unit/data_mapper/ordered_set/append_spec.rb +26 -0
  197. data/spec/unit/data_mapper/ordered_set/clear_spec.rb +24 -0
  198. data/spec/unit/data_mapper/ordered_set/delete_spec.rb +28 -0
  199. data/spec/unit/data_mapper/ordered_set/each_spec.rb +19 -0
  200. data/spec/unit/data_mapper/ordered_set/empty_spec.rb +20 -0
  201. data/spec/unit/data_mapper/ordered_set/entries_spec.rb +22 -0
  202. data/spec/unit/data_mapper/ordered_set/eql_spec.rb +51 -0
  203. data/spec/unit/data_mapper/ordered_set/equal_value_spec.rb +84 -0
  204. data/spec/unit/data_mapper/ordered_set/hash_spec.rb +12 -0
  205. data/spec/unit/data_mapper/ordered_set/include_spec.rb +23 -0
  206. data/spec/unit/data_mapper/ordered_set/index_spec.rb +28 -0
  207. data/spec/unit/data_mapper/ordered_set/initialize_spec.rb +32 -0
  208. data/spec/unit/data_mapper/ordered_set/merge_spec.rb +36 -0
  209. data/spec/unit/data_mapper/ordered_set/shared/append_spec.rb +24 -0
  210. data/spec/unit/data_mapper/ordered_set/shared/clear_spec.rb +9 -0
  211. data/spec/unit/data_mapper/ordered_set/shared/delete_spec.rb +25 -0
  212. data/spec/unit/data_mapper/ordered_set/shared/each_spec.rb +17 -0
  213. data/spec/unit/data_mapper/ordered_set/shared/empty_spec.rb +9 -0
  214. data/spec/unit/data_mapper/ordered_set/shared/entries_spec.rb +9 -0
  215. data/spec/unit/data_mapper/ordered_set/shared/include_spec.rb +9 -0
  216. data/spec/unit/data_mapper/ordered_set/shared/index_spec.rb +13 -0
  217. data/spec/unit/data_mapper/ordered_set/shared/initialize_spec.rb +28 -0
  218. data/spec/unit/data_mapper/ordered_set/shared/merge_spec.rb +28 -0
  219. data/spec/unit/data_mapper/ordered_set/shared/size_spec.rb +13 -0
  220. data/spec/unit/data_mapper/ordered_set/shared/to_ary_spec.rb +11 -0
  221. data/spec/unit/data_mapper/ordered_set/size_spec.rb +27 -0
  222. data/spec/unit/data_mapper/ordered_set/to_ary_spec.rb +23 -0
  223. data/spec/unit/data_mapper/subject_set/append_spec.rb +47 -0
  224. data/spec/unit/data_mapper/subject_set/clear_spec.rb +34 -0
  225. data/spec/unit/data_mapper/subject_set/delete_spec.rb +40 -0
  226. data/spec/unit/data_mapper/subject_set/each_spec.rb +30 -0
  227. data/spec/unit/data_mapper/subject_set/empty_spec.rb +31 -0
  228. data/spec/unit/data_mapper/subject_set/entries_spec.rb +31 -0
  229. data/spec/unit/data_mapper/subject_set/get_spec.rb +34 -0
  230. data/spec/unit/data_mapper/subject_set/include_spec.rb +32 -0
  231. data/spec/unit/data_mapper/subject_set/named_spec.rb +33 -0
  232. data/spec/unit/data_mapper/subject_set/shared/append_spec.rb +18 -0
  233. data/spec/unit/data_mapper/subject_set/shared/clear_spec.rb +9 -0
  234. data/spec/unit/data_mapper/subject_set/shared/delete_spec.rb +9 -0
  235. data/spec/unit/data_mapper/subject_set/shared/each_spec.rb +9 -0
  236. data/spec/unit/data_mapper/subject_set/shared/empty_spec.rb +9 -0
  237. data/spec/unit/data_mapper/subject_set/shared/entries_spec.rb +9 -0
  238. data/spec/unit/data_mapper/subject_set/shared/get_spec.rb +9 -0
  239. data/spec/unit/data_mapper/subject_set/shared/include_spec.rb +9 -0
  240. data/spec/unit/data_mapper/subject_set/shared/named_spec.rb +9 -0
  241. data/spec/unit/data_mapper/subject_set/shared/size_spec.rb +13 -0
  242. data/spec/unit/data_mapper/subject_set/shared/to_ary_spec.rb +9 -0
  243. data/spec/unit/data_mapper/subject_set/shared/values_at_spec.rb +44 -0
  244. data/spec/unit/data_mapper/subject_set/size_spec.rb +42 -0
  245. data/spec/unit/data_mapper/subject_set/to_ary_spec.rb +34 -0
  246. data/spec/unit/data_mapper/subject_set/values_at_spec.rb +57 -0
  247. data/spec/unit/hash_spec.rb +27 -0
  248. data/spec/unit/hook_spec.rb +1216 -0
  249. data/spec/unit/inflections_spec.rb +14 -0
  250. data/spec/unit/lazy_array_spec.rb +1949 -0
  251. data/spec/unit/mash_spec.rb +289 -0
  252. data/spec/unit/module_spec.rb +70 -0
  253. data/spec/unit/object_spec.rb +38 -0
  254. data/spec/unit/try_dup_spec.rb +46 -0
  255. data/tasks/ci.rake +1 -0
  256. data/tasks/spec.rake +18 -0
  257. data/tasks/yard.rake +9 -0
  258. data/tasks/yardstick.rake +19 -0
  259. metadata +323 -0
@@ -0,0 +1,230 @@
1
+ require_relative '../../spec_helper'
2
+
3
+ describe DataMapper::Resource::PersistenceState 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
+ DataMapper.finalize
16
+
17
+ @model = Author
18
+ end
19
+
20
+ before do
21
+ @resource = @model.new(:name => 'Dan Kubb')
22
+
23
+ @state = DataMapper::Resource::PersistenceState.new(@resource)
24
+ end
25
+
26
+ describe '.new' do
27
+ subject { DataMapper::Resource::PersistenceState.new(@resource) }
28
+
29
+ it { is_expected.to be_kind_of(DataMapper::Resource::PersistenceState) }
30
+ end
31
+
32
+ describe '#==' do
33
+ subject { @state == @other }
34
+
35
+ supported_by :all do
36
+ describe 'with the same class and resource' do
37
+ before do
38
+ @other = DataMapper::Resource::PersistenceState.new(@resource)
39
+ end
40
+
41
+ it { is_expected.to be(true) }
42
+
43
+ it 'Is symmetric' do
44
+ is_expected.to eq(@other == @state)
45
+ end
46
+ end
47
+
48
+ describe 'with the same class and different resource' do
49
+ before do
50
+ @other = DataMapper::Resource::PersistenceState.new(@model.new)
51
+ end
52
+
53
+ it { is_expected.to be(false) }
54
+
55
+ it 'Is symmetric' do
56
+ is_expected.to eq(@other == @state)
57
+ end
58
+ end
59
+
60
+ describe 'with a different class and the same resource' do
61
+ before do
62
+ @other = DataMapper::Resource::PersistenceState::Clean.new(@resource)
63
+ end
64
+
65
+ it 'Is true for a subclass' do
66
+ is_expected.to be(true)
67
+ end
68
+
69
+ it 'Is symmetric' do
70
+ is_expected.to eq(@other == @state)
71
+ end
72
+ end
73
+
74
+ describe 'with a different class and different resource' do
75
+ before do
76
+ @other = DataMapper::Resource::PersistenceState::Clean.new(@model.new)
77
+ end
78
+
79
+ it { is_expected.to be(false) }
80
+
81
+ it 'Is symmetric' do
82
+ is_expected.to eq(@other == @state)
83
+ end
84
+ end
85
+ end
86
+ end
87
+
88
+ [ :commit, :delete, :rollback ].each do |method|
89
+ describe "##{method}" do
90
+ subject { @state.send(method) }
91
+
92
+ it 'Raises an exception' do
93
+ expect { method(:subject) }.to raise_error(NotImplementedError, "DataMapper::Resource::PersistenceState##{method} should be implemented")
94
+ end
95
+ end
96
+ end
97
+
98
+ describe '#eql?' do
99
+ subject { @state.eql?(@other) }
100
+
101
+ supported_by :all do
102
+ describe 'with the same class and resource' do
103
+ before do
104
+ @other = DataMapper::Resource::PersistenceState.new(@resource)
105
+ end
106
+
107
+ it { is_expected.to be(true) }
108
+
109
+ it 'Is symmetric' do
110
+ is_expected.to eq @other.eql?(@state)
111
+ end
112
+ end
113
+
114
+ describe 'with the same class and different resource' do
115
+ before do
116
+ @other = DataMapper::Resource::PersistenceState.new(@model.new)
117
+ end
118
+
119
+ it { is_expected.to be(false) }
120
+
121
+ it 'Is symmetric' do
122
+ is_expected.to eq @other.eql?(@state)
123
+ end
124
+ end
125
+
126
+ describe 'with a different class and the same resource' do
127
+ before do
128
+ @other = DataMapper::Resource::PersistenceState::Clean.new(@resource)
129
+ end
130
+
131
+ it { is_expected.to be(false) }
132
+
133
+ it 'Is symmetric' do
134
+ is_expected.to eq @other.eql?(@state)
135
+ end
136
+ end
137
+
138
+ describe 'with a different class and different resource' do
139
+ before do
140
+ @other = DataMapper::Resource::PersistenceState::Clean.new(@model.new)
141
+ end
142
+
143
+ it { is_expected.to be(false) }
144
+
145
+ it 'Is symmetric' do
146
+ is_expected.to eq @other.eql?(@state)
147
+ end
148
+ end
149
+ end
150
+ end
151
+
152
+ describe '#get' do
153
+ subject { @state.get(@key) }
154
+
155
+ describe 'with a Property subject' do
156
+ before do
157
+ @key = @model.properties[:name]
158
+ end
159
+
160
+ it 'Returns the value' do
161
+ is_expected.to eq 'Dan Kubb'
162
+ end
163
+ end
164
+
165
+ describe 'with a Relationship subject' do
166
+ supported_by :all do
167
+ before do
168
+ # set the association
169
+ @resource.parent = @resource
170
+
171
+ @key = @model.relationships[:parent]
172
+ end
173
+
174
+ it 'Returns the association' do
175
+ is_expected.to eq @resource
176
+ end
177
+ end
178
+ end
179
+ end
180
+
181
+ describe '#hash' do
182
+ subject { @state.hash }
183
+
184
+ it { is_expected.to eq @state.class.hash ^ @resource.hash }
185
+ end
186
+
187
+ describe '#resource' do
188
+ subject { @state.resource }
189
+
190
+ it 'Returns the resource' do
191
+ is_expected.to equal(@resource)
192
+ end
193
+ end
194
+
195
+ describe '#set' do
196
+ subject { @state.set(@key, @value) }
197
+
198
+ describe 'with a Property subject' do
199
+ before do
200
+ @key = @model.properties[:name]
201
+ @value = 'John Doe'
202
+ end
203
+
204
+ it 'Returns a state object' do
205
+ is_expected.to be_kind_of(DataMapper::Resource::PersistenceState)
206
+ end
207
+
208
+ it 'Change the object attributes' do
209
+ expect { method(:subject) }.to change(@resource, :attributes).from(:name => 'Dan Kubb').to(:name => 'John Doe')
210
+ end
211
+ end
212
+
213
+ describe 'with a Relationship subject' do
214
+ supported_by :all do
215
+ before do
216
+ @key = @model.relationships[:parent]
217
+ @value = @resource
218
+ end
219
+
220
+ it 'Returns a state object' do
221
+ is_expected.to be_kind_of(DataMapper::Resource::PersistenceState)
222
+ end
223
+
224
+ it 'Changes the object relationship' do
225
+ expect { method(:subject) }.to change(@resource, :parent).from(nil).to(@resource)
226
+ end
227
+ end
228
+ end
229
+ end
230
+ end
@@ -0,0 +1,23 @@
1
+ require_relative '../spec_helper'
2
+
3
+ describe DataMapper::Resource do
4
+ before :all do
5
+ class ::User
6
+ include DataMapper::Resource
7
+
8
+ property :name, String, :key => true
9
+ property :age, Integer
10
+ property :description, Text
11
+ end
12
+
13
+ @user_model = User
14
+ end
15
+
16
+ supported_by :all do
17
+ before :all do
18
+ @user = @user_model.create(:name => 'dbussink', :age => 25, :description => "Test")
19
+ end
20
+
21
+ it_behaves_like 'A semipublic Resource'
22
+ end
23
+ end
@@ -0,0 +1,9 @@
1
+ shared_examples 'A valid query condition' do
2
+ before :all do
3
+ raise '+@comp+ should be defined in before block' unless instance_variable_get(:@comp)
4
+ end
5
+
6
+ it 'is valid' do
7
+ expect(@comp).to be_valid
8
+ end
9
+ end
@@ -0,0 +1,198 @@
1
+ shared_examples 'A semipublic Resource' do
2
+ before :all do
3
+ %w[ @user_model @user ].each do |ivar|
4
+ raise "+#{ivar}+ should be defined in before block" unless instance_variable_get(ivar)
5
+ end
6
+ end
7
+
8
+ it { expect(@user).to respond_to(:attribute_dirty?) }
9
+
10
+ describe '#attribute_dirty?' do
11
+ describe 'on a non-dirty record' do
12
+ it { expect(@user.attribute_dirty?(:age)).to be(false) }
13
+ end
14
+
15
+ describe 'on a dirty record' do
16
+ before { @user.age = 100 }
17
+
18
+ it { expect(@user.attribute_dirty?(:age)).to be(true) }
19
+ end
20
+
21
+ describe 'on a new record' do
22
+ before { @user = @user_model.new }
23
+
24
+ it { expect(@user.attribute_dirty?(:age)).to be(false) }
25
+ end
26
+ end
27
+
28
+ it { expect(@user).to respond_to(:dirty_attributes) }
29
+
30
+ describe '#dirty_attributes' do
31
+ describe 'on a saved/clean record' do
32
+ it { expect(@user.dirty_attributes).to be_empty }
33
+ end
34
+
35
+ describe 'on a saved/dirty record' do
36
+ before { @user.age = 100 }
37
+
38
+ it { expect(@user.dirty_attributes).to eq({@user_model.properties[:age] => 100}) }
39
+ end
40
+
41
+ describe 'on an saved/set/unset record' do
42
+ before do
43
+ @user.age = 100
44
+ @user.age = 25
45
+ end
46
+
47
+ it { expect(@user.dirty_attributes).to be_empty }
48
+ end
49
+
50
+ describe 'on an saved/unchanged record' do
51
+ before do
52
+ @user.age = 25
53
+ end
54
+
55
+ it { expect(@user.dirty_attributes).to be_empty }
56
+ end
57
+
58
+ describe 'on a new/clean record' do
59
+ before { @user = @user_model.new }
60
+
61
+ it { expect(@user.dirty_attributes).to be_empty }
62
+ end
63
+
64
+ describe 'on a new/dirty record' do
65
+ before { @user = @user_model.new(:age => 100) }
66
+
67
+ it { expect(@user.original_attributes).to eq({@user_model.properties[:age] => nil}) }
68
+ end
69
+
70
+ describe 'on an new/set/unset record' do
71
+ before do
72
+ @user = @user_model.new(:age => 100)
73
+ @user.age = nil
74
+ end
75
+
76
+ it { expect(@user.dirty_attributes).to eq({@user_model.properties[:age] => nil}) }
77
+ end
78
+
79
+ describe 'on an new/unchanged record' do
80
+ before do
81
+ @user = @user_model.new(:age => nil)
82
+ end
83
+
84
+ it { expect(@user.dirty_attributes).to eq({@user_model.properties[:age] => nil}) }
85
+ end
86
+ end
87
+
88
+ it { expect(@user).to respond_to(:original_attributes) }
89
+
90
+ describe '#original_attributes' do
91
+ describe 'on a saved/clean record' do
92
+ it { expect(@user.original_attributes).to be_empty }
93
+ end
94
+
95
+ describe 'on a saved/dirty record' do
96
+ before { @user.age = 100 }
97
+
98
+ it { expect(@user.original_attributes).to eq({@user_model.properties[:age] => 25}) }
99
+ end
100
+
101
+ describe 'on an saved/set/unset record' do
102
+ before do
103
+ @user.age = 100
104
+ @user.age = 25
105
+ end
106
+
107
+ it { expect(@user.original_attributes).to be_empty }
108
+ end
109
+
110
+ describe 'on an saved/unchanged record' do
111
+ before do
112
+ @user.age = 25
113
+ end
114
+
115
+ it { expect(@user.original_attributes).to be_empty }
116
+ end
117
+
118
+ describe 'on a new/clean record' do
119
+ before { @user = @user_model.new }
120
+
121
+ it { expect(@user.original_attributes).to be_empty }
122
+ end
123
+
124
+ describe 'on a new/dirty record' do
125
+ before { @user = @user_model.new(:age => 100) }
126
+
127
+ it { expect(@user.original_attributes).to eq({@user_model.properties[:age] => nil}) }
128
+ end
129
+
130
+ describe 'on an new/set/unset record' do
131
+ before do
132
+ @user = @user_model.new(:age => 100)
133
+ @user.age = nil
134
+ end
135
+
136
+ it { expect(@user.original_attributes).to eq({@user_model.properties[:age] => nil}) }
137
+ end
138
+
139
+ describe 'on an new/unchanged record' do
140
+ before do
141
+ @user = @user_model.new(:age => nil)
142
+ end
143
+
144
+ it { expect(@user.original_attributes).to eq({@user_model.properties[:age] => nil}) }
145
+ end
146
+ end
147
+
148
+ it { expect(@user).to respond_to(:repository) }
149
+
150
+ describe '#repository' do
151
+ before :all do
152
+ class ::Statistic
153
+ include DataMapper::Resource
154
+
155
+ def self.default_repository_name
156
+ :alternate
157
+ end
158
+
159
+ property :id, Serial
160
+ property :name, String
161
+ property :value, Integer
162
+ end
163
+ end
164
+
165
+ with_alternate_adapter do
166
+ before :all do
167
+ if @user_model.respond_to?(:auto_migrate!)
168
+ # force the user model to be available in the alternate repository
169
+ @user_model.auto_migrate!(@adapter.name)
170
+ end
171
+ end
172
+
173
+ it 'Returns the default repository when nothing is specified' do
174
+ default_repository = DataMapper.repository(:default)
175
+ expect(@user_model.create(name: 'carl').repository).to eq default_repository
176
+ expect(@user_model.new.repository).to eq default_repository
177
+ expect(@user_model.get('carl').repository).to eq default_repository
178
+ end
179
+
180
+ it 'Returns the default repository for the model' do
181
+ statistic = Statistic.create(name: 'visits', value: 2)
182
+ expect(statistic.repository).to eq @repository
183
+ expect(Statistic.new.repository).to eq @repository
184
+ expect(Statistic.get(statistic.id).repository).to eq @repository
185
+ end
186
+
187
+ it 'Returns the repository defined by the current context' do
188
+ @repository.scope do
189
+ expect(@user_model.new.repository).to eq @repository
190
+ expect(@user_model.create(name: 'carl').repository).to eq @repository
191
+ expect(@user_model.get('carl').repository).to eq @repository
192
+ end
193
+
194
+ expect(@repository.scope { @user_model.get('carl') }.repository).to eq @repository
195
+ end
196
+ end
197
+ end
198
+ end
@@ -0,0 +1,91 @@
1
+ shared_examples 'A method that delegates to the superclass #set' do
2
+ it 'Delegates to the superclass' do
3
+ # this is the only way I could think of to test if the
4
+ # superclass method is being called
5
+ DataMapper::Resource::PersistenceState.class_eval do
6
+ alias_method :original_set, :set
7
+ undef_method(:set)
8
+ end
9
+ expect { method(:subject) }.to raise_error(NoMethodError)
10
+ DataMapper::Resource::PersistenceState.class_eval do
11
+ alias_method :set, :original_set
12
+ undef_method(:original_set)
13
+ end
14
+ end
15
+ end
16
+
17
+ shared_examples 'A method that does not delegate to the superclass #set' do
18
+ it 'Delegates to the superclass' do
19
+ # this is the only way I could think of to test if the
20
+ # superclass method is not being called
21
+ DataMapper::Resource::PersistenceState.class_eval do
22
+ alias_method :original_set, :set
23
+ undef_method(:set)
24
+ end
25
+ expect { method(:subject) }.not_to raise_error
26
+ DataMapper::Resource::PersistenceState.class_eval do
27
+ alias_method :set, :original_set
28
+ undef_method(:original_set)
29
+ end
30
+ end
31
+ end
32
+
33
+ shared_examples 'It resets resource state' do
34
+ it 'Resets the dirty property' do
35
+ expect { method(:subject) }.to change(@resource, :name).from('John Doe').to('Dan Kubb')
36
+ end
37
+
38
+ it 'Resets the dirty m:1 relationship' do
39
+ expect { method(:subject) }.to change(@resource, :parent).from(@resource).to(nil)
40
+ end
41
+
42
+ it 'Resets the dirty 1:m relationship' do
43
+ expect { method(:subject) }.to change(@resource, :children).from([@resource]).to([])
44
+ end
45
+
46
+ it 'Clear original attributes' do
47
+ expect { method(:subject) }.to change { @resource.original_attributes.dup }.to({})
48
+ end
49
+ end
50
+
51
+ shared_examples 'Resource::PersistenceState::Persisted#get' do
52
+ subject { @state.get(@key) }
53
+
54
+ supported_by :all do
55
+ describe 'with an unloaded subject' do
56
+ before do
57
+ @key = @model.relationships[:parent]
58
+
59
+ # set the parent relationship
60
+ @resource.attributes = {@key => @resource}
61
+ expect(@resource).to be_dirty
62
+ expect(@resource.save).to be(true)
63
+
64
+ attributes = @model.key.zip(@resource.key).to_h
65
+ @resource = @model.first(attributes.merge(fields: @model.key))
66
+ @state = @state.class.new(@resource)
67
+
68
+ # make sure the subject is not loaded
69
+ expect(@key).not_to be_loaded(@resource)
70
+ end
71
+
72
+ it 'Lazy loads the value' do
73
+ expect(subject.key).to eq @resource.key
74
+ end
75
+ end
76
+
77
+ describe 'with a loaded subject' do
78
+ before do
79
+ @key = @model.properties[:name]
80
+ @loaded_value ||= 'Dan Kubb'
81
+
82
+ # make sure the subject is loaded
83
+ expect(@key).to be_loaded(@resource)
84
+ end
85
+
86
+ it 'Returns value' do
87
+ is_expected.to eq @loaded_value
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,79 @@
1
+ shared_examples 'A semipublic Subject' do
2
+ describe '#default?' do
3
+ describe 'with a default' do
4
+ subject { @subject_with_default.default? }
5
+
6
+ it { is_expected.to be(true) }
7
+ end
8
+
9
+ describe 'without a default' do
10
+ subject { @subject_without_default.default? }
11
+
12
+ it { is_expected.to be(false) }
13
+ end
14
+ end
15
+
16
+ describe '#default_for' do
17
+ describe 'without a default' do
18
+ subject { @subject_without_default.default_for(@resource) }
19
+
20
+ it 'Matches the default value' do
21
+ expect(DataMapper::Ext.blank?(subject)).to eq true
22
+ end
23
+
24
+ it 'Is used as a default for the subject accessor' do
25
+ is_expected.to eq @resource.__send__(@subject_without_default.name)
26
+ end
27
+
28
+ it 'Persists the value' do
29
+ expect(@resource.save).to be(true)
30
+ @resource = @resource.model.get!(*@resource.key)
31
+ expect(@resource.without_default).to eq subject
32
+ end
33
+ end
34
+
35
+ describe 'with a default value' do
36
+ subject { @subject_with_default.default_for(@resource) }
37
+
38
+ it 'Matches the default value' do
39
+ if @default_value.is_a?(DataMapper::Resource)
40
+ expect(subject.key).to eq @default_value.key
41
+ else
42
+ is_expected.to eq @default_value
43
+ end
44
+ end
45
+
46
+ it 'Is used as a default for the subject accessor' do
47
+ is_expected.to eq @resource.__send__(@subject_with_default.name)
48
+ end
49
+
50
+ it 'Persists the value' do
51
+ expect(@resource.save).to be(true)
52
+ @resource = @resource.model.get!(*@resource.key)
53
+ expect(@resource.with_default).to eq subject
54
+ end
55
+ end
56
+
57
+ describe 'with a default value responding to #call' do
58
+ subject { @subject_with_default_callable.default_for(@resource) }
59
+
60
+ it 'Matches the default value' do
61
+ if @default_value.is_a?(DataMapper::Resource)
62
+ expect(subject.key).to eq @default_value_callable.key
63
+ else
64
+ is_expected.to eq @default_value_callable
65
+ end
66
+ end
67
+
68
+ it 'Is used as a default for the subject accessor' do
69
+ is_expected.to eq @resource.__send__(@subject_with_default_callable.name)
70
+ end
71
+
72
+ it 'Persists the value' do
73
+ expect(@resource.save).to be(true)
74
+ @resource = @resource.model.get!(*@resource.key)
75
+ expect(@resource.with_default_callable).to eq subject
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,34 @@
1
+ require 'pathname'
2
+ require 'rspec'
3
+ require 'rspec/its'
4
+ require 'dm-core/spec/setup'
5
+
6
+ ENV['ADAPTER'] ||= 'in_memory'
7
+
8
+ SPEC_ROOT = Pathname(__FILE__).dirname.expand_path
9
+ LIB_ROOT = "#{SPEC_ROOT.parent}/lib".freeze
10
+ Pathname.glob("#{LIB_ROOT}/dm-core/spec/**/*.rb".to_s).each { |file| require file }
11
+ Pathname.glob("#{SPEC_ROOT}/{lib,support,*/shared}/**/*.rb".to_s).each { |file| require file }
12
+
13
+ RSpec.configure do |config|
14
+ config.extend(DataMapper::Spec::Adapters::Helpers)
15
+ config.include(DataMapper::Spec::PendingHelpers)
16
+ config.include(DataMapper::Spec::Helpers)
17
+
18
+ config.after :all do
19
+ DataMapper::Spec.cleanup_models
20
+ end
21
+
22
+ config.after :all do
23
+ # global ivar cleanup
24
+ DataMapper::Spec.remove_ivars(self, instance_variables.reject { |ivar| ivar[0, 2] == '@_' })
25
+ end
26
+
27
+ config.after :all do
28
+ # WTF: rspec holds a reference to the last match for some reason.
29
+ # When the object ivars are explicitly removed, this causes weird
30
+ # problems when rspec uses it (!). Why rspec does this I have no
31
+ # idea because I cannot determine the intention from the code.
32
+ DataMapper::Spec.remove_ivars(RSpec::Matchers.last_matcher, %w(@expected))
33
+ end
34
+ end
@@ -0,0 +1,10 @@
1
+ class Hash
2
+ def except(*keys)
3
+ dup.except!(*keys)
4
+ end
5
+
6
+ def except!(*keys)
7
+ keys.each { |key| delete(key) }
8
+ self
9
+ end
10
+ end