mongoid 2.0.2 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (240) hide show
  1. data/README.rdoc +3 -1
  2. data/Rakefile +3 -2
  3. data/lib/config/locales/bg.yml +6 -0
  4. data/lib/config/locales/de.yml +6 -0
  5. data/lib/config/locales/en-GB.yml +48 -0
  6. data/lib/config/locales/en.yml +6 -3
  7. data/lib/config/locales/es.yml +6 -0
  8. data/lib/config/locales/fr.yml +6 -0
  9. data/lib/config/locales/hi.yml +39 -0
  10. data/lib/config/locales/hu.yml +13 -7
  11. data/lib/config/locales/id.yml +3 -0
  12. data/lib/config/locales/it.yml +7 -1
  13. data/lib/config/locales/ja.yml +4 -1
  14. data/lib/config/locales/kr.yml +9 -34
  15. data/lib/config/locales/nl.yml +6 -0
  16. data/lib/config/locales/pl.yml +6 -0
  17. data/lib/config/locales/pt-BR.yml +6 -0
  18. data/lib/config/locales/pt.yml +6 -0
  19. data/lib/config/locales/ro.yml +6 -0
  20. data/lib/config/locales/ru.yml +6 -0
  21. data/lib/config/locales/sv.yml +6 -0
  22. data/lib/config/locales/vi.yml +3 -0
  23. data/lib/config/locales/zh-CN.yml +6 -0
  24. data/lib/mongoid.rb +51 -45
  25. data/lib/mongoid/atomic.rb +145 -0
  26. data/lib/mongoid/atomic/modifiers.rb +109 -0
  27. data/lib/mongoid/atomic/paths.rb +3 -0
  28. data/lib/mongoid/atomic/paths/embedded.rb +43 -0
  29. data/lib/mongoid/atomic/paths/embedded/many.rb +44 -0
  30. data/lib/mongoid/atomic/paths/embedded/one.rb +43 -0
  31. data/lib/mongoid/atomic/paths/root.rb +40 -0
  32. data/lib/mongoid/attributes.rb +12 -23
  33. data/lib/mongoid/attributes/processing.rb +5 -5
  34. data/lib/mongoid/callbacks.rb +2 -0
  35. data/lib/mongoid/collection.rb +12 -59
  36. data/lib/mongoid/collections.rb +23 -20
  37. data/lib/mongoid/collections/master.rb +6 -4
  38. data/lib/mongoid/collections/operations.rb +1 -0
  39. data/lib/mongoid/collections/retry.rb +7 -0
  40. data/lib/mongoid/components.rb +2 -2
  41. data/lib/mongoid/config.rb +42 -55
  42. data/lib/mongoid/config/database.rb +6 -2
  43. data/lib/mongoid/config/replset_database.rb +7 -3
  44. data/lib/mongoid/contexts.rb +9 -3
  45. data/lib/mongoid/contexts/enumerable.rb +7 -3
  46. data/lib/mongoid/contexts/mongo.rb +139 -101
  47. data/lib/mongoid/criteria.rb +86 -69
  48. data/lib/mongoid/criterion/complex.rb +32 -5
  49. data/lib/mongoid/criterion/inclusion.rb +4 -2
  50. data/lib/mongoid/criterion/optional.rb +111 -86
  51. data/lib/mongoid/criterion/selector.rb +8 -4
  52. data/lib/mongoid/cursor.rb +27 -27
  53. data/lib/mongoid/dirty.rb +54 -214
  54. data/lib/mongoid/document.rb +37 -39
  55. data/lib/mongoid/errors/document_not_found.rb +3 -4
  56. data/lib/mongoid/errors/invalid_collection.rb +2 -3
  57. data/lib/mongoid/errors/invalid_database.rb +2 -3
  58. data/lib/mongoid/errors/invalid_field.rb +2 -3
  59. data/lib/mongoid/errors/invalid_options.rb +19 -7
  60. data/lib/mongoid/errors/invalid_type.rb +2 -3
  61. data/lib/mongoid/errors/mongoid_error.rb +5 -6
  62. data/lib/mongoid/errors/too_many_nested_attribute_records.rb +2 -3
  63. data/lib/mongoid/errors/unsupported_version.rb +2 -3
  64. data/lib/mongoid/errors/validations.rb +2 -3
  65. data/lib/mongoid/extensions.rb +8 -62
  66. data/lib/mongoid/extensions/array/deletion.rb +29 -0
  67. data/lib/mongoid/extensions/false_class/equality.rb +14 -1
  68. data/lib/mongoid/extensions/hash/criteria_helpers.rb +21 -10
  69. data/lib/mongoid/extensions/hash/scoping.rb +14 -1
  70. data/lib/mongoid/extensions/nil/collectionization.rb +12 -1
  71. data/lib/mongoid/extensions/object/reflections.rb +33 -2
  72. data/lib/mongoid/extensions/object_id/conversions.rb +2 -36
  73. data/lib/mongoid/extensions/proc/scoping.rb +14 -1
  74. data/lib/mongoid/extensions/string/conversions.rb +4 -16
  75. data/lib/mongoid/extensions/string/inflections.rb +35 -14
  76. data/lib/mongoid/extensions/symbol/inflections.rb +38 -12
  77. data/lib/mongoid/extensions/true_class/equality.rb +14 -1
  78. data/lib/mongoid/extras.rb +11 -30
  79. data/lib/mongoid/factory.rb +1 -1
  80. data/lib/mongoid/fields.rb +121 -29
  81. data/lib/mongoid/fields/mappings.rb +36 -0
  82. data/lib/mongoid/fields/serializable.rb +131 -0
  83. data/lib/mongoid/fields/serializable/array.rb +64 -0
  84. data/lib/mongoid/fields/serializable/big_decimal.rb +42 -0
  85. data/lib/mongoid/fields/serializable/bignum.rb +10 -0
  86. data/lib/mongoid/fields/serializable/binary.rb +11 -0
  87. data/lib/mongoid/fields/serializable/boolean.rb +44 -0
  88. data/lib/mongoid/fields/serializable/date.rb +51 -0
  89. data/lib/mongoid/fields/serializable/date_time.rb +28 -0
  90. data/lib/mongoid/fields/serializable/fixnum.rb +10 -0
  91. data/lib/mongoid/fields/serializable/float.rb +33 -0
  92. data/lib/mongoid/fields/serializable/foreign_keys/array.rb +56 -0
  93. data/lib/mongoid/fields/serializable/foreign_keys/object.rb +43 -0
  94. data/lib/mongoid/fields/serializable/hash.rb +25 -0
  95. data/lib/mongoid/fields/serializable/integer.rb +33 -0
  96. data/lib/mongoid/fields/serializable/object.rb +11 -0
  97. data/lib/mongoid/fields/serializable/object_id.rb +32 -0
  98. data/lib/mongoid/fields/serializable/range.rb +42 -0
  99. data/lib/mongoid/fields/serializable/set.rb +42 -0
  100. data/lib/mongoid/fields/serializable/string.rb +28 -0
  101. data/lib/mongoid/fields/serializable/symbol.rb +28 -0
  102. data/lib/mongoid/fields/serializable/time.rb +12 -0
  103. data/lib/mongoid/fields/serializable/time_with_zone.rb +12 -0
  104. data/lib/mongoid/fields/serializable/timekeeping.rb +102 -0
  105. data/lib/mongoid/finders.rb +61 -37
  106. data/lib/mongoid/hierarchy.rb +43 -8
  107. data/lib/mongoid/identity_map.rb +106 -0
  108. data/lib/mongoid/indexes.rb +17 -1
  109. data/lib/mongoid/javascript.rb +2 -3
  110. data/lib/mongoid/keys.rb +10 -21
  111. data/lib/mongoid/logger.rb +22 -1
  112. data/lib/mongoid/matchers/all.rb +10 -0
  113. data/lib/mongoid/matchers/default.rb +1 -1
  114. data/lib/mongoid/matchers/exists.rb +10 -0
  115. data/lib/mongoid/matchers/gt.rb +10 -0
  116. data/lib/mongoid/matchers/gte.rb +10 -0
  117. data/lib/mongoid/matchers/in.rb +10 -0
  118. data/lib/mongoid/matchers/lt.rb +10 -0
  119. data/lib/mongoid/matchers/lte.rb +10 -0
  120. data/lib/mongoid/matchers/ne.rb +10 -0
  121. data/lib/mongoid/matchers/nin.rb +10 -0
  122. data/lib/mongoid/matchers/or.rb +7 -4
  123. data/lib/mongoid/matchers/size.rb +10 -0
  124. data/lib/mongoid/multi_database.rb +26 -6
  125. data/lib/mongoid/multi_parameter_attributes.rb +40 -17
  126. data/lib/mongoid/named_scope.rb +1 -2
  127. data/lib/mongoid/nested_attributes.rb +4 -1
  128. data/lib/mongoid/observer.rb +108 -5
  129. data/lib/mongoid/paranoia.rb +26 -26
  130. data/lib/mongoid/persistence.rb +15 -21
  131. data/lib/mongoid/persistence/atomic.rb +135 -0
  132. data/lib/mongoid/persistence/atomic/add_to_set.rb +11 -8
  133. data/lib/mongoid/persistence/atomic/bit.rb +37 -0
  134. data/lib/mongoid/persistence/atomic/inc.rb +9 -6
  135. data/lib/mongoid/persistence/atomic/operation.rb +48 -7
  136. data/lib/mongoid/persistence/atomic/pop.rb +34 -0
  137. data/lib/mongoid/persistence/atomic/pull.rb +34 -0
  138. data/lib/mongoid/persistence/atomic/pull_all.rb +10 -9
  139. data/lib/mongoid/persistence/atomic/push.rb +8 -5
  140. data/lib/mongoid/persistence/atomic/push_all.rb +31 -0
  141. data/lib/mongoid/persistence/atomic/rename.rb +31 -0
  142. data/lib/mongoid/persistence/atomic/set.rb +30 -0
  143. data/lib/mongoid/persistence/atomic/unset.rb +28 -0
  144. data/lib/mongoid/persistence/deletion.rb +32 -0
  145. data/lib/mongoid/persistence/insertion.rb +41 -0
  146. data/lib/mongoid/persistence/modification.rb +37 -0
  147. data/lib/mongoid/persistence/operations.rb +214 -0
  148. data/lib/mongoid/persistence/operations/embedded/insert.rb +42 -0
  149. data/lib/mongoid/persistence/operations/embedded/remove.rb +40 -0
  150. data/lib/mongoid/persistence/operations/insert.rb +34 -0
  151. data/lib/mongoid/persistence/operations/remove.rb +33 -0
  152. data/lib/mongoid/persistence/operations/update.rb +53 -0
  153. data/lib/mongoid/railtie.rb +21 -33
  154. data/lib/mongoid/railties/database.rake +12 -12
  155. data/lib/mongoid/relations.rb +9 -5
  156. data/lib/mongoid/relations/accessors.rb +15 -36
  157. data/lib/mongoid/relations/auto_save.rb +2 -2
  158. data/lib/mongoid/relations/binding.rb +28 -1
  159. data/lib/mongoid/relations/bindings/embedded/in.rb +17 -30
  160. data/lib/mongoid/relations/bindings/embedded/many.rb +16 -21
  161. data/lib/mongoid/relations/bindings/embedded/one.rb +11 -16
  162. data/lib/mongoid/relations/bindings/referenced/in.rb +31 -32
  163. data/lib/mongoid/relations/bindings/referenced/many.rb +19 -61
  164. data/lib/mongoid/relations/bindings/referenced/many_to_many.rb +15 -63
  165. data/lib/mongoid/relations/bindings/referenced/one.rb +18 -26
  166. data/lib/mongoid/relations/builder.rb +4 -2
  167. data/lib/mongoid/relations/builders.rb +21 -2
  168. data/lib/mongoid/relations/builders/embedded/in.rb +5 -1
  169. data/lib/mongoid/relations/builders/embedded/many.rb +12 -4
  170. data/lib/mongoid/relations/builders/embedded/one.rb +5 -1
  171. data/lib/mongoid/relations/builders/nested_attributes/many.rb +2 -2
  172. data/lib/mongoid/relations/builders/nested_attributes/one.rb +1 -1
  173. data/lib/mongoid/relations/builders/referenced/in.rb +2 -5
  174. data/lib/mongoid/relations/builders/referenced/many.rb +2 -3
  175. data/lib/mongoid/relations/builders/referenced/many_to_many.rb +14 -5
  176. data/lib/mongoid/relations/builders/referenced/one.rb +2 -3
  177. data/lib/mongoid/relations/embedded/atomic.rb +2 -2
  178. data/lib/mongoid/relations/embedded/in.rb +72 -41
  179. data/lib/mongoid/relations/embedded/many.rb +116 -120
  180. data/lib/mongoid/relations/embedded/one.rb +59 -41
  181. data/lib/mongoid/relations/embedded/sort.rb +31 -0
  182. data/lib/mongoid/relations/macros.rb +28 -24
  183. data/lib/mongoid/relations/many.rb +10 -103
  184. data/lib/mongoid/relations/metadata.rb +335 -38
  185. data/lib/mongoid/relations/one.rb +7 -32
  186. data/lib/mongoid/relations/options.rb +47 -0
  187. data/lib/mongoid/relations/proxy.rb +29 -28
  188. data/lib/mongoid/relations/referenced/batch.rb +2 -3
  189. data/lib/mongoid/relations/referenced/in.rb +66 -53
  190. data/lib/mongoid/relations/referenced/many.rb +216 -143
  191. data/lib/mongoid/relations/referenced/many_to_many.rb +132 -163
  192. data/lib/mongoid/relations/referenced/one.rb +76 -58
  193. data/lib/mongoid/relations/synchronization.rb +113 -0
  194. data/lib/mongoid/relations/targets.rb +2 -0
  195. data/lib/mongoid/relations/targets/enumerable.rb +329 -0
  196. data/lib/mongoid/safety.rb +24 -156
  197. data/lib/mongoid/serialization.rb +21 -0
  198. data/lib/mongoid/state.rb +34 -0
  199. data/lib/mongoid/threaded.rb +175 -0
  200. data/lib/mongoid/timestamps/updated.rb +1 -1
  201. data/lib/mongoid/validations.rb +3 -7
  202. data/lib/mongoid/version.rb +1 -1
  203. data/lib/mongoid/versioning.rb +61 -7
  204. data/lib/rack/mongoid.rb +2 -0
  205. data/lib/rack/mongoid/middleware/identity_map.rb +38 -0
  206. data/lib/rails/generators/mongoid/model/model_generator.rb +1 -1
  207. data/lib/rails/generators/mongoid/model/templates/{model.rb → model.rb.tt} +0 -0
  208. data/lib/rails/generators/mongoid/observer/observer_generator.rb +1 -1
  209. data/lib/rails/generators/mongoid/observer/templates/{observer.rb → observer.rb.tt} +0 -0
  210. data/lib/rails/mongoid.rb +17 -17
  211. metadata +136 -102
  212. data/lib/mongoid/atomicity.rb +0 -111
  213. data/lib/mongoid/collections/cyclic_iterator.rb +0 -34
  214. data/lib/mongoid/collections/slaves.rb +0 -61
  215. data/lib/mongoid/extensions/array/conversions.rb +0 -23
  216. data/lib/mongoid/extensions/array/parentization.rb +0 -13
  217. data/lib/mongoid/extensions/big_decimal/conversions.rb +0 -19
  218. data/lib/mongoid/extensions/binary/conversions.rb +0 -17
  219. data/lib/mongoid/extensions/boolean/conversions.rb +0 -27
  220. data/lib/mongoid/extensions/date/conversions.rb +0 -25
  221. data/lib/mongoid/extensions/datetime/conversions.rb +0 -12
  222. data/lib/mongoid/extensions/float/conversions.rb +0 -20
  223. data/lib/mongoid/extensions/hash/conversions.rb +0 -19
  224. data/lib/mongoid/extensions/integer/conversions.rb +0 -20
  225. data/lib/mongoid/extensions/object/conversions.rb +0 -25
  226. data/lib/mongoid/extensions/range/conversions.rb +0 -25
  227. data/lib/mongoid/extensions/set/conversions.rb +0 -20
  228. data/lib/mongoid/extensions/symbol/conversions.rb +0 -21
  229. data/lib/mongoid/extensions/time_conversions.rb +0 -38
  230. data/lib/mongoid/field.rb +0 -162
  231. data/lib/mongoid/paths.rb +0 -61
  232. data/lib/mongoid/persistence/command.rb +0 -71
  233. data/lib/mongoid/persistence/insert.rb +0 -53
  234. data/lib/mongoid/persistence/insert_embedded.rb +0 -43
  235. data/lib/mongoid/persistence/remove.rb +0 -44
  236. data/lib/mongoid/persistence/remove_all.rb +0 -40
  237. data/lib/mongoid/persistence/remove_embedded.rb +0 -48
  238. data/lib/mongoid/persistence/update.rb +0 -77
  239. data/lib/mongoid/safe.rb +0 -23
  240. data/lib/mongoid/validations/referenced.rb +0 -58
