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,63 @@
1
+ module DataMapper
2
+ module Spec
3
+ module Adapters
4
+ module Helpers
5
+ def supported_by(*adapters, &block)
6
+ adapters = adapters.map(&:to_sym)
7
+ adapter = DataMapper::Spec.adapter_name.to_sym
8
+ if adapters.include?(:all) || adapters.include?(adapter)
9
+ describe_adapter(:default, &block)
10
+ end
11
+ end
12
+
13
+ def with_alternate_adapter(&block)
14
+ describe_adapter(:alternate, &block)
15
+ end
16
+
17
+ def describe_adapter(kind, &block)
18
+ describe("with #{kind} adapter") do
19
+ let(:adapter) { @adapter }
20
+ let(:repository) { @repository }
21
+
22
+ before :all do
23
+ # store these in instance vars for the shared adapter specs
24
+ @adapter = DataMapper::Spec.adapter(kind)
25
+ @repository = DataMapper.repository(@adapter&.name)
26
+
27
+ @repository&.scope { DataMapper.finalize }
28
+
29
+ # create all tables and constraints before each spec
30
+ DataMapper::Model.descendants.each do |model|
31
+ next unless model.respond_to?(:auto_migrate!)
32
+
33
+ begin
34
+ model.auto_migrate!(@repository&.name)
35
+ rescue IncompleteModelError
36
+ # skip incomplete models
37
+ end
38
+ end
39
+ end
40
+
41
+ after :all do
42
+ # remove all tables and constraints after each spec
43
+ DataMapper::Model.descendants.each do |model|
44
+ next unless model.respond_to?(:auto_migrate_down!)
45
+
46
+ begin
47
+ model.auto_migrate_down!(@repository&.name)
48
+ rescue IncompleteModelError
49
+ # skip incomplete models
50
+ end
51
+ end
52
+ # TODO: consider proper automigrate functionality
53
+ if @adapter.respond_to?(:reset)
54
+ @adapter.reset
55
+ end
56
+ end
57
+ instance_eval(&block)
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,21 @@
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
+ super
9
+ end
10
+
11
+ def should_not_be_a_kicker(ivar = :@articles)
12
+ return if loaded
13
+
14
+ it 'is not a kicker' do
15
+ expect(instance_variable_get(ivar)).not_to be_loaded
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ 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.is_a?(DataMapper::Logger) ||
46
+ object.is_a?(DataMapper::DescendantSet) ||
47
+ object.is_a?(DataMapper::Adapters::AbstractAdapter) ||
48
+ object.class.name.to_s[0, 13] == 'DataObjects::'
49
+
50
+ # skip classes and modules in the DataMapper namespace
51
+ next if object.is_a?(Module) &&
52
+ object.name.to_s[0, 12] == 'DataMapper::'
53
+
54
+ # skip when the ivar is no longer defined in the object
55
+ next unless object.instance_variable_defined?(ivar)
56
+
57
+ value = object.instance_variable_get(ivar)
58
+
59
+ # skip descendant sets
60
+ next if value.is_a?(DataMapper::DescendantSet)
61
+
62
+ object.__send__(:remove_instance_variable, ivar) unless object.frozen?
63
+
64
+ # skip when the value was seen
65
+ next if seen.key?(value.object_id)
66
+
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,164 @@
1
+ require 'dm-core'
2
+
3
+ module DataMapper
4
+ module Spec
5
+ class << self
6
+ def root
7
+ @root ||= default_root
8
+ end
9
+
10
+ def root=(path)
11
+ @root = Pathname(path)
12
+ end
13
+
14
+ %w(setup setup! adapter adapter_name).each do |action|
15
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
16
+ def #{action}(kind = :default)
17
+ perform_action(kind, :#{action})
18
+ end
19
+ RUBY
20
+ end
21
+
22
+ def configure
23
+ @configured = begin
24
+ setup_logger
25
+ require_plugins
26
+ require_spec_adapter
27
+ true
28
+ end
29
+ end
30
+
31
+ def configured?
32
+ @configured
33
+ end
34
+
35
+ def setup_logger
36
+ return unless (log = ENV.fetch('LOG', nil))
37
+
38
+ logger = DataMapper::Logger.new(log_stream(log), :debug)
39
+ logger.auto_flush = true
40
+ logger
41
+ end
42
+
43
+ def require_spec_adapter
44
+ desired_adapter = ENV['ADAPTER'] || ENV.fetch('ADAPTERS', nil)
45
+ if desired_adapter.nil? || desired_adapter == 'in_memory'
46
+ ENV['ADAPTER_SUPPORTS'] = 'all'
47
+ Adapters.use(Adapters::InMemoryAdapter)
48
+ else
49
+ require "dm-#{desired_adapter}-adapter/spec/setup"
50
+ end
51
+ end
52
+
53
+ def require_plugins
54
+ adapter = ENV['ADAPTER'] || ENV.fetch('ADAPTERS', nil)
55
+ plugins = ENV['PLUGINS'] || ENV.fetch('PLUGIN', nil)
56
+ plugins = plugins.to_s.split(/[,\s]+/)
57
+ plugins.push('dm-migrations') unless adapter == 'in_memory'
58
+ plugins.uniq.each { |plugin| require plugin }
59
+ end
60
+
61
+ def spec_adapters
62
+ @spec_adapters ||= {}
63
+ end
64
+
65
+ private def perform_action(kind, action)
66
+ configure unless configured?
67
+ spec_adapters[kind].send(action)
68
+ end
69
+
70
+ private def default_root
71
+ Pathname(Dir.pwd).join('spec')
72
+ end
73
+
74
+ private def log_stream(log)
75
+ (log == 'file') ? root.join('log/dm.log') : $stdout
76
+ end
77
+ end
78
+
79
+ module Adapters
80
+ def self.use(adapter_class)
81
+ Spec.spec_adapters[:default] = adapter_class.new(:default)
82
+ Spec.spec_adapters[:alternate] = adapter_class.new(:alternate)
83
+ end
84
+
85
+ class Adapter
86
+ attr_reader :name
87
+
88
+ def initialize(name)
89
+ @name = name.to_sym
90
+ end
91
+
92
+ def adapter
93
+ @adapter ||= setup!
94
+ end
95
+
96
+ alias_method :setup, :adapter
97
+
98
+ def setup!
99
+ adapter = DataMapper.setup(name, connection_uri)
100
+ test_connection(adapter)
101
+ adapter
102
+ rescue Exception => e
103
+ puts "Could not connect to the database using '#{connection_uri}' because of: #{e.inspect}"
104
+ end
105
+
106
+ def adapter_name
107
+ @adapter_name ||= infer_adapter_name
108
+ end
109
+
110
+ def connection_uri
111
+ "#{adapter_name}://#{username}%s@#{host}/#{storage_name}".tap do |s|
112
+ return s % (password.empty? ? '' : ":#{password}")
113
+ end
114
+ end
115
+
116
+ def storage_name
117
+ send("#{name}_storage_name")
118
+ end
119
+
120
+ def default_storage_name
121
+ 'datamapper_default_tests'
122
+ end
123
+
124
+ def alternate_storage_name
125
+ 'datamapper_alternate_tests'
126
+ end
127
+
128
+ def username
129
+ ENV.fetch('DM_DB_USER', 'datamapper')
130
+ end
131
+
132
+ def password
133
+ ENV.fetch('DM_DB_PASSWORD', 'datamapper')
134
+ end
135
+
136
+ def host
137
+ ENV.fetch('DM_DB_HOST', '127.0.0.1')
138
+ end
139
+
140
+ # Test the connection
141
+ #
142
+ # Overwrite this method if you need to perform custom connection testing
143
+ #
144
+ # @raise [Exception]
145
+ def test_connection(adapter)
146
+ return unless adapter.respond_to?(:select)
147
+
148
+ adapter.select('SELECT 1')
149
+ end
150
+
151
+ private def infer_adapter_name
152
+ demodulized = DataMapper::Inflector.demodulize(self.class.name.chomp('Adapter'))
153
+ DataMapper::Inflector.underscore(demodulized).freeze
154
+ end
155
+ end
156
+
157
+ class InMemoryAdapter < Adapter
158
+ def connection_uri
159
+ {adapter: :in_memory}
160
+ end
161
+ end
162
+ end
163
+ end
164
+ end