mongoid 2.0.2 → 2.1.0

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 (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