@@ -7,28 +7,6 @@ module Mongoid # :nodoc:
7
7
  # relations.
8
8
  class One < Relations::One
9
9
 
10
- # Binds the base object to the inverse of the relation. This is so we
11
- # are referenced to the actual objects themselves and dont hit the
12
- # database twice when setting the relations up.
13
- #
14
- # This is called after first creating the relation, or if a new object
15
- # is set on the relation.
16
- #
17
- # @example Bind the relation.
18
- # person.name.bind(:continue => false)
19
- #
20
- # @param [ Hash ] options The options to bind with.
21
- #
22
- # @option options [ true, false ] :binding Are we in build mode?
23
- # @option options [ true, false ] :continue Continue binding the
24
- # inverse?
25
- #
26
- # @since 2.0.0.rc.1
27
- def bind(options = {})
28
- binding.bind(options)
29
- target.save if base.persisted? && !options[:binding]
30
- end
31
-
32
10
  # Instantiate a new embeds_one relation.
33
11
  #
34
12
  # @example Create the new proxy.
@@ -40,29 +18,30 @@ module Mongoid # :nodoc:
40
18
  def initialize(base, target, metadata)
41
19
  init(base, target, metadata) do
42
20
  characterize_one(target)
43
- target.parentize(base)
21
+ bind_one
22
+ target.save if persistable?
44
23
  end
