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,21 @@
1
+ module Kernel
2
+ # Returns the object's singleton class.
3
+ #
4
+ # @return [Class]
5
+ #
6
+ # @api private
7
+ unless respond_to?(:singleton_class)
8
+ def singleton_class
9
+ class << self
10
+ self
11
+ end
12
+ end
13
+ end
14
+
15
+ # Delegates to DataMapper.repository()
16
+ #
17
+ # @api public
18
+ private def repository(*args, &block)
19
+ DataMapper.repository(*args, &block)
20
+ end
21
+ end
@@ -0,0 +1,4 @@
1
+ class Pathname
2
+ # alias_method :to_s, :to to_str when to_str not defined
3
+ alias_method :to_str, :to_s unless public_instance_methods(false).any? { |m| m.to_sym == :to_str }
4
+ end
@@ -0,0 +1,10 @@
1
+ class Symbol
2
+ (DataMapper::Query::Conditions::Comparison.slugs | %i(not asc desc)).each do |sym|
3
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
4
+ def #{sym}
5
+ #{"raise \"explicit use of '#{sym}' operator is deprecated (#{caller.first})\"" if %i(eql in).include?(sym)}
6
+ DataMapper::Query::Operator.new(self, #{sym.inspect})
7
+ end
8
+ RUBY
9
+ end
10
+ end
@@ -0,0 +1,6 @@
1
+ module DataMapper
2
+ # Tracks objects to help ensure that each object gets loaded only once.
3
+ # See: http://www.martinfowler.com/eaaCatalog/identityMap.html
4
+ class IdentityMap < Hash
5
+ end
6
+ end
@@ -0,0 +1,99 @@
1
+ module DataMapper
2
+ module Model
3
+ module Hook
4
+ Model.append_inclusions self
5
+
6
+ extend Chainable
7
+
8
+ def self.included(model)
9
+ model.send(:include, DataMapper::Hook)
10
+ model.extend Methods
11
+ super
12
+ end
13
+
14
+ module Methods
15
+ def inherited(model)
16
+ copy_hooks(model)
17
+ super
18
+ end
19
+
20
+ # @api public
21
+ def before(target_method, method_sym = nil, &block)
22
+ setup_hook(:before, target_method, method_sym, block) { super }
23
+ end
24
+
25
+ # @api public
26
+ def after(target_method, method_sym = nil, &block)
27
+ setup_hook(:after, target_method, method_sym, block) { super }
28
+ end
29
+
30
+ # @api private
31
+ def hooks
32
+ @hooks ||= {
33
+ save: {before: [], after: []},
34
+ create: {before: [], after: []},
35
+ update: {before: [], after: []},
36
+ destroy: {before: [], after: []}
37
+ }
38
+ end
39
+
40
+ private def setup_hook(type, name, method, proc)
41
+ types = hooks[name]
42
+ if types && types[type]
43
+ types[type] << if proc
44
+ ProcCommand.new(proc)
45
+ else
46
+ MethodCommand.new(self, method)
47
+ end
48
+ else
49
+ yield
50
+ end
51
+ end
52
+
53
+ # deep copy hooks from the parent model
54
+ private def copy_hooks(model)
55
+ hooks = Hash.new do |hooks_hash, name|
56
+ hooks_hash[name] = Hash.new do |types, type|
57
+ if self.hooks[name]
58
+ types[type] = self.hooks[name][type].map do |command|
59
+ command.copy(model)
60
+ end
61
+ end
62
+ end
63
+ end
64
+
65
+ model.instance_variable_set(:@hooks, hooks)
66
+ end
67
+ end
68
+
69
+ class ProcCommand
70
+ def initialize(proc)
71
+ @proc = proc.to_proc
72
+ end
73
+
74
+ def call(resource)
75
+ resource.instance_eval(&@proc)
76
+ end
77
+
78
+ def copy(_model)
79
+ self
80
+ end
81
+ end
82
+
83
+ class MethodCommand
84
+ def initialize(model, method)
85
+ @model = model
86
+ @method = method.to_sym
87
+ end
88
+
89
+ def call(resource)
90
+ resource.__send__(@method)
91
+ end
92
+
93
+ def copy(model)
94
+ self.class.new(model, @method)
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,30 @@
1
+ module DataMapper
2
+ module Model
3
+ # Module that provides a common way for plugin authors
4
+ # to implement "is ... " traits (object behaviors that can be shared)
5
+ module Is
6
+ # A common interface to activate plugins for a resource. For instance:
7
+ #
8
+ # class Widget
9
+ # include DataMapper::Resource
10
+ #
11
+ # is :list
12
+ # end
13
+ #
14
+ # adds list item behavior to the model. Plugin that wants to conform
15
+ # to "is API" of DataMapper must supply is_+behavior name+ method,
16
+ # for example above it would be is_list.
17
+ #
18
+ # @api public
19
+ def is(plugin, *args, &block)
20
+ generator_method = "is_#{plugin}".to_sym
21
+
22
+ raise PluginNotFoundError, "could not find plugin named #{plugin}" unless respond_to?(generator_method)
23
+
24
+ send(generator_method, *args, &block)
25
+ end
26
+ end
27
+
28
+ include Is
29
+ end
30
+ end
@@ -0,0 +1,244 @@
1
+ # TODO: update Model#respond_to? to return true if method_method missing
2
+ # would handle the message
3
+
4
+ module DataMapper
5
+ module Model
6
+ module Property
7
+ Model.append_extensions self, DataMapper::Property::Lookup
8
+
9
+ def self.extended(model)
10
+ model.instance_variable_set(:@properties, {})
11
+ model.instance_variable_set(:@field_naming_conventions, {})
12
+ super
13
+ end
14
+
15
+ def inherited(model)
16
+ model.instance_variable_set(:@properties, {})
17
+ model.instance_variable_set(:@field_naming_conventions, @field_naming_conventions.dup)
18
+
19
+ @properties.each do |repository_name, properties|
20
+ model_properties = model.properties(repository_name)
21
+ properties.each { |property| model_properties << property }
22
+ end
23
+
24
+ super
25
+ end
26
+
27
+ # Defines a Property on the Resource
28
+ #
29
+ # @param [Symbol] name
30
+ # the name for which to call this property
31
+ # @param [Class] type
32
+ # the ruby type to define this property as
33
+ # @param [Hash(Symbol => String)] options
34
+ # a hash of available options
35
+ #
36
+ # @return [Property]
37
+ # the created Property
38
+ #
39
+ # @see Property
40
+ #
41
+ # @api public
42
+ def property(name, type, options = {})
43
+ # if the type can be found within Property then
44
+ # use that class rather than the primitive
45
+ klass = DataMapper::Property.determine_class(type)
46
+
47
+ raise ArgumentError, "+type+ was #{type.inspect}, which is not a supported type" unless klass
48
+
49
+ property = klass.new(self, name, options)
50
+
51
+ repository_name = self.repository_name
52
+ properties = properties(repository_name)
53
+
54
+ properties << property
55
+
56
+ # Add property to the other mappings as well if this is for the default
57
+ # repository.
58
+
59
+ if repository_name == default_repository_name
60
+ other_repository_properties = DataMapper::Ext::Hash.except(@properties, default_repository_name)
61
+
62
+ other_repository_properties.each do |other_repository_name, properties|
63
+ next if properties.named?(name)
64
+
65
+ # make sure the property is created within the correct repository scope
66
+ DataMapper.repository(other_repository_name) do
67
+ properties << klass.new(self, name, options)
68
+ end
69
+ end
70
+ end
71
+
72
+ # Add the property to the lazy_loads set for this resources repository
73
+ # only.
74
+ # TODO Is this right or should we add the lazy contexts to all
75
+ # repositories?
76
+ if property.lazy?
77
+ context = options.fetch(:lazy, :default)
78
+ context = :default if context == true
79
+
80
+ Array(context).each { |c| properties.lazy_context(c) << property }
81
+ end
82
+
83
+ # add the property to the child classes only if the property was
84
+ # added after the child classes' properties have been copied from
85
+ # the parent
86
+ descendants.each do |descendant|
87
+ descendant.properties(repository_name) << property
88
+ end
89
+
90
+ create_reader_for(property)
91
+ create_writer_for(property)
92
+
93
+ # FIXME: explicit return needed for YARD to parse this properly
94
+ return property
95
+ end
96
+
97
+ # Gets a list of all properties that have been defined on this Model in
98
+ # the requested repository
99
+ #
100
+ # @param [Symbol, String] repository_name
101
+ # The name of the repository to use. Uses the default Repository
102
+ # if none is specified.
103
+ #
104
+ # @return [PropertySet]
105
+ # A list of Properties defined on this Model in the given Repository
106
+ #
107
+ # @api public
108
+ def properties(repository_name = default_repository_name)
109
+ # TODO: create PropertySet#copy that will copy the properties, but assign the
110
+ # new Relationship objects to a supplied repository and model. dup does not really
111
+ # do what is needed
112
+ repository_name = repository_name.to_sym
113
+
114
+ default_repository_name = self.default_repository_name
115
+
116
+ @properties[repository_name] ||= if repository_name == default_repository_name
117
+ PropertySet.new
118
+ else
119
+ properties(default_repository_name).dup
120
+ end
121
+ end
122
+
123
+ # Gets the list of key fields for this Model in +repository_name+
124
+ #
125
+ # @param [String] repository_name
126
+ # The name of the Repository for which the key is to be reported
127
+ #
128
+ # @return [Array]
129
+ # The list of key fields for this Model in +repository_name+
130
+ #
131
+ # @api public
132
+ def key(repository_name = default_repository_name)
133
+ properties(repository_name).key
134
+ end
135
+
136
+ # @api public
137
+ def serial(repository_name = default_repository_name)
138
+ key(repository_name).detect(&:serial?)
139
+ end
140
+
141
+ # Gets the field naming conventions for this resource in the given Repository
142
+ #
143
+ # @param [String, Symbol] repository_name
144
+ # the name of the Repository for which the field naming convention
145
+ # will be retrieved
146
+ #
147
+ # @return [#call]
148
+ # The naming convention for the given Repository
149
+ #
150
+ # @api public
151
+ def field_naming_convention(repository_name = default_storage_name)
152
+ @field_naming_conventions[repository_name] ||= repository(repository_name).adapter.field_naming_convention
153
+ end
154
+
155
+ # @api private
156
+ def properties_with_subclasses(repository_name = default_repository_name)
157
+ properties = properties(repository_name).dup
158
+
159
+ descendants.each do |model|
160
+ model.properties(repository_name).each do |property|
161
+ properties << property
162
+ end
163
+ end
164
+
165
+ properties
166
+ end
167
+
168
+ # @api private
169
+ def key_conditions(repository, key)
170
+ self.key(repository.name).zip(Array(key)).to_h
171
+ end
172
+
173
+ # Defines the anonymous module that is used to add properties.
174
+ # Using a single module here prevents having a very large number
175
+ # of anonymous modules, where each property has their own module.
176
+ # @api private
177
+ private def property_module
178
+ @property_module ||= begin
179
+ mod = Module.new
180
+ class_eval do
181
+ include mod
182
+ end
183
+ mod
184
+ end
185
+ end
186
+
187
+ # defines the reader method for the property
188
+ #
189
+ # @api private
190
+ private def create_reader_for(property)
191
+ name = property.name.to_s
192
+ reader_visibility = property.reader_visibility
193
+ instance_variable_name = property.instance_variable_name
194
+ property_module.module_eval <<-RUBY, __FILE__, __LINE__ + 1
195
+ #{reader_visibility}
196
+ def #{name}
197
+ return #{instance_variable_name} if defined?(#{instance_variable_name})
198
+ property = properties[#{name.inspect}]
199
+ #{instance_variable_name} = property ? persistence_state.get(property) : nil
200
+ end
201
+ RUBY
202
+
203
+ boolean_reader_name = "#{name}?"
204
+
205
+ return unless property.is_a?(DataMapper::Property::Boolean)
206
+
207
+ property_module.module_eval <<-RUBY, __FILE__, __LINE__ + 1
208
+ #{reader_visibility}
209
+ def #{boolean_reader_name}
210
+ #{name}
211
+ end
212
+ RUBY
213
+ end
214
+
215
+ # defines the setter for the property
216
+ #
217
+ # @api private
218
+ private def create_writer_for(property)
219
+ name = property.name
220
+ writer_visibility = property.writer_visibility
221
+
222
+ writer_name = "#{name}="
223
+ property_module.module_eval <<-RUBY, __FILE__, __LINE__ + 1
224
+ #{writer_visibility}
225
+ def #{writer_name}(value)
226
+ property = properties[#{name.inspect}]
227
+ value = property.typecast(value)
228
+ self.persistence_state = persistence_state.set(property, value)
229
+ persistence_state.get(property)
230
+ end
231
+ RUBY
232
+ end
233
+
234
+ # @api public
235
+ private def method_missing(method, *args, &block)
236
+ if (property = properties(repository_name)[method])
237
+ return property
238
+ end
239
+
240
+ super
241
+ end
242
+ end
243
+ end
244
+ end