ardm-core 1.2.1

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 +35 -0
  5. data/.travis.yml +23 -0
  6. data/.yardopts +1 -0
  7. data/Gemfile +63 -0
  8. data/LICENSE +20 -0
  9. data/README.rdoc +237 -0
  10. data/Rakefile +4 -0
  11. data/VERSION +1 -0
  12. data/ardm-core.gemspec +25 -0
  13. data/lib/ardm-core.rb +1 -0
  14. data/lib/dm-core.rb +285 -0
  15. data/lib/dm-core/adapters.rb +222 -0
  16. data/lib/dm-core/adapters/abstract_adapter.rb +236 -0
  17. data/lib/dm-core/adapters/in_memory_adapter.rb +113 -0
  18. data/lib/dm-core/associations/many_to_many.rb +496 -0
  19. data/lib/dm-core/associations/many_to_one.rb +296 -0
  20. data/lib/dm-core/associations/one_to_many.rb +345 -0
  21. data/lib/dm-core/associations/one_to_one.rb +86 -0
  22. data/lib/dm-core/associations/relationship.rb +663 -0
  23. data/lib/dm-core/backwards.rb +13 -0
  24. data/lib/dm-core/collection.rb +1514 -0
  25. data/lib/dm-core/core_ext/kernel.rb +23 -0
  26. data/lib/dm-core/core_ext/pathname.rb +6 -0
  27. data/lib/dm-core/core_ext/symbol.rb +10 -0
  28. data/lib/dm-core/identity_map.rb +7 -0
  29. data/lib/dm-core/model.rb +869 -0
  30. data/lib/dm-core/model/hook.rb +102 -0
  31. data/lib/dm-core/model/is.rb +32 -0
  32. data/lib/dm-core/model/property.rb +253 -0
  33. data/lib/dm-core/model/relationship.rb +377 -0
  34. data/lib/dm-core/model/scope.rb +89 -0
  35. data/lib/dm-core/property.rb +839 -0
  36. data/lib/dm-core/property/binary.rb +22 -0
  37. data/lib/dm-core/property/boolean.rb +31 -0
  38. data/lib/dm-core/property/class.rb +24 -0
  39. data/lib/dm-core/property/date.rb +45 -0
  40. data/lib/dm-core/property/date_time.rb +44 -0
  41. data/lib/dm-core/property/decimal.rb +50 -0
  42. data/lib/dm-core/property/discriminator.rb +46 -0
  43. data/lib/dm-core/property/float.rb +28 -0
  44. data/lib/dm-core/property/integer.rb +32 -0
  45. data/lib/dm-core/property/lookup.rb +29 -0
  46. data/lib/dm-core/property/numeric.rb +40 -0
  47. data/lib/dm-core/property/object.rb +28 -0
  48. data/lib/dm-core/property/serial.rb +13 -0
  49. data/lib/dm-core/property/string.rb +50 -0
  50. data/lib/dm-core/property/text.rb +12 -0
  51. data/lib/dm-core/property/time.rb +46 -0
  52. data/lib/dm-core/property/typecast/numeric.rb +32 -0
  53. data/lib/dm-core/property/typecast/time.rb +33 -0
  54. data/lib/dm-core/property_set.rb +177 -0
  55. data/lib/dm-core/query.rb +1444 -0
  56. data/lib/dm-core/query/conditions/comparison.rb +910 -0
  57. data/lib/dm-core/query/conditions/operation.rb +720 -0
  58. data/lib/dm-core/query/direction.rb +36 -0
  59. data/lib/dm-core/query/operator.rb +35 -0
  60. data/lib/dm-core/query/path.rb +114 -0
  61. data/lib/dm-core/query/sort.rb +39 -0
  62. data/lib/dm-core/relationship_set.rb +72 -0
  63. data/lib/dm-core/repository.rb +226 -0
  64. data/lib/dm-core/resource.rb +1228 -0
  65. data/lib/dm-core/resource/persistence_state.rb +75 -0
  66. data/lib/dm-core/resource/persistence_state/clean.rb +40 -0
  67. data/lib/dm-core/resource/persistence_state/deleted.rb +30 -0
  68. data/lib/dm-core/resource/persistence_state/dirty.rb +96 -0
  69. data/lib/dm-core/resource/persistence_state/immutable.rb +34 -0
  70. data/lib/dm-core/resource/persistence_state/persisted.rb +29 -0
  71. data/lib/dm-core/resource/persistence_state/transient.rb +78 -0
  72. data/lib/dm-core/spec/lib/adapter_helpers.rb +54 -0
  73. data/lib/dm-core/spec/lib/collection_helpers.rb +20 -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 +173 -0
  78. data/lib/dm-core/spec/shared/adapter_spec.rb +326 -0
  79. data/lib/dm-core/spec/shared/public/property_spec.rb +229 -0
  80. data/lib/dm-core/spec/shared/resource_spec.rb +1236 -0
  81. data/lib/dm-core/spec/shared/sel_spec.rb +111 -0
  82. data/lib/dm-core/spec/shared/semipublic/property_spec.rb +134 -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 +402 -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 +12 -0
  102. data/lib/dm-core/support/logger.rb +199 -0
  103. data/lib/dm-core/support/mash.rb +176 -0
  104. data/lib/dm-core/support/naming_conventions.rb +90 -0
  105. data/lib/dm-core/support/ordered_set.rb +380 -0
  106. data/lib/dm-core/support/subject.rb +33 -0
  107. data/lib/dm-core/support/subject_set.rb +250 -0
  108. data/lib/dm-core/version.rb +3 -0
  109. data/script/performance.rb +275 -0
  110. data/script/profile.rb +218 -0
  111. data/spec/lib/rspec_immediate_feedback_formatter.rb +54 -0
  112. data/spec/public/associations/many_to_many/read_multiple_join_spec.rb +68 -0
  113. data/spec/public/associations/many_to_many_spec.rb +197 -0
  114. data/spec/public/associations/many_to_one_spec.rb +83 -0
  115. data/spec/public/associations/many_to_one_with_boolean_cpk_spec.rb +40 -0
  116. data/spec/public/associations/many_to_one_with_custom_fk_spec.rb +49 -0
  117. data/spec/public/associations/one_to_many_spec.rb +81 -0
  118. data/spec/public/associations/one_to_one_spec.rb +176 -0
  119. data/spec/public/associations/one_to_one_with_boolean_cpk_spec.rb +46 -0
  120. data/spec/public/collection_spec.rb +69 -0
  121. data/spec/public/finalize_spec.rb +76 -0
  122. data/spec/public/model/hook_spec.rb +246 -0
  123. data/spec/public/model/property_spec.rb +88 -0
  124. data/spec/public/model/relationship_spec.rb +1040 -0
  125. data/spec/public/model_spec.rb +458 -0
  126. data/spec/public/property/binary_spec.rb +41 -0
  127. data/spec/public/property/boolean_spec.rb +22 -0
  128. data/spec/public/property/class_spec.rb +28 -0
  129. data/spec/public/property/date_spec.rb +22 -0
  130. data/spec/public/property/date_time_spec.rb +22 -0
  131. data/spec/public/property/decimal_spec.rb +23 -0
  132. data/spec/public/property/discriminator_spec.rb +135 -0
  133. data/spec/public/property/float_spec.rb +22 -0
  134. data/spec/public/property/integer_spec.rb +22 -0
  135. data/spec/public/property/object_spec.rb +107 -0
  136. data/spec/public/property/serial_spec.rb +22 -0
  137. data/spec/public/property/string_spec.rb +22 -0
  138. data/spec/public/property/text_spec.rb +63 -0
  139. data/spec/public/property/time_spec.rb +22 -0
  140. data/spec/public/property_spec.rb +341 -0
  141. data/spec/public/resource_spec.rb +284 -0
  142. data/spec/public/sel_spec.rb +53 -0
  143. data/spec/public/setup_spec.rb +145 -0
  144. data/spec/public/shared/association_collection_shared_spec.rb +309 -0
  145. data/spec/public/shared/collection_finder_shared_spec.rb +267 -0
  146. data/spec/public/shared/collection_shared_spec.rb +1669 -0
  147. data/spec/public/shared/finder_shared_spec.rb +1629 -0
  148. data/spec/rcov.opts +6 -0
  149. data/spec/semipublic/adapters/abstract_adapter_spec.rb +30 -0
  150. data/spec/semipublic/adapters/in_memory_adapter_spec.rb +12 -0
  151. data/spec/semipublic/associations/many_to_many_spec.rb +94 -0
  152. data/spec/semipublic/associations/many_to_one_spec.rb +63 -0
  153. data/spec/semipublic/associations/one_to_many_spec.rb +55 -0
  154. data/spec/semipublic/associations/one_to_one_spec.rb +53 -0
  155. data/spec/semipublic/associations/relationship_spec.rb +200 -0
  156. data/spec/semipublic/associations_spec.rb +177 -0
  157. data/spec/semipublic/collection_spec.rb +110 -0
  158. data/spec/semipublic/model_spec.rb +96 -0
  159. data/spec/semipublic/property/binary_spec.rb +13 -0
  160. data/spec/semipublic/property/boolean_spec.rb +47 -0
  161. data/spec/semipublic/property/class_spec.rb +33 -0
  162. data/spec/semipublic/property/date_spec.rb +43 -0
  163. data/spec/semipublic/property/date_time_spec.rb +46 -0
  164. data/spec/semipublic/property/decimal_spec.rb +83 -0
  165. data/spec/semipublic/property/discriminator_spec.rb +19 -0
  166. data/spec/semipublic/property/float_spec.rb +82 -0
  167. data/spec/semipublic/property/integer_spec.rb +82 -0
  168. data/spec/semipublic/property/lookup_spec.rb +29 -0
  169. data/spec/semipublic/property/serial_spec.rb +13 -0
  170. data/spec/semipublic/property/string_spec.rb +13 -0
  171. data/spec/semipublic/property/text_spec.rb +31 -0
  172. data/spec/semipublic/property/time_spec.rb +50 -0
  173. data/spec/semipublic/property_spec.rb +114 -0
  174. data/spec/semipublic/query/conditions/comparison_spec.rb +1501 -0
  175. data/spec/semipublic/query/conditions/operation_spec.rb +1294 -0
  176. data/spec/semipublic/query/path_spec.rb +471 -0
  177. data/spec/semipublic/query_spec.rb +3777 -0
  178. data/spec/semipublic/resource/state/clean_spec.rb +88 -0
  179. data/spec/semipublic/resource/state/deleted_spec.rb +78 -0
  180. data/spec/semipublic/resource/state/dirty_spec.rb +156 -0
  181. data/spec/semipublic/resource/state/immutable_spec.rb +105 -0
  182. data/spec/semipublic/resource/state/transient_spec.rb +162 -0
  183. data/spec/semipublic/resource/state_spec.rb +230 -0
  184. data/spec/semipublic/resource_spec.rb +23 -0
  185. data/spec/semipublic/shared/condition_shared_spec.rb +9 -0
  186. data/spec/semipublic/shared/resource_shared_spec.rb +199 -0
  187. data/spec/semipublic/shared/resource_state_shared_spec.rb +79 -0
  188. data/spec/semipublic/shared/subject_shared_spec.rb +79 -0
  189. data/spec/spec.opts +5 -0
  190. data/spec/spec_helper.rb +37 -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 +28 -0
  248. data/spec/unit/hook_spec.rb +1235 -0
  249. data/spec/unit/lazy_array_spec.rb +1949 -0
  250. data/spec/unit/mash_spec.rb +312 -0
  251. data/spec/unit/module_spec.rb +71 -0
  252. data/spec/unit/object_spec.rb +38 -0
  253. data/spec/unit/try_dup_spec.rb +46 -0
  254. data/tasks/ci.rake +1 -0
  255. data/tasks/db.rake +11 -0
  256. data/tasks/spec.rake +38 -0
  257. data/tasks/yard.rake +9 -0
  258. data/tasks/yardstick.rake +19 -0
  259. metadata +491 -0