45
24
  end
46
25
 
47
- # Unbinds the base object to the inverse of the relation. This occurs
48
- # when setting a side of the relation to nil.
49
- #
50
- # Will delete the object if necessary.
26
+ # Substitutes the supplied target documents for the existing document
27
+ # in the relation.
51
28
  #
52
- # @example Unbind the relation.
53
- # person.name.unbind(name, :continue => true)
29
+ # @example Substitute the new document.
30
+ # person.name.substitute(new_name)
54
31
  #
55
- # @param [ Document ] old_target The previous target of the relation.
56
- # @param [ Hash ] options The options to bind with.
32
+ # @param [ Document ] other A document to replace the target.
57
33
  #
58
- # @option options [ true, false ] :binding Are we in build mode?
59
- # @option options [ true, false ] :continue Continue binding the
60
- # inverse?
34
+ # @return [ Document, nil ] The relation or nil.
61
35
  #
62
36
  # @since 2.0.0.rc.1
63
- def unbind(old_target, options = {})
64
- binding(old_target).unbind(options)
65
- old_target.delete if base.persisted? && !old_target.destroyed?
37
+ def substitute(replacement)
38
+ tap do |proxy|
39
+ proxy.delete
40
+ proxy.unbind_one
41
+ return nil unless replacement
42
+ proxy.target = replacement
43
+ proxy.bind_one
44
+ end
66
45
  end
