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,111 @@
1
+ share_examples_for 'A Collection supporting Strategic Eager Loading' do
2
+ describe 'using SEL when looping within a loop' do
3
+ before :all do
4
+ @many_to_many = @articles.kind_of?(DataMapper::Associations::ManyToMany::Collection)
5
+ end
6
+
7
+ before :all do
8
+ attributes = {}
9
+
10
+ unless @many_to_many
11
+ attributes[:author] = @author
12
+ end
13
+
14
+ @revision = @article.revisions.create(attributes.merge(:title => 'Revision'))
15
+
16
+ @new_article = @article_model.create(attributes.merge(:title => 'Sample Article'))
17
+ @new_revision = @new_article.revisions.create(attributes.merge(:title => 'New Revision'))
18
+ end
19
+
20
+ before :all do
21
+ @original_adapter = @adapter
22
+
23
+ @adapter.singleton_class.class_eval do
24
+ def eql?(other)
25
+ super || self == other
26
+ end
27
+ end
28
+
29
+ @adapter = DataMapper::Repository.adapters[@adapter.name] = CounterAdapter.new(@adapter)
30
+ @repository.instance_variable_set(:@adapter, @adapter)
31
+ @articles.instance_variable_get(:@query).instance_variable_set(:@repository, @repository)
32
+ end
33
+
34
+ before :all do
35
+ @results = []
36
+
37
+ @articles.each do |article|
38
+ article.revisions.each do |revision|
39
+ @results << [ article, revision ]
40
+ end
41
+ end
42
+ end
43
+
44
+ after :all do
45
+ @adapter = @original_adapter
46
+ end
47
+
48
+ it "should only execute the Adapter#read #{loaded ? 'once' : 'twice'}" do
49
+ @adapter.counts[:read].should == (loaded ? 1 : 2)
50
+ end
51
+
52
+ it 'should return the expected results' do
53
+ # if the collection is already loaded, then when it iterates it will
54
+ # not know about the newly added articles and their revisions
55
+ if loaded
56
+ @results.should == [ [ @article, @revision ] ]
57
+ else
58
+ pending_if 'TODO: make m:m not kick when delegating to the relationship', @many_to_many do
59
+ @results.should == [ [ @article, @revision ], [ @new_article, @new_revision ] ]
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
65
+
66
+ share_examples_for 'A Resource supporting Strategic Eager Loading' do
67
+ describe 'using SEL when inside a Collection' do
68
+ before :all do
69
+ @referrer = @user_model.create(:name => 'Referrer', :comment => @comment)
70
+
71
+ @user.update(:referrer => @referrer)
72
+
73
+ @new_user = @user_model.create(:name => 'Another User', :referrer => @referrer, :comment => @comment)
74
+ end
75
+
76
+ before :all do
77
+ @original_adapter = @adapter
78
+
79
+ @adapter.singleton_class.class_eval do
80
+ def eql?(other)
81
+ super || other == self
82
+ end
83
+ end
84
+
85
+ @adapter = DataMapper::Repository.adapters[@adapter.name] = CounterAdapter.new(@adapter)
86
+ @repository.instance_variable_set(:@adapter, @adapter)
87
+ end
88
+
89
+ before :all do
90
+ @results = @user_model.all.map do |user|
91
+ [ user, user.referrer ]
92
+ end
93
+
94
+ # some storage engines return the data in a different order
95
+ @results.sort!
96
+ end
97
+
98
+ after :all do
99
+ @adapter = @original_adapter
100
+ end
101
+
102
+ it 'should only execute the Adapter#read twice' do
103
+ @adapter.counts[:read].should == 2
104
+ end
105
+
106
+ it 'should return the expected results' do
107
+ # results are ordered alphabetically by the User name
108
+ @results.should == [ [ @new_user, @referrer ], [ @referrer, nil ], [ @user, @referrer ] ]
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,176 @@
1
+ share_examples_for 'A semipublic Property' do
2
+ before :all do
3
+ %w[ @type @name @value @other_value ].each do |ivar|
4
+ raise "+#{ivar}+ should be defined in before block" unless instance_variable_defined?(ivar)
5
+ end
6
+
7
+ module ::Blog
8
+ class Article
9
+ include DataMapper::Resource
10
+ property :id, Serial
11
+ end
12
+ end
13
+
14
+ @model = Blog::Article
15
+ @options ||= {}
16
+ @property = @type.new(@model, @name, @options)
17
+ end
18
+
19
+ describe '.new' do
20
+ describe 'when provided no options' do
21
+ it 'should return a Property' do
22
+ @property.should be_kind_of(@type)
23
+ end
24
+
25
+ it 'should set the load_as' do
26
+ @property.load_as.should be(@type.load_as)
27
+ end
28
+
29
+ it 'should set the model' do
30
+ @property.model.should equal(@model)
31
+ end
32
+
33
+ it 'should set the options to the default' do
34
+ @property.options.should == @type.options.merge(@options)
35
+ end
36
+ end
37
+
38
+ [ :index, :unique_index, :unique, :lazy ].each do |attribute|
39
+ [ true, false, :title, [ :title ] ].each do |value|
40
+ describe "when provided #{(options = { attribute => value }).inspect}" do
41
+ before :all do
42
+ @property = @type.new(@model, @name, @options.merge(options))
43
+ end
44
+
45
+ it 'should return a Property' do
46
+ @property.should be_kind_of(@type)
47
+ end
48
+
49
+ it 'should set the model' do
50
+ @property.model.should equal(@model)
51
+ end
52
+
53
+ it 'should set the load_as' do
54
+ @property.load_as.should be(@type.load_as)
55
+ end
56
+
57
+ it "should set the options to #{options.inspect}" do
58
+ @property.options.should == @type.options.merge(@options.merge(options))
59
+ end
60
+ end
61
+ end
62
+
63
+ [ [], nil ].each do |value|
64
+ describe "when provided #{(invalid_options = { attribute => value }).inspect}" do
65
+ it 'should raise an exception' do
66
+ lambda {
67
+ @type.new(@model, @name, @options.merge(invalid_options))
68
+ }.should raise_error(ArgumentError, "options[#{attribute.inspect}] must be either true, false, a Symbol or an Array of Symbols")
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
74
+
75
+ describe '#load' do
76
+ subject { @property.load(@value) }
77
+
78
+ before do
79
+ @property.should_receive(:typecast).with(@value).and_return(@value)
80
+ end
81
+
82
+ it { should eql(@value) }
83
+ end
84
+
85
+ describe "#typecast" do
86
+ describe 'when value is nil' do
87
+ it 'returns value unchanged' do
88
+ @property.typecast(nil).should be(nil)
89
+ end
90
+
91
+ describe 'when value is a Ruby primitive' do
92
+ it 'returns value unchanged' do
93
+ @property.typecast(@value).should == @value
94
+ end
95
+ end
96
+ end
97
+ end
98
+
99
+ describe '#valid?' do
100
+ describe 'when provided a valid value' do
101
+ it 'should return true' do
102
+ @property.valid?(@value).should be(true)
103
+ end
104
+ end
105
+
106
+ describe 'when provide an invalid value' do
107
+ it 'should return false' do
108
+ @property.valid?(@invalid_value).should be(false)
109
+ end
110
+ end
111
+
112
+ describe 'when provide a nil value when required' do
113
+ it 'should return false' do
114
+ @property = @type.new(@model, @name, @options.merge(:required => true))
115
+ @property.valid?(nil).should be(false)
116
+ end
117
+ end
118
+
119
+ describe 'when provide a nil value when not required' do
120
+ it 'should return false' do
121
+ @property = @type.new(@model, @name, @options.merge(:required => false))
122
+ @property.valid?(nil).should be(true)
123
+ end
124
+ end
125
+ end
126
+
127
+ describe '#assert_valid_value' do
128
+ subject do
129
+ @property.assert_valid_value(value)
130
+ end
131
+
132
+ shared_examples_for 'assert_valid_value on invalid value' do
133
+ it 'should raise DataMapper::Property::InvalidValueError' do
134
+ expect { subject }.to(raise_error(DataMapper::Property::InvalidValueError) do |error|
135
+ error.property.should == @property
136
+ end)
137
+ end
138
+ end
139
+
140
+ describe 'when provided a valid value' do
141
+ let(:value) { @value }
142
+
143
+ it 'should return true' do
144
+ subject.should be(true)
145
+ end
146
+ end
147
+
148
+ describe 'when provide an invalid value' do
149
+ let(:value) { @invalid_value }
150
+
151
+ it_should_behave_like 'assert_valid_value on invalid value'
152
+ end
153
+
154
+ describe 'when provide a nil value when required' do
155
+ before do
156
+ @property = @type.new(@model, @name, @options.merge(:required => true))
157
+ end
158
+
159
+ let(:value) { nil }
160
+
161
+ it_should_behave_like 'assert_valid_value on invalid value'
162
+ end
163
+
164
+ describe 'when provide a nil value when not required' do
165
+ before do
166
+ @property = @type.new(@model, @name, @options.merge(:required => false))
167
+ end
168
+
169
+ let(:value) { nil }
170
+
171
+ it 'should return true' do
172
+ subject.should be(true)
173
+ end
174
+ end
175
+ end
176
+ end
@@ -0,0 +1,261 @@
1
+ shared_examples_for 'DataMapper::Query::Conditions::AbstractComparison' do
2
+ before :all do
3
+ module ::Blog
4
+ class Article
5
+ include DataMapper::Resource
6
+
7
+ property :id, Serial
8
+ property :title, String, :required => true
9
+
10
+ belongs_to :parent, self, :required => false
11
+ has n, :children, self, :inverse => :parent
12
+ end
13
+ end
14
+
15
+ DataMapper.finalize
16
+
17
+ @model = Blog::Article
18
+ end
19
+
20
+ before do
21
+ class ::OtherComparison < DataMapper::Query::Conditions::AbstractComparison
22
+ slug :other
23
+ end
24
+ end
25
+
26
+ before do
27
+ @relationship = @model.relationships[:parent]
28
+ end
29
+
30
+ it { subject.class.should respond_to(:new) }
31
+
32
+ describe '.new' do
33
+ subject { @comparison.class.new(@property, @value) }
34
+
35
+ it { should be_kind_of(@comparison.class) }
36
+
37
+ it { subject.subject.should equal(@property) }
38
+
39
+ it { subject.value.should == @value }
40
+ end
41
+
42
+ it { subject.class.should respond_to(:slug) }
43
+
44
+ describe '.slug' do
45
+ describe 'with no arguments' do
46
+ subject { @comparison.class.slug }
47
+
48
+ it { should == @slug }
49
+ end
50
+
51
+ describe 'with an argument' do
52
+ subject { @comparison.class.slug(:other) }
53
+
54
+ it { should == :other }
55
+
56
+ # reset the slug
57
+ after { @comparison.class.slug(@slug) }
58
+ end
59
+ end
60
+
61
+ it { should respond_to(:==) }
62
+
63
+ describe '#==' do
64
+ describe 'when the other AbstractComparison is equal' do
65
+ # artificially modify the object so #== will throw an
66
+ # exception if the equal? branch is not followed when heckling
67
+ before { @comparison.singleton_class.send(:undef_method, :slug) }
68
+
69
+ subject { @comparison == @comparison }
70
+
71
+ it { should be(true) }
72
+ end
73
+
74
+ describe 'when the other AbstractComparison is the same class' do
75
+ subject { @comparison == DataMapper::Query::Conditions::Comparison.new(@slug, @property, @value) }
76
+
77
+ it { should be(true) }
78
+ end
79
+
80
+ describe 'when the other AbstractComparison is a different class' do
81
+ subject { @comparison == DataMapper::Query::Conditions::Comparison.new(:other, @property, @value) }
82
+
83
+ it { should be(false) }
84
+ end
85
+
86
+ describe 'when the other AbstractComparison is the same class, with different property' do
87
+ subject { @comparison == DataMapper::Query::Conditions::Comparison.new(@slug, @other_property, @value) }
88
+
89
+ it { should be(false) }
90
+ end
91
+
92
+ describe 'when the other AbstractComparison is the same class, with different value' do
93
+ subject { @comparison == DataMapper::Query::Conditions::Comparison.new(@slug, @property, @other_value) }
94
+
95
+ it { should be(false) }
96
+ end
97
+ end
98
+
99
+ it { should respond_to(:eql?) }
100
+
101
+ describe '#eql?' do
102
+ describe 'when the other AbstractComparison is equal' do
103
+ # artificially modify the object so #eql? will throw an
104
+ # exception if the equal? branch is not followed when heckling
105
+ before { @comparison.singleton_class.send(:undef_method, :slug) }
106
+
107
+ subject { @comparison.eql?(@comparison) }
108
+
109
+ it { should be(true) }
110
+ end
111
+
112
+ describe 'when the other AbstractComparison is the same class' do
113
+ subject { @comparison.eql?(DataMapper::Query::Conditions::Comparison.new(@slug, @property, @value)) }
114
+
115
+ it { should be(true) }
116
+ end
117
+
118
+ describe 'when the other AbstractComparison is a different class' do
119
+ subject { @comparison.eql?(DataMapper::Query::Conditions::Comparison.new(:other, @property, @value)) }
120
+
121
+ it { should be(false) }
122
+ end
123
+
124
+ describe 'when the other AbstractComparison is the same class, with different property' do
125
+ subject { @comparison.eql?(DataMapper::Query::Conditions::Comparison.new(@slug, @other_property, @value)) }
126
+
127
+ it { should be(false) }
128
+ end
129
+
130
+ describe 'when the other AbstractComparison is the same class, with different value' do
131
+ subject { @comparison.eql?(DataMapper::Query::Conditions::Comparison.new(@slug, @property, @other_value)) }
132
+
133
+ it { should be(false) }
134
+ end
135
+ end
136
+
137
+ it { should respond_to(:hash) }
138
+
139
+ describe '#hash' do
140
+ subject { @comparison.hash }
141
+
142
+ it 'should match the same AbstractComparison with the same property and value' do
143
+ should == DataMapper::Query::Conditions::Comparison.new(@slug, @property, @value).hash
144
+ end
145
+
146
+ it 'should not match the same AbstractComparison with different property' do
147
+ should_not == DataMapper::Query::Conditions::Comparison.new(@slug, @other_property, @value).hash
148
+ end
149
+
150
+ it 'should not match the same AbstractComparison with different value' do
151
+ should_not == DataMapper::Query::Conditions::Comparison.new(@slug, @property, @other_value).hash
152
+ end
153
+
154
+ it 'should not match a different AbstractComparison with the same property and value' do
155
+ should_not == @other.hash
156
+ end
157
+
158
+ it 'should not match a different AbstractComparison with different property' do
159
+ should_not == @other.class.new(@other_property, @value).hash
160
+ end
161
+
162
+ it 'should not match a different AbstractComparison with different value' do
163
+ should_not == @other.class.new(@property, @other_value).hash
164
+ end
165
+ end
166
+
167
+ it { should respond_to(:loaded_value) }
168
+
169
+ describe '#loaded_value' do
170
+ subject { @comparison.loaded_value }
171
+
172
+ it { should == @value }
173
+ end
174
+
175
+ it { should respond_to(:parent) }
176
+
177
+ describe '#parent' do
178
+ subject { @comparison.parent }
179
+
180
+ describe 'should be nil by default' do
181
+ it { should be_nil }
182
+ end
183
+
184
+ describe 'should relate to parent operation' do
185
+ before do
186
+ @operation = DataMapper::Query::Conditions::Operation.new(:and)
187
+ @comparison.parent = @operation
188
+ end
189
+
190
+ it { should be_equal(@operation) }
191
+ end
192
+ end
193
+
194
+ it { should respond_to(:parent=) }
195
+
196
+ describe '#parent=' do
197
+ before do
198
+ @operation = DataMapper::Query::Conditions::Operation.new(:and)
199
+ end
200
+
201
+ subject { @comparison.parent = @operation }
202
+
203
+ it { should equal(@operation) }
204
+
205
+ it 'should change the parent' do
206
+ method(:subject).should change(@comparison, :parent).
207
+ from(nil).
208
+ to(@operation)
209
+ end
210
+ end
211
+
212
+ it { should respond_to(:property?) }
213
+
214
+ describe '#property?' do
215
+ subject { @comparison.property? }
216
+
217
+ it { should be(true) }
218
+ end
219
+
220
+ it { should respond_to(:slug) }
221
+
222
+ describe '#slug' do
223
+ subject { @comparison.slug }
224
+
225
+ it { should == @slug }
226
+ end
227
+
228
+ it { should respond_to(:subject) }
229
+
230
+ describe '#subject' do
231
+ subject { @comparison.subject }
232
+
233
+ it { should be_equal(@property) }
234
+ end
235
+
236
+ it { should respond_to(:valid?) }
237
+
238
+ describe '#valid?' do
239
+ subject { @comparison.valid? }
240
+
241
+ describe 'when the value is valid for the subject' do
242
+ it { should be(true) }
243
+ end
244
+
245
+ describe 'when the value is not valid for the subject' do
246
+ before do
247
+ @comparison = DataMapper::Query::Conditions::Comparison.new(@slug, @property, nil)
248
+ end
249
+
250
+ it { should be(false) }
251
+ end
252
+ end
253
+
254
+ it { should respond_to(:value) }
255
+
256
+ describe '#value' do
257
+ subject { @comparison.value }
258
+
259
+ it { should == @value }
260
+ end
261
+ end