@@ -0,0 +1,20 @@
1
+ module DataMapper
2
+ module Spec
3
+ module CollectionHelpers
4
+ module GroupMethods
5
+ def self.extended(base)
6
+ base.class_inheritable_accessor :loaded
7
+ base.loaded = false
8
+ end
9
+
10
+ def should_not_be_a_kicker(ivar = :@articles)
11
+ unless loaded
12
+ it 'should not be a kicker' do
13
+ instance_variable_get(ivar).should_not be_loaded
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,38 @@
1
+ class CounterAdapter < DataMapper::Adapters::AbstractAdapter
2
+ instance_methods.each do |method|
3
+ next if method =~ /\A__/ ||
4
+ %w[ send class dup object_id kind_of? instance_of? respond_to? equal? freeze frozen? should should_not instance_variables instance_variable_set instance_variable_get instance_variable_defined? remove_instance_variable extend inspect copy_object ].include?(method.to_s)
5
+ undef_method method
6
+ end
7
+
8
+ attr_reader :counts
9
+
10
+ def kind_of?(klass)
11
+ super || @adapter.kind_of?(klass)
12
+ end
13
+
14
+ def instance_of?(klass)
15
+ super || @adapter.instance_of?(klass)
16
+ end
17
+
18
+ def respond_to?(method, include_private = false)
19
+ super || @adapter.respond_to?(method, include_private)
20
+ end
21
+
22
+ private
23
+
24
+ def initialize(adapter)
25
+ @counts = Hash.new { |hash, key| hash[key] = 0 }
26
+ @adapter = adapter
27
+ @count = 0
28
+ end
29
+
30
+ def increment_count_for(method)
31
+ @counts[method] += 1
32
+ end
33
+
34
+ def method_missing(method, *args, &block)
35
+ increment_count_for(method)
36
+ @adapter.send(method, *args, &block)
37
+ end
38
+ end
@@ -0,0 +1,50 @@
1
+ module DataMapper
2
+ module Spec
3
+ module PendingHelpers
4
+
5
+ def pending_if(*args)
6
+ message, boolean = parse_args(*args)
7
+
8
+ if boolean
9
+ pending(message) { yield }
10
+ else
11
+ yield
12
+ end
13
+ end
14
+
15
+ def rescue_if(*args)
16
+ message, boolean = parse_args(*args)
17
+
18
+ if boolean
19
+ raised = nil
20
+ begin
21
+ yield
22
+ raised = false
23
+ rescue Exception
24
+ raised = true
25
+ end
26
+
27
+ raise "should have raised: #{message || 'TODO'}" if raised == false
28
+ else
29
+ yield
30
+ end
31
+ end
32
+
33
+ private
34
+
35
+ def parse_args(*args)
36
+ case args.map { |arg| arg.class }
37
+ when [ String, TrueClass ], [ String, FalseClass ] then args
38
+ when [ String, NilClass ] then [ args.first, false ]
39
+ when [ String ] then [ args.first, true ]
40
+ when [ TrueClass ], [ FalseClass ] then [ '', args.first ]
41
+ when [ NilClass ] then [ '', false ]
42
+ when [] then [ '', true ] # defaults
43
+ else
44
+ raise ArgumentError, "Invalid arguments: #{args.inspect}"
45
+ end
46
+ end
47
+
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,74 @@
1
+ module DataMapper
2
+ module Spec
3
+
4
+ module Helpers
5
+ def reset_raise_on_save_failure(object)
6
+ object.instance_eval do
7
+ if defined?(@raise_on_save_failure)
8
+ remove_instance_variable(:@raise_on_save_failure)
9
+ end
10
+ end
11
+ end
12
+ end
13
+
14
+ # global model cleanup
15
+ def self.cleanup_models
16
+ descendants = DataMapper::Model.descendants.to_a
17
+
18
+ while model = descendants.shift
19
+ model_name = model.name.to_s.strip
20
+
21
+ unless model_name.empty? || model_name[0] == ?#
22
+ parts = model_name.split('::')
23
+ constant_name = parts.pop.to_sym
24
+ base = parts.empty? ? Object : DataMapper::Ext::Object.full_const_get(parts.join('::'))
25
+
26
+ base.class_eval { remove_const(constant_name) if const_defined?(constant_name) }
27
+ end
28
+
29
+ remove_ivars(model)
30
+ model.instance_methods(false).each { |method| model.send(:undef_method, method) }
31
+
32
+ end
33
+
34
+ DataMapper::Model.descendants.clear
35
+ end
36
+
37
+ def self.remove_ivars(object, instance_variables = object.instance_variables)
38
+ seen = {}
39
+ stack = instance_variables.map { |var| [ object, var ] }
40
+
41
+ while node = stack.pop
42
+ object, ivar = node
43
+
44
+ # skip "global" and non-DM objects
45
+ next if object.kind_of?(DataMapper::Logger) ||
46
+ object.kind_of?(DataMapper::DescendantSet) ||
47
+ object.kind_of?(DataMapper::Adapters::AbstractAdapter) ||
48
+ object.class.name[0, 13] == 'DataObjects::'
49
+
50
+ # skip classes and modules in the DataMapper namespace
51
+ next if object.kind_of?(Module) &&
52
+ !object.name.nil? &&
53
+ object.name[0, 12] == 'DataMapper::'
54
+
55
+ # skip when the ivar is no longer defined in the object
56
+ next unless object.instance_variable_defined?(ivar)
57
+
58
+ value = object.instance_variable_get(ivar)
59
+
60
+ # skip descendant sets
61
+ next if value.kind_of?(DataMapper::DescendantSet)
62
+
63
+ object.__send__(:remove_instance_variable, ivar) unless object.frozen?
64
+
65
+ # skip when the value was seen
66
+ next if seen.key?(value.object_id)
67
+ seen[value.object_id] = true
68
+
69
+ stack.concat value.instance_variables.map { |ivar| [ value, ivar ] }
70
+ end
71
+ end
72
+
73
+ end
74
+ end
@@ -0,0 +1,173 @@
1
+ require 'dm-core'
2
+
3
+ module DataMapper
4
+ module Spec
5
+
6
+ class << self
7
+
8
+ def root
9
+ @root ||= default_root
10
+ end
11
+
12
+ def root=(path)
13
+ @root = Pathname(path)
14
+ end
15
+
16
+ %w[setup setup! adapter adapter_name].each do |action|
17
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
18
+ def #{action}(kind = :default)
19
+ perform_action(kind, :#{action})
20
+ end
21
+ RUBY
22
+ end
23
+
24
+ def configure
25
+ @configured = begin
26
+ setup_logger
27
+ require_plugins
28
+ require_spec_adapter
29
+ true
30
+ end
31
+ end
32
+
33
+ def configured?
34
+ @configured
35
+ end
36
+
37
+ def setup_logger
38
+ if log = ENV['LOG']
39
+ logger = DataMapper::Logger.new(log_stream(log), :debug)
40
+ logger.auto_flush = true
41
+ end
42
+ end
43
+
44
+ def require_spec_adapter
45
+ desired_adapter = ENV['ADAPTER']
46
+ if desired_adapter.nil? || desired_adapter == 'in_memory'
47
+ ENV['ADAPTER_SUPPORTS'] = 'all'
48
+ Adapters.use(Adapters::InMemoryAdapter)
49
+ else
50
+ require "dm-#{desired_adapter}-adapter/spec/setup"
51
+ end
52
+ end
53
+
54
+ def require_plugins
55
+ plugins = ENV['PLUGINS'] || ENV['PLUGIN']
56
+ plugins = plugins.to_s.split(/[,\s]+/)
57
+ unless ENV['ADAPTER'] == 'in_memory'
58
+ plugins.push('dm-migrations')
59
+ end
60
+ plugins.uniq.each { |plugin| require plugin }
61
+ end
62
+
63
+ def spec_adapters
64
+ @spec_adapters ||= {}
65
+ end
66
+
67
+ private
68
+
69
+ def perform_action(kind, action)
70
+ configure unless configured?
71
+ spec_adapters[kind].send(action)
72
+ end
73
+
74
+ def default_root
75
+ Pathname(Dir.pwd).join('spec')
76
+ end
77
+
78
+ def log_stream(log)
79
+ log == 'file' ? root.join('log/dm.log') : $stdout
80
+ end
81
+
82
+ end
83
+
84
+ module Adapters
85
+
86
+ def self.use(adapter_class)
87
+ Spec.spec_adapters[:default] = adapter_class.new(:default)
88
+ Spec.spec_adapters[:alternate] = adapter_class.new(:alternate)
89
+ end
90
+
91
+ class Adapter
92
+
93
+ attr_reader :name
94
+
95
+ def initialize(name)
96
+ @name = name.to_sym
97
+ end
98
+
99
+ def adapter
100
+ @adapter ||= setup!
101
+ end
102
+
103
+ alias_method :setup, :adapter
104
+
105
+ def setup!
106
+ adapter = DataMapper.setup(name, connection_uri)
107
+ test_connection(adapter)
108
+ adapter
109
+ rescue Exception => e
110
+ puts "Could not connect to the database using '#{connection_uri}' because of: #{e.inspect}"
111
+ end
112
+
113
+ def adapter_name
114
+ @adapter_name ||= infer_adapter_name
115
+ end
116
+
117
+ def connection_uri
118
+ "#{adapter_name}://#{username}:#{password}@#{host}/#{storage_name}"
119
+ end
120
+
121
+ def storage_name
122
+ send("#{name}_storage_name")
123
+ end
124
+
125
+ def default_storage_name
126
+ "datamapper_default_tests"
127
+ end
128
+
129
+ def alternate_storage_name
130
+ "datamapper_alternate_tests"
131
+ end
132
+
133
+ def username
134
+ ENV.fetch('DM_DB_USER', 'datamapper')
135
+ end
136
+
137
+ def password
138
+ ENV.fetch('DM_DB_PASSWORD', 'datamapper')
139
+ end
140
+
141
+ def host
142
+ ENV.fetch('DM_DB_HOST', 'localhost')
143
+ end
144
+
145
+ # Test the connection
146
+ #
147
+ # Overwrite this method if you need to perform custom connection testing
148
+ #
149
+ # @raise [Exception]
150
+ def test_connection(adapter)
151
+ if adapter.respond_to?(:select)
152
+ adapter.select('SELECT 1')
153
+ end
154
+ end
155
+
156
+ private
157
+
158
+ def infer_adapter_name
159
+ demodulized = DataMapper::Inflector.demodulize(self.class.name.chomp('Adapter'))
160
+ DataMapper::Inflector.underscore(demodulized).freeze
161
+ end
162
+
163
+ end
164
+
165
+ class InMemoryAdapter < Adapter
166
+ def connection_uri
167
+ { :adapter => :in_memory }
168
+ end
169
+ end
170
+
171
+ end
172
+ end
173
+ end
@@ -0,0 +1,326 @@
1
+ share_examples_for 'An Adapter' do
2
+
3
+ def self.adapter_supports?(*methods)
4
+
5
+ # FIXME obviously this needs a real fix!
6
+ # --------------------------------------
7
+ # Probably, delaying adapter_supports?
8
+ # to be executed after DataMapper.setup
9
+ # has been called will solve our current
10
+ # problem with described_type() being nil
11
+ # for as long as DataMapper.setup wasn't
12
+ # called
13
+ return true if ENV['ADAPTER_SUPPORTS'] == 'all'
14
+
15
+ methods.all? do |method|
16
+ # TODO: figure out a way to see if the instance method is only inherited
17
+ # from the Abstract Adapter, and not defined in it's class. If that is
18
+ # the case return false
19
+
20
+ # CRUD methods can be inherited from parent class
21
+ described_type.instance_methods.any? { |instance_method| method.to_s == instance_method.to_s }
22
+ end
23
+ end
24
+
25
+ before :all do
26
+ raise '+@adapter+ should be defined in before block' unless instance_variable_get('@adapter')
27
+
28
+ class ::Heffalump
29
+ include DataMapper::Resource
30
+
31
+ property :id, Serial
32
+ property :color, String
33
+ property :num_spots, Integer
34
+ property :striped, Boolean
35
+ end
36
+
37
+ DataMapper.finalize
38
+
39
+ # create all tables and constraints before each spec
40
+ if @repository.respond_to?(:auto_migrate!)
41
+ Heffalump.auto_migrate!
42
+ end
43
+ end
44
+
45
+ if adapter_supports?(:create)
46
+ describe '#create' do
47
+ it 'should not raise any errors' do
48
+ lambda {
49
+ Heffalump.create(:color => 'peach')
50
+ }.should_not raise_error
51
+ end
52
+
53
+ it 'should set the identity field for the resource' do
54
+ heffalump = Heffalump.new(:color => 'peach')
55
+ heffalump.id.should be_nil
56
+ heffalump.save
57
+ heffalump.id.should_not be_nil
58
+ end
59
+ end
60
+ else
61
+ it 'needs to support #create'
62
+ end
63
+
64
+ if adapter_supports?(:read)
65
+ describe '#read' do
66
+ before :all do
67
+ @heffalump = Heffalump.create(:color => 'brownish hue')
68
+ #just going to borrow this, so I can check the return values
69
+ @query = Heffalump.all.query
70
+ end
71
+
72
+ it 'should not raise any errors' do
73
+ lambda {
74
+ Heffalump.all()
75
+ }.should_not raise_error
76
+ end
77
+
78
+ it 'should return stuff' do
79
+ Heffalump.all.should be_include(@heffalump)
80
+ end
81
+ end
82
+ else
83
+ it 'needs to support #read'
84
+ end
85
+
86
+ if adapter_supports?(:update)
87
+ describe '#update' do
88
+ before do
89
+ @heffalump = Heffalump.create(:color => 'indigo')
90
+ end
91
+
92
+ it 'should not raise any errors' do
93
+ lambda {
94
+ @heffalump.color = 'violet'
95
+ @heffalump.save
96
+ }.should_not raise_error
97
+ end
98
+
99
+ it 'should not alter the identity field' do
100
+ id = @heffalump.id
101
+ @heffalump.color = 'violet'
102
+ @heffalump.save
103
+ @heffalump.id.should == id
104
+ end
105
+
106
+ it 'should update altered fields' do
107
+ @heffalump.color = 'violet'
108
+ @heffalump.save
109
+ Heffalump.get(*@heffalump.key).color.should == 'violet'
110
+ end
111
+
112
+ it 'should not alter other fields' do
113
+ color = @heffalump.color
114
+ @heffalump.num_spots = 3
115
+ @heffalump.save
116
+ Heffalump.get(*@heffalump.key).color.should == color
117
+ end
118
+ end
119
+ else
120
+ it 'needs to support #update'
121
+ end
122
+
123
+ if adapter_supports?(:delete)
124
+ describe '#delete' do
125
+ before do
126
+ @heffalump = Heffalump.create(:color => 'forest green')
127
+ end
128
+
129
+ it 'should not raise any errors' do
130
+ lambda {
131
+ @heffalump.destroy
132
+ }.should_not raise_error
133
+ end
134
+
135
+ it 'should delete the requested resource' do
136
+ id = @heffalump.id
137
+ @heffalump.destroy
138
+ Heffalump.get(id).should be_nil
139
+ end
140
+ end
141
+ else
142
+ it 'needs to support #delete'
143
+ end
144
+
145
+ if adapter_supports?(:read, :create)
146
+ describe 'query matching' do
147
+ before :all do
148
+ @red = Heffalump.create(:color => 'red')
149
+ @two = Heffalump.create(:num_spots => 2)
150
+ @five = Heffalump.create(:num_spots => 5)
151
+ end
152
+
153
+ describe 'conditions' do
154
+ describe 'eql' do
155
+ it 'should be able to search for objects included in an inclusive range of values' do
156
+ Heffalump.all(:num_spots => 1..5).should be_include(@five)
157
+ end
158
+
159
+ it 'should be able to search for objects included in an exclusive range of values' do
160
+ Heffalump.all(:num_spots => 1...6).should be_include(@five)
161
+ end
162
+
163
+ it 'should not be able to search for values not included in an inclusive range of values' do
164
+ Heffalump.all(:num_spots => 1..4).should_not be_include(@five)
165
+ end
166
+
167
+ it 'should not be able to search for values not included in an exclusive range of values' do
168
+ Heffalump.all(:num_spots => 1...5).should_not be_include(@five)
169
+ end
170
+ end
171
+
172
+ describe 'not' do
173
+ it 'should be able to search for objects with not equal value' do
174
+ Heffalump.all(:color.not => 'red').should_not be_include(@red)
175
+ end
176
+
177
+ it 'should include objects that are not like the value' do
178
+ Heffalump.all(:color.not => 'black').should be_include(@red)
179
+ end
180
+
181
+ it 'should be able to search for objects with not nil value' do
182
+ Heffalump.all(:color.not => nil).should be_include(@red)
183
+ end
184
+
185
+ it 'should not include objects with a nil value' do
186
+ Heffalump.all(:color.not => nil).should_not be_include(@two)
187
+ end
188
+
189
+ it 'should be able to search for object with a nil value using required properties' do
190
+ Heffalump.all(:id.not => nil).should == [ @red, @two, @five ]
191
+ end
192
+
193
+ it 'should be able to search for objects not in an empty list (match all)' do
194
+ Heffalump.all(:color.not => []).should == [ @red, @two, @five ]
195
+ end
196
+
197
+ it 'should be able to search for objects in an empty list and another OR condition (match none on the empty list)' do
198
+ Heffalump.all(
199
+ :conditions => DataMapper::Query::Conditions::Operation.new(
200
+ :or,
201
+ DataMapper::Query::Conditions::Comparison.new(:in, Heffalump.properties[:color], []),
202
+ DataMapper::Query::Conditions::Comparison.new(:in, Heffalump.properties[:num_spots], [5])
203
+ )
204
+ ).should == [ @five ]
205
+ end
206
+
207
+ it 'should be able to search for objects not included in an array of values' do
208
+ Heffalump.all(:num_spots.not => [ 1, 3, 5, 7 ]).should be_include(@two)
209
+ end
210
+
211
+ it 'should be able to search for objects not included in an array of values' do
212
+ Heffalump.all(:num_spots.not => [ 1, 3, 5, 7 ]).should_not be_include(@five)
213
+ end
214
+
215
+ it 'should be able to search for objects not included in an inclusive range of values' do
216
+ Heffalump.all(:num_spots.not => 1..4).should be_include(@five)
217
+ end
218
+
219
+ it 'should be able to search for objects not included in an exclusive range of values' do
220
+ Heffalump.all(:num_spots.not => 1...5).should be_include(@five)
221
+ end
222
+
223
+ it 'should not be able to search for values not included in an inclusive range of values' do
224
+ Heffalump.all(:num_spots.not => 1..5).should_not be_include(@five)
225
+ end
226
+
227
+ it 'should not be able to search for values not included in an exclusive range of values' do
228
+ Heffalump.all(:num_spots.not => 1...6).should_not be_include(@five)
229
+ end
230
+ end
231
+
232
+ describe 'like' do
233
+ it 'should be able to search for objects that match value' do
234
+ Heffalump.all(:color.like => '%ed').should be_include(@red)
235
+ end
236
+
237
+ it 'should not search for objects that do not match the value' do
238
+ Heffalump.all(:color.like => '%blak%').should_not be_include(@red)
239
+ end
240
+ end
241
+
242
+ describe 'regexp' do
243
+ before do
244
+ if (defined?(DataMapper::Adapters::SqliteAdapter) && @adapter.kind_of?(DataMapper::Adapters::SqliteAdapter) ||
245
+ defined?(DataMapper::Adapters::SqlserverAdapter) && @adapter.kind_of?(DataMapper::Adapters::SqlserverAdapter))
246
+ pending 'delegate regexp matches to same system that the InMemory and YAML adapters use'
247
+ end
248
+ end
249
+
250
+ it 'should be able to search for objects that match value' do
251
+ Heffalump.all(:color => /ed/).should be_include(@red)
252
+ end
253
+
254
+ it 'should not be able to search for objects that do not match the value' do
255
+ Heffalump.all(:color => /blak/).should_not be_include(@red)
256
+ end
257
+
258
+ it 'should be able to do a negated search for objects that match value' do
259
+ Heffalump.all(:color.not => /blak/).should be_include(@red)
260
+ end
261
+
262
+ it 'should not be able to do a negated search for objects that do not match value' do
263
+ Heffalump.all(:color.not => /ed/).should_not be_include(@red)
264
+ end
265
+
266
+ end
267
+
268
+ describe 'gt' do
269
+ it 'should be able to search for objects with value greater than' do
270
+ Heffalump.all(:num_spots.gt => 1).should be_include(@two)
271
+ end
272
+
273
+ it 'should not find objects with a value less than' do
274
+ Heffalump.all(:num_spots.gt => 3).should_not be_include(@two)
275
+ end
276
+ end
277
+
278
+ describe 'gte' do
279
+ it 'should be able to search for objects with value greater than' do
280
+ Heffalump.all(:num_spots.gte => 1).should be_include(@two)
281
+ end
282
+
283
+ it 'should be able to search for objects with values equal to' do
284
+ Heffalump.all(:num_spots.gte => 2).should be_include(@two)
285
+ end
286
+
287
+ it 'should not find objects with a value less than' do
288
+ Heffalump.all(:num_spots.gte => 3).should_not be_include(@two)
289
+ end
290
+ end
291
+
292
+ describe 'lt' do
293
+ it 'should be able to search for objects with value less than' do
294
+ Heffalump.all(:num_spots.lt => 3).should be_include(@two)
295
+ end
296
+
297
+ it 'should not find objects with a value less than' do
298
+ Heffalump.all(:num_spots.gt => 2).should_not be_include(@two)
299
+ end
300
+ end
301
+
302
+ describe 'lte' do
303
+ it 'should be able to search for objects with value less than' do
304
+ Heffalump.all(:num_spots.lte => 3).should be_include(@two)
305
+ end
306
+
307
+ it 'should be able to search for objects with values equal to' do
308
+ Heffalump.all(:num_spots.lte => 2).should be_include(@two)
309
+ end
310
+
311
+ it 'should not find objects with a value less than' do
312
+ Heffalump.all(:num_spots.lte => 1).should_not be_include(@two)
313
+ end
314
+ end
315
+ end
316
+
317
+ describe 'limits' do
318
+ it 'should be able to limit the objects' do
319
+ Heffalump.all(:limit => 2).length.should == 2
320
+ end
321
+ end
322
+ end
323
+ else
324
+ it 'needs to support #read and #create to test query matching'
325
+ end
326
+ end