67
46
 
68
47
  private
@@ -77,8 +56,20 @@ module Mongoid # :nodoc:
77
56
  # @return [ Binding ] The relation's binding.
78
57
  #
79
58
  # @since 2.0.0.rc.1
80
- def binding(new_target = nil)
81
- Bindings::Embedded::One.new(base, new_target || target, metadata)
59
+ def binding
60
+ Bindings::Embedded::One.new(base, target, metadata)
61
+ end
62
+
63
+ # Are we able to persist this relation?
64
+ #
65
+ # @example Can we persist the relation?
66
+ # relation.persistable?
67
+ #
68
+ # @return [ true, false ] If the relation is persistable.
69
+ #
70
+ # @since 2.1.0
71
+ def persistable?
72
+ base.persisted? && !binding? && !building?
82
73
  end
83
74
 
84
75
  class << self
@@ -95,8 +86,8 @@ module Mongoid # :nodoc:
95
86
  # @return [ Builder ] A newly instantiated builder object.
96
87
  #
97
88
  # @since 2.0.0.rc.1
98
- def builder(meta, object)
99
- Builders::Embedded::One.new(meta, object)
89
+ def builder(meta, object, loading = false)
90
+ Builders::Embedded::One.new(meta, object, loading)
100
91
  end
101
92
 
102
93
  # Returns true if the relation is an embedded one. In this case
@@ -151,6 +142,21 @@ module Mongoid # :nodoc:
151
142
  Builders::NestedAttributes::One.new(metadata, attributes, options)
152
143
  end
153
144
 
145
+ # Get the path calculator for the supplied document.
146
+ #
147
+ # @example Get the path calculator.
148
+ # Proxy.path(document)
149
+ #
150
+ # @param [ Document ] document The document to calculate on.
151
+ #
152
+ # @return [ Mongoid::Atomic::Paths::Embedded::One ]
153
+ # The embedded one atomic path calculator.
154
+ #
155
+ # @since 2.1.0
156
+ def path(document)
157
+ Mongoid::Atomic::Paths::Embedded::One.new(document)
158
+ end
159
+
154
160
  # Tells the caller if this relation is one that stores the foreign
155
161
  # key on its own objects.
156
162
  #
@@ -163,6 +169,18 @@ module Mongoid # :nodoc:
163
169
  def stores_foreign_key?
164
170
  false
165
171
  end
172
+
173
+ # Get the valid options allowed with this relation.
174
+ #
175
+ # @example Get the valid options.
176
+ # Relation.valid_options
177
+ #
178
+ # @return [ Array<Symbol> ] The valid options.
179
+ #
180
+ # @since 2.1.0
181
+ def valid_options
182
+ [ :as, :cyclic ]
183
+ end
166
184
  end
167
185
  end
168
186
  end
@@ -0,0 +1,31 @@
1
+ # encoding: utf-8
2
+ module Mongoid # :nodoc:
3
+ module Relations #:nodoc:
4
+ module Embedded #:nodoc:
5
+
6
+ # This module handles embedded associations sorting
7
+ # Since mongodb doesn't have virtual collection for embedded docs yet
8
+ # (see https://jira.mongodb.org/browse/SERVER-142 for details)
9
+ # Sorting implemented in ruby
10
+ # This can be a performance killer on collections with many embedded documents
11
+ module Sort
12
+
13
+ # Sorts documents
14
+ #
15
+ # @param [ Array<Documents> ] documents array of documents
16
+ # @param [ Mongoid::Relations::Metadata ] metadata association metadata
17
+ def sort_documents!(documents, metadata)
18
+ sort_options = Criteria.new(metadata.klass).order_by(metadata.order).options[:sort]
19
+
20
+ docs = documents.sort_by do |document|
21
+ sort_options.map do |key, direction|
22
+ Contexts::Enumerable::Sort.new(document.read_attribute(key), direction)
23
+ end
24
+ end
25
+ documents.replace(docs)
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+
@@ -157,7 +157,6 @@ module Mongoid # :nodoc:
157
157
  # @param [ Hash ] options The relation options.
158
158
  # @param [ Proc ] block Optional block for defining extensions.
159
159
  def references_many(name, options = {}, &block)
160
- check_options(options)
161
160
  characterize(name, Referenced::Many, options, &block).tap do |meta|
162
161
  relate(name, meta)
163
162
  reference(meta)
@@ -191,8 +190,10 @@ module Mongoid # :nodoc:
191
190
  def references_and_referenced_in_many(name, options = {}, &block)
192
191
  characterize(name, Referenced::ManyToMany, options, &block).tap do |meta|
193
192
  relate(name, meta)
194
- reference(meta)
193
+ reference(meta, Array)
194
+ autosave(meta)
195
195
  validates_relation(meta)
196
+ synced(meta)
196
197
  end
197
198
  end
198
199
  alias :has_and_belongs_to_many :references_and_referenced_in_many
@@ -228,26 +229,6 @@ module Mongoid # :nodoc:
228
229
 
229
230
  private
230
231
 
231
- # Temporary check while people switch over to the new macro. Will be
232
- # deleted in 2.0.0.
233
- #
234
- # @example Check the options.
235
- # Person.check_options({})
236
- #
237
- # @param [ Hash ] options The options given to the relational many.
238
- #
239
- # @raise [ RuntimeError ] If :stored_as => :array is found.
240
- #
241
- # @since 2.0.0.rc.1
242
- def check_options(options = {})
243
- if options[:stored_as] == :array
244
- raise RuntimeError.new(
245
- "Macro: references_many :name, :stored_as => :array " <<
246
- "Is no longer valid. Please use: references_and_referenced_in_many :name"
247
- )
248
- end
249
- end
250
-
251
232
  # Create the metadata for the relation.
252
233
  #
253
234
  # @example Create the metadata.
@@ -263,13 +244,35 @@ module Mongoid # :nodoc:
263
244
  Metadata.new(
264
245
  options.merge(
265
246
  :relation => relation,
266
- :extend => block,
247
+ :extend => create_extension_module(name, &block),
267
248
  :inverse_class_name => self.name,
268
249
  :name => name
269
250
  )
270
251
  )
271
252
  end
272
253
 
254
+ # Generate a named extension module suitable for marshaling
255
+ #
256
+ # @example Get the module.
257
+ # Person.create_extension_module(:posts, &block)
258
+ #
259
+ # @param [ Symbol ] name The name of the relation.
260
+ # @param [ Proc ] block Optional block for defining extensions.
261
+ #
262
+ # @return [ Module, nil ] The extension or nil.
263
+ #
264
+ # @since 2.1.0
265
+ def create_extension_module(name, &block)
266
+ if block
267
+ extension_module_name =
268
+ "#{self.to_s.demodulize}#{name.to_s.camelize}RelationExtension"
269
+ silence_warnings do
270
+ self.const_set(extension_module_name, Module.new(&block))
271
+ end
272
+ "#{self}::#{extension_module_name}".constantize
273
+ end
274
+ end
275
+
273
276
  # Defines a field to be used as a foreign key in the relation and
274
277
  # indexes it if defined.
275
278
  #
@@ -277,12 +280,13 @@ module Mongoid # :nodoc:
277
280
  # Person.reference(metadata)
278
281
  #
279
282
  # @param [ Metadata ] metadata The metadata for the relation.
280
- def reference(metadata)
283
+ def reference(metadata, type = Object)
281
284
  polymorph(metadata).cascade(metadata)
282
285
  if metadata.relation.stores_foreign_key?
283
286
  key = metadata.foreign_key
284
287
  field(
285
288
  key,
289
+ :type => type,
286
290
  :identity => true,
287
291
  :metadata => metadata,
288
292
  :default => metadata.foreign_key_default
@@ -7,85 +7,18 @@ module Mongoid #:nodoc:
7
7
  class Many < Proxy
8
8
 
9
9
  delegate :avg, :max, :min, :sum, :to => :criteria
10
+ delegate :length, :size, :to => :target
10
11
 
11
- # Appends a document or array of documents to the relation. Will set
12
- # the parent and update the index in the process.
13
- #
14
- # @example Append a document.
15
- # person.addresses << address
16
- #
17
- # @example Push a document.
18
- # person.addresses.push(address)
19
- #
20
- # @example Concat with other documents.
21
- # person.addresses.concat([ address_one, address_two ])
22
- #
23
- # @param [ Document, Array<Document> ] *args Any number of documents.
24
- def <<(*args)
25
- options = default_options(args)
26
- args.flatten.each do |doc|
27
- return doc unless doc
28
- append(doc, options)
29
- doc.save if base.persisted? && !options[:binding]
30
- end
31
- end
32
- alias :concat :<<
33
- alias :push :<<
34
-
35
- # Builds a new document in the relation and appends it to the target.
36
- # Takes an optional type if you want to specify a subclass.
37
- #
38
- # @example Build a new document on the relation.
39
- # person.people.build(:name => "Bozo")
40
- #
41
- # @param [ Hash ] attributes The attributes to build the document with.
42
- # @param [ Class ] type Optional class to build the document with.
43
- #
44
- # @return [ Document ] The new document.
45
- def build(attributes = {}, type = nil, &block)
46
- instantiated(type).tap do |doc|
47
- doc.write_attributes(attributes)
48
- doc.identify
49
- append(doc, default_options(:binding => true))
50
- block.call(doc) if block
51
- end
52
- end
53
- alias :new :build
54
-
55
- # Creates a new document on the references many relation. This will
56
- # save the document if the parent has been persisted.
12
+ # Is the relation empty?
57
13
  #
58
- # @example Create and save the new document.
59
- # person.posts.create(:text => "Testing")
14
+ # @example Is the relation empty??
15
+ # person.addresses.blank?
60
16
  #
61
- # @param [ Hash ] attributes The attributes to create with.
62
- # @param [ Class ] type The optional type of document to create.
17
+ # @return [ true, false ] If the relation is empty or not.
63
18
  #
64
- # @return [ Document ] The newly created document.
65
- def create(attributes = nil, type = nil, &block)
66
- build(attributes, type).tap do |doc|
67
- block.call(doc) if block
68
- doc.save if base.persisted?
69
- end
70
- end
71
-
72
- # Creates a new document on the references many relation. This will
73
- # save the document if the parent has been persisted and will raise an
74
- # error if validation fails.
75
- #
76
- # @example Create and save the new document.
77
- # person.posts.create!(:text => "Testing")
78
- #
79
- # @param [ Hash ] attributes The attributes to create with.
80
- # @param [ Class ] type The optional type of document to create.
81
- #
82
- # @raise [ Errors::Validations ] If validation failed.
83
- #
84
- # @return [ Document ] The newly created document.
85
- def create!(attributes = nil, type = nil)
86
- build(attributes, type).tap do |doc|
87
- doc.save! if base.persisted?
88
- end
19
+ # @since 2.1.0
20
+ def blank?
21
+ size == 0
89
22
  end
90
23
 
91
24
  # Determine if any documents in this relation exist in the database.
@@ -146,8 +79,8 @@ module Mongoid #:nodoc:
146
79
  # @return [ true, false ] If the proxy responds to the method.
147
80
  #
148
81
  # @since 2.0.0
149
- def respond_to?(name)
150
- [].respond_to?(name) || methods.include?(name)
82
+ def respond_to?(name, include_private = false)
83
+ [].respond_to?(name, include_private) || super
151
84
  end
152
85
 
153
86
  # Gets the document as a serializable hash, used by ActiveModel's JSON and
@@ -170,34 +103,8 @@ module Mongoid #:nodoc:
170
103
  target.map { |document| document.serializable_hash(options) }
171
104
  end
172
105
 
173
- # Always returns the number of documents that are in memory.
174
- #
175
- # @example Get the number of loaded documents.
176
- # relation.size
177
- #
178
- # @return [ Integer ] The number of documents in memory.
179
- #
180
- # @since 2.0.0
181
- def size
182
- target.size
183
- end
184
- alias :length :size
185
-
186
106
  private
187
107
 
188
- # Get the default options used in binding functions.
189
- #
190
- # @example Get the default options.
191
- # relation.default_options(:continue => true)
192
- #
193
- # @param [ Hash, Array ] args The arguments to parse from.
194
- #
195
- # @return [ Hash ] The options merged with the actuals.
196
- def default_options(args = {})
197
- options = args.is_a?(Hash) ? args : args.extract_options!
198
- Mongoid.binding_defaults.merge(options)
199
- end
200
-
201
108
  # Find the first object given the supplied attributes or create/initialize it.
202
109
  #
203
110
  # @example Find or create|initialize.
@@ -8,6 +8,54 @@ module Mongoid # :nodoc:
8
8
 
9
9
  delegate :foreign_key_default, :stores_foreign_key?, :to => :relation
10
10
 
11
+ # Returns the as option of the relation.
12
+ #
13
+ # @example Get the as option.
14
+ # metadata.as
15
+ #
16
+ # @return [ true, false ] The as option.
17
+ #
18
+ # @since 2.1.0
19
+ def as
20
+ self[:as]
21
+ end
22
+
23
+ # Tells whether an as option exists.
24
+ #
25
+ # @example Is the as option set?
26
+ # metadata.as?
27
+ #
28
+ # @return [ true, false ] True if an as exists, false if not.
29
+ #
30
+ # @since 2.0.0.rc.1
31
+ def as?
32
+ !!as
33
+ end
34
+
35
+ # Returns the autosave option of the relation.
36
+ #
37
+ # @example Get the autosave option.
38
+ # metadata.autosave
39
+ #
40
+ # @return [ true, false ] The autosave option.
41
+ #
42
+ # @since 2.1.0
43
+ def autosave
44
+ self[:autosave]
45
+ end
46
+
47
+ # Does the metadata have a autosave option?
48
+ #
49
+ # @example Is the relation autosaving?
50
+ # metadata.autosave?
51
+ #
52
+ # @return [ true, false ] If the relation autosaves.
53
+ #
54
+ # @since 2.1.0
55
+ def autosave?
56
+ !!autosave
57
+ end
58
+
11
59
  # Gets a relation builder associated with the relation this metadata is
12
60
  # for.
13
61
  #
@@ -19,8 +67,8 @@ module Mongoid # :nodoc:
19
67
  # @return [ Builder ] The builder for the relation.
20
68
  #
21
69
  # @since 2.0.0.rc.1
22
- def builder(object)
23
- relation.builder(self, object)
70
+ def builder(object, loading = false)
71
+ relation.builder(self, object, loading)
24
72
  end
25
73
 
26
74
  # Returns the name of the strategy used for handling dependent relations.
@@ -55,10 +103,81 @@ module Mongoid # :nodoc:
55
103
  @class_name ||= (self[:class_name] || classify)
56
104
  end
57
105
 
106
+ # Get the foreign key contraint for the metadata.
107
+ #
108
+ # @example Get the constaint.
109
+ # metadata.constraint
110
+ #
111
+ # @return [ Constraint ] The constraint.
112
+ #
113
+ # @since 2.0.0.rc.1
58
114
  def constraint
59
115
  @constraint ||= Constraint.new(self)
60
116
  end
61
117
 
118
+ # Get the criteria that is used to query for this metadata's relation.
119
+ #
120
+ # @example Get the criteria.
121
+ # metadata.criteria([ id_one, id_two ])
122
+ #
123
+ # @param [ Object ] object The foreign key used for the query.
124
+ #
125
+ # @return [ Criteria ] The criteria.
126
+ #
127
+ # @since 2.1.0
128
+ def criteria(object, type = nil)
129
+ query = relation.criteria(self, object, type)
130
+ order ? query.order_by(order) : query
131
+ end
132
+
133
+ # Returns the cyclic option of the relation.
134
+ #
135
+ # @example Get the cyclic option.
136
+ # metadata.cyclic
137
+ #
138
+ # @return [ true, false ] The cyclic option.
139
+ #
140
+ # @since 2.1.0
141
+ def cyclic
142
+ self[:cyclic]
143
+ end
144
+
145
+ # Does the metadata have a cyclic option?
146
+ #
147
+ # @example Is the metadata cyclic?
148
+ # metadata.cyclic?
149
+ #
150
+ # @return [ true, false ] If the metadata is cyclic.
151
+ #
152
+ # @since 2.1.0
153
+ def cyclic?
154
+ !!cyclic
155
+ end
156
+
157
+ # Returns the dependent option of the relation.
158
+ #
159
+ # @example Get the dependent option.
160
+ # metadata.dependent
161
+ #
162
+ # @return [ Symbol ] The dependent option.
163
+ #
164
+ # @since 2.1.0
165
+ def dependent
166
+ self[:dependent]
167
+ end
168
+
169
+ # Does the metadata have a dependent option?
170
+ #
171
+ # @example Is the metadata performing cascades?
172
+ # metadata.dependent?
173
+ #
174
+ # @return [ true, false ] If the metadata cascades.
175
+ #
176
+ # @since 2.1.0
177
+ def dependent?
178
+ !!dependent
179
+ end
180
+
62
181
  # Will determine if the relation is an embedded one or not. Currently
63
182
  # only checks against embeds one and many.
64
183
  #
@@ -72,12 +191,12 @@ module Mongoid # :nodoc:
72
191
  @embedded ||= (macro == :embeds_one || macro == :embeds_many)
73
192
  end
74
193
 
75
- # Returns the extension of the relation. This can be a proc or module.
194
+ # Returns the extension of the relation.
76
195
  #
77
196
  # @example Get the relation extension.
78
197
  # metadata.extension
79
198
  #
80
- # @return [ Proc ] The extension or nil.
199
+ # @return [ Module ] The extension or nil.
81
200
  #
82
201
  # @since 2.0.0.rc.1
83
202
  def extension
@@ -115,6 +234,18 @@ module Mongoid # :nodoc:
115
234
  @foreign_key ||= determine_foreign_key
116
235
  end
117
236
 
237
+ # Get the name of the method to check if the foreign key has changed.
238
+ #
239
+ # @example Get the foreign key check method.
240
+ # metadata.foreign_key_check
241
+ #
242
+ # @return [ String ] The foreign key check.
243
+ #
244
+ # @since 2.1.0
245
+ def foreign_key_check
246
+ @foreign_key_check ||= "#{foreign_key}_changed?"
247
+ end
248
+
118
249
  # Returns the name of the method used to set the foreign key on a
119
250
  # document.
120
251
  #
@@ -128,6 +259,18 @@ module Mongoid # :nodoc:
128
259
  @foreign_key_setter ||= "#{foreign_key}="
129
260
  end
130
261
 
262
+ # Returns the index option of the relation.
263
+ #
264
+ # @example Get the index option.
265
+ # metadata.index
266
+ #
267
+ # @return [ true, false ] The index option.
268
+ #
269
+ # @since 2.1.0
270
+ def index
271
+ self[:index]
272
+ end
273
+
131
274
  # Tells whether a foreign key index exists on the relation.
132
275
  #
133
276
  # @example Is the key indexed?
@@ -137,7 +280,7 @@ module Mongoid # :nodoc:
137
280
  #
138
281
  # @since 2.0.0.rc.1
139
282
  def indexed?
140
- !!self[:index]
283
+ !!index
141
284
  end
142
285
 
143
286
  # Instantiate new metadata for a relation.
@@ -149,6 +292,7 @@ module Mongoid # :nodoc:
149
292
  #
150
293
  # @since 2.0.0.rc.1
151
294
  def initialize(properties = {})
295
+ Options.validate!(properties)
152
296
  merge!(properties)
153
297
  end
154
298
 
@@ -168,15 +312,14 @@ module Mongoid # :nodoc:
168
312
  " cyclic: #{cyclic || "No"},\n" <<
169
313
  " dependent: #{dependent || "None"},\n" <<
170
314
  " inverse_of: #{inverse_of || "N/A"},\n" <<
171
- " inverse_setter: #{inverse_setter},\n" <<
172
- " inverse_type: #{inverse_type || "N/A"},\n" <<
173
- " inverse_type_setter: #{inverse_type_setter || "N/A"},\n" <<
174
315
  " key: #{key},\n" <<
175
316
  " macro: #{macro},\n" <<
176
317
  " name: #{name},\n" <<
177
- " polymorphic: #{polymorphic? ? "Yes" : "No"},\n" <<
318
+ " order: #{order.inspect || "No"},\n" <<
319
+ " polymorphic: #{polymorphic? || "No"},\n" <<
178
320
  " relation: #{relation},\n" <<
179
- " setter: #{setter}>\n"
321
+ " setter: #{setter},\n" <<
322
+ " versioned: #{versioned? || "No"}>\n"
180
323
  end
181
324
 
182
325
  # Get the name of the inverse relation if it exists. If this is a
@@ -196,6 +339,30 @@ module Mongoid # :nodoc:
196
339
  @inverse ||= (cyclic? ? cyclic_inverse : inverse_relation)
197
340
  end
198
341
 
342
+ # Returns the inverse_class_name option of the relation.
343
+ #
344
+ # @example Get the inverse_class_name option.
345
+ # metadata.inverse_class_name
346
+ #
347
+ # @return [ true, false ] The inverse_class_name option.
348
+ #
349
+ # @since 2.1.0
350
+ def inverse_class_name
351
+ self[:inverse_class_name]
352
+ end
353
+
354
+ # Returns the if the inverse class name option exists.
355
+ #
356
+ # @example Is an inverse class name defined?
357
+ # metadata.inverse_class_name?
358
+ #
359
+ # @return [ true, false ] If the inverse if defined.
360
+ #
361
+ # @since 2.1.0
362
+ def inverse_class_name?
363
+ !!inverse_class_name
364
+ end
365
+
199
366
  # Used for relational many to many only. This determines the name of the
200
367
  # foreign key field on the inverse side of the relation, since in this
201
368
  # case there are keys on both sides.
@@ -224,6 +391,34 @@ module Mongoid # :nodoc:
224
391
  @inverse_klass ||= inverse_class_name.constantize
225
392
  end
226
393
 
394
+ def inverse_metadata(document)
395
+ document.reflect_on_association(inverse(document))
396
+ end
397
+
398
+ # Returns the inverse_of option of the relation.
399
+ #
400
+ # @example Get the inverse_of option.
401
+ # metadata.inverse_of
402
+ #
403
+ # @return [ true, false ] The inverse_of option.
404
+ #
405
+ # @since 2.1.0
406
+ def inverse_of
407
+ self[:inverse_of]
408
+ end
409
+
410
+ # Does the metadata have a inverse_of option?
411
+ #
412
+ # @example Is an inverse_of defined?
413
+ # metadata.inverse_of?
414
+ #
415
+ # @return [ true, false ] If the relation has an inverse_of defined.
416
+ #
417
+ # @since 2.1.0
418
+ def inverse_of?
419
+ !!inverse_of
420
+ end
421
+
227
422
  # Returns the setter for the inverse side of the relation.
228
423
  #
229
424
  # @example Get the inverse setter.
@@ -235,7 +430,7 @@ module Mongoid # :nodoc:
235
430
  #
236
431
  # @since 2.0.0.rc.1
237
432
  def inverse_setter(other = nil)
238
- inverse(other).to_s << "="
433
+ "#{inverse(other)}="
239
434
  end
240
435
 
241
436
  # Returns the name of the field in which to store the name of the class
@@ -248,11 +443,8 @@ module Mongoid # :nodoc:
248
443
  #
249
444
  # @since 2.0.0.rc.1
250
445
  def inverse_type
251
- if relation.stores_foreign_key? && polymorphic?
252
- (polymorphic? ? name.to_s : class_name.underscore) << "_type"
253
- else
254
- return nil
255
- end
446
+ @inverse_type ||=
447
+ relation.stores_foreign_key? && polymorphic? ? "#{name}_type" : nil
256
448
  end
257
449
 
258
450
  # Gets the setter for the field that sets the type of document on a
@@ -265,7 +457,7 @@ module Mongoid # :nodoc:
265
457
  #
266
458
  # @since 2.0.0.rc.1
267
459
  def inverse_type_setter
268
- inverse_type ? inverse_type << "=" : nil
460
+ @inverse_type_setter ||= inverse_type ? "#{inverse_type}=" : nil
269
461
  end
270
462
 
271
463
  # This returns the key that is to be used to grab the attributes for the
@@ -306,6 +498,43 @@ module Mongoid # :nodoc:
306
498
  relation.macro
307
499
  end
308
500
 
501
+ # Get the name associated with this metadata.
502
+ #
503
+ # @example Get the name.
504
+ # metadata.name
505
+ #
506
+ # @return [ Symbol ] The name.
507
+ #
508
+ # @since 2.1.0
509
+ def name
510
+ self[:name]
511
+ end
512
+
513
+ # Is the name defined?
514
+ #
515
+ # @example Is the name defined?
516
+ # metadata.name?
517
+ #
518
+ # @return [ true, false ] If the name is defined.
519
+ #
520
+ # @since 2.1.0
521
+ def name?
522
+ !!name
523
+ end
524
+
525
+ # Does the relation have a destructive dependent option specified. This
526
+ # is true for :dependent => :delete and :dependent => :destroy.
527
+ #
528
+ # @example Is the relation destructive?
529
+ # metadata.destructive?
530
+ #
531
+ # @return [ true, false ] If the relation is destructive.
532
+ #
533
+ # @since 2.1.0
534
+ def destructive?
535
+ @destructive ||= (dependent == :delete || dependent == :destroy)
536
+ end
537
+
309
538
  # Gets a relation nested builder associated with the relation this metadata
310
539
  # is for. Nested builders are used in conjunction with nested attributes.
311
540
  #
@@ -322,6 +551,20 @@ module Mongoid # :nodoc:
322
551
  relation.nested_builder(self, attributes, options)
323
552
  end
324
553
 
554
+ # Get the path calculator for the supplied document.
555
+ #
556
+ # @example Get the path calculator.
557
+ # metadata.path(document)
558
+ #
559
+ # @param [ Document ] document The document to calculate on.
560
+ #
561
+ # @return [ Object ] The atomic path calculator.
562
+ #
563
+ # @since 2.1.0
564
+ def path(document)
565
+ relation.path(document)
566
+ end
567
+
325
568
  # Returns true if the relation is polymorphic.
326
569
  #
327
570
  # @example Is the relation polymorphic?
@@ -334,6 +577,18 @@ module Mongoid # :nodoc:
334
577
  @polymorphic ||= (!!self[:as] || !!self[:polymorphic])
335
578
  end
336
579
 
580
+ # Get the relation associated with this metadata.
581
+ #
582
+ # @example Get the relation.
583
+ # metadata.relation
584
+ #
585
+ # @return [ Proxy ] The relation proxy class.
586
+ #
587
+ # @since 2.1.0
588
+ def relation
589
+ self[:relation]
590
+ end
591
+
337
592
  # Gets the method name used to set this relation.
338
593
  #
339
594
  # @example Get the setter.
@@ -347,6 +602,32 @@ module Mongoid # :nodoc:
347
602
  @setter ||= "#{name.to_s}="
348
603
  end
349
604
 
605
+ # Returns the name of the field in which to store the name of the class
606
+ # for the polymorphic relation.
607
+ #
608
+ # @example Get the name of the field.
609
+ # metadata.inverse_type
610
+ #
611
+ # @return [ String ] The name of the field for storing the type.
612
+ #
613
+ # @since 2.0.0.rc.1
614
+ def type
615
+ @type ||= polymorphic? ? "#{as.to_s}_type" : nil
616
+ end
617
+
618
+ # Gets the setter for the field that sets the type of document on a
619
+ # polymorphic relation.
620
+ #
621
+ # @example Get the inverse type setter.
622
+ # metadata.inverse_type_setter
623
+ #
624
+ # @return [ String ] The name of the setter.
625
+ #
626
+ # @since 2.0.0.rc.1
627
+ def type_setter
628
+ @type_setter ||= type ? "#{type}=" : nil
629
+ end
630
+
350
631
  # Are we validating this relation automatically?
351
632
  #
352
633
  # @example Is automatic validation on?
@@ -359,6 +640,42 @@ module Mongoid # :nodoc:
359
640
  self[:validate] != false
360
641
  end
361
642
 
643
+ # Is this relation using Mongoid's internal versioning system?
644
+ #
645
+ # @example Is this relation versioned?
646
+ # metadata.versioned?
647
+ #
648
+ # @return [ true, false ] If the relation uses Mongoid versioning.
649
+ #
650
+ # @since 2.1.0
651
+ def versioned?
652
+ !!self[:versioned]
653
+ end
654
+
655
+ # Returns default order for this association.
656
+ #
657
+ # @example Get default order
658
+ # metadata.order
659
+ #
660
+ # @return [ Criterion::Complex, nil] nil if doesn't set
661
+ #
662
+ # @since 2.1.0
663
+ def order
664
+ self[:order]
665
+ end
666
+
667
+ # Is a default order set?
668
+ #
669
+ # @example Is the order set?
670
+ # metadata.order?
671
+ #
672
+ # @return [ true, false ] If the order is set.
673
+ #
674
+ # @since 2.1.0
675
+ def order?
676
+ !!order
677
+ end
678
+
362
679
  private
363
680
 
364
681
  # Returns the class name for the relation.
@@ -510,30 +827,10 @@ module Mongoid # :nodoc:
510
827
  # @since 2.0.0.rc.1
511
828
  def lookup_inverse(other)
512
829
  return nil unless other
513
- other.to_a.first.relations.each_pair do |key, meta|
830
+ other.class.relations.each_pair do |key, meta|
514
831
  return meta.name if meta.as == name
515
832
  end
516
833
  end
517
-
518
- # Handles two different cases - the first is a convenience for JSON like
519
- # access to the hash instead of having to call []. The second is a
520
- # delegation of the "*?" methods to has_key? as a convenience to check
521
- # for existence of a value.
522
- #
523
- # @example Extras provided by this method.
524
- # metadata.name
525
- # metadata.name?
526
- #
527
- # @param [ Symbol ] name The name of the method.
528
- # @param [ Array ] args The arguments passed to the method.
529
- #
530
- # @return [ Object ] Either the value or a boolen.
531
- #
532
- # @since 2.0.0.rc.1
533
- def method_missing(name, *args)
534
- method = name.to_s
535
- method =~ /\?/ ? has_key?(method.sub('?', '').to_sym) : self[name]
536
- end
537
834
  end
538
835
  end
539
836
  end