mongoid 2.1.5 → 2.1.6

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.
@@ -21,7 +21,9 @@ module Mongoid #:nodoc:
21
21
  {}.tap do |hash|
22
22
  changed.each do |name|
23
23
  change = attribute_change(name)
24
- hash[name] = change if change[0] != change[1]
24
+ if change
25
+ hash[name] = change if change[0] != change[1]
26
+ end
25
27
  end
26
28
  end
27
29
  end
@@ -89,5 +91,20 @@ module Mongoid #:nodoc:
89
91
  def attribute_change(attr)
90
92
  [changed_attributes[attr], attributes[attr]] if attribute_changed?(attr)
91
93
  end
94
+
95
+ # Determine if a specific attribute has changed.
96
+ #
97
+ # @note Overriding AM::Dirty once again since their implementation is not
98
+ # friendly to fields that can be changed in place.
99
+ #
100
+ # @param [ String ] attr The name of the attribute.
101
+ #
102
+ # @return [ true, false ] Whether the attribute has changed.
103
+ #
104
+ # @since 2.1.6
105
+ def attribute_changed?(attr)
106
+ return false unless changed_attributes.include?(attr)
107
+ changed_attributes[attr] != attributes[attr]
108
+ end
92
109
  end
93
110
  end
@@ -154,11 +154,7 @@ module Mongoid #:nodoc:
154
154
  changed_attributes.clear
155
155
  apply_default_attributes
156
156
  tap do
157
- relations.keys.each do |name|
158
- if instance_variable_defined?("@#{name}")
159
- remove_instance_variable("@#{name}")
160
- end
161
- end
157
+ reload_relations
162
158
  run_callbacks(:initialize)
163
159
  end
164
160
  end
@@ -6,6 +6,7 @@ require "mongoid/extensions/hash/scoping"
6
6
  require "mongoid/extensions/nil/collectionization"
7
7
  require "mongoid/extensions/object/checks"
8
8
  require "mongoid/extensions/object/reflections"
9
+ require "mongoid/extensions/object/substitutable"
9
10
  require "mongoid/extensions/object/yoda"
10
11
  require "mongoid/extensions/proc/scoping"
11
12
  require "mongoid/extensions/string/conversions"
@@ -37,6 +38,7 @@ end
37
38
  class Object #:nodoc:
38
39
  include Mongoid::Extensions::Object::Checks
39
40
  include Mongoid::Extensions::Object::Reflections
41
+ include Mongoid::Extensions::Object::Substitutable
40
42
  include Mongoid::Extensions::Object::Yoda
41
43
  end
42
44
 
@@ -0,0 +1,15 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+ module Extensions #:nodoc:
4
+ module Object #:nodoc:
5
+
6
+ # This module is for defining base substitutable behaviour.
7
+ module Substitutable #:nodoc:
8
+
9
+ def substitutable
10
+ self
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -242,11 +242,11 @@ module Mongoid #:nodoc
242
242
  end
243
243
  else
244
244
  define_method(meth) do
245
- value = read_attribute(name)
246
- if value.is_a?(Array) || value.is_a?(Hash)
247
- changed_attributes[name] = value.clone unless attribute_changed?(name)
245
+ read_attribute(name).tap do |value|
246
+ if value.is_a?(Array) || value.is_a?(Hash)
247
+ changed_attributes[name] = value.clone unless attribute_changed?(name)
248
+ end
248
249
  end
249
- value
250
250
  end
251
251
  end
252
252
  define_method("#{meth}=") do |value|
@@ -33,7 +33,7 @@ module Mongoid #:nodoc:
33
33
  #
34
34
  # @since 2.1.0
35
35
  def serialize(object)
36
- object.blank? ? [] : constraint.convert(object)
36
+ object ? constraint.convert(object) : []
37
37
  end
38
38
 
39
39
  protected
@@ -107,5 +107,22 @@ module Mongoid # :nodoc:
107
107
  def referenced_one?
108
108
  metadata && metadata.macro == :references_one
109
109
  end
110
+
111
+ # Convenience method for iterating through the loaded relations and
112
+ # reloading them.
113
+ #
114
+ # @example Reload the relations.
115
+ # document.reload_relations
116
+ #
117
+ # @return [ Hash ] The relations metadata.
118
+ #
119
+ # @since 2.1.6
120
+ def reload_relations
121
+ relations.each_pair do |name, meta|
122
+ if instance_variable_defined?("@#{name}")
123
+ remove_instance_variable("@#{name}")
124
+ end
125
+ end
126
+ end
110
127
  end
111
128
  end
@@ -74,20 +74,6 @@ module Mongoid # :nodoc:
74
74
  instance_variable_set("@#{name}", relation)
75
75
  end
76
76
 
77
- # Replace an existing relation with a new one.
78
- #
79
- # @example Replace the relation.
80
- # document.substitute("addresses", Address.new)
81
- #
82
- # @param [ String ] name The name of the relation.
83
- # @param [ Document ] object The document to replace with.
84
- # @param [ Hash ] options The options.
85
- #
86
- # @since 2.0.0
87
- def substitute(name, object)
88
- set_relation(name, ivar(name).substitute(object))
89
- end
90
-
91
77
  module ClassMethods #:nodoc:
92
78
 
93
79
  # Defines the getter for the relation. Nothing too special here: just
@@ -134,16 +120,11 @@ module Mongoid # :nodoc:
134
120
  # @since 2.0.0.rc.1
135
121
  def setter(name, metadata)
136
122
  tap do
137
- define_method("#{name}=") do |*args|
138
- object = args.first
139
- if relation_exists?(name) && !object.is_a?(Hash)
140
- substitute(name, object)
123
+ define_method("#{name}=") do |object|
124
+ if relation_exists?(name) || metadata.many?
125
+ set_relation(name, send(name).substitute(object.substitutable))
141
126
  else
142
- if metadata.embedded? && object.blank? && send(name)
143
- substitute(name, object)
144
- else
145
- build(name, object, metadata)
146
- end
127
+ set_relation(name, build(name, object.substitutable, metadata))
147
128
  end
148
129
  end
149
130
  end
@@ -26,6 +26,18 @@ module Mongoid # :nodoc:
26
26
  end
27
27
  end
28
28
 
29
+ # This substituable does not clone.
30
+ #
31
+ # @example Get the substitutable.
32
+ # proxy.substitutable
33
+ #
34
+ # @return [ Object ] The target.
35
+ #
36
+ # @since 2.1.6
37
+ def substitutable
38
+ target
39
+ end
40
+
29
41
  # Substitutes the supplied target documents for the existing document
30
42
  # in the relation.
31
43
  #
@@ -44,6 +56,7 @@ module Mongoid # :nodoc:
44
56
  base.delete unless binding?
45
57
  return nil
46
58
  end
59
+ base.new_record = true
47
60
  proxy.target = replacement
48
61
  proxy.bind_one
49
62
  end
@@ -231,6 +231,9 @@ module Mongoid # :nodoc:
231
231
  proxy.clear
232
232
  else
233
233
  atomically(:$set) do
234
+ if replacement.first.is_a?(Hash)
235
+ replacement = Many.builder(metadata, replacement).build
236
+ end
234
237
  proxy.target = replacement.compact
235
238
  proxy.target.each_with_index do |doc, index|
236
239
  integrate(doc)
@@ -375,7 +375,7 @@ module Mongoid # :nodoc:
375
375
  # @since 2.0.0.rc.1
376
376
  def inverse_foreign_key
377
377
  @inverse_foreign_key ||=
378
- ( inverse_of ? inverse_of.to_s.singularize : inverse_class_name.underscore ) <<
378
+ ( inverse_of ? inverse_of.to_s.singularize : inverse_class_name.demodulize.underscore ) <<
379
379
  relation.foreign_key_suffix
380
380
  end
381
381
 
@@ -496,6 +496,18 @@ module Mongoid # :nodoc:
496
496
  @klass ||= class_name.constantize
497
497
  end
498
498
 
499
+ # Is this metadata representing a one to many or many to many relation?
500
+ #
501
+ # @example Is the relation a many?
502
+ # metadata.many?
503
+ #
504
+ # @return [ true, false ] If the relation is a many.
505
+ #
506
+ # @since 2.1.6
507
+ def many?
508
+ @many ||= relation.macro =~ /many/
509
+ end
510
+
499
511
  # Returns the macro for the relation of this metadata.
500
512
  #
501
513
  # @example Get the macro.
@@ -16,7 +16,6 @@ module Mongoid # :nodoc:
16
16
 
17
17
  # Backwards compatibility with Mongoid beta releases.
18
18
  delegate :klass, :to => :metadata
19
-
20
19
  delegate :bind_one, :unbind_one, :to => :binding
21
20
 
22
21
  # Convenience for setting the target and the metadata properties since
@@ -36,6 +35,19 @@ module Mongoid # :nodoc:
36
35
  extend metadata.extension if metadata.extension?
37
36
  end
38
37
 
38
+ # The default substitutable object for a relation proxy is the clone of
39
+ # the target.
40
+ #
41
+ # @example Get the substitutable.
42
+ # proxy.substitutable
43
+ #
44
+ # @return [ Object ] A clone of the target.
45
+ #
46
+ # @since 2.1.6
47
+ def substitutable
48
+ target.clone
49
+ end
50
+
39
51
  protected
40
52
 
41
53
  # Is the current thread in binding mode?
@@ -25,6 +25,18 @@ module Mongoid # :nodoc:
25
25
  end
26
26
  end
27
27
 
28
+ # This substituable does not clone.
29
+ #
30
+ # @example Get the substitutable.
31
+ # proxy.substitutable
32
+ #
33
+ # @return [ Object ] The target.
34
+ #
35
+ # @since 2.1.6
36
+ def substitutable
37
+ target
38
+ end
39
+
28
40
  # Substitutes the supplied target documents for the existing document
29
41
  # in the relation.
30
42
  #
@@ -214,15 +214,8 @@ module Mongoid #:nodoc:
214
214
  #
215
215
  # @since 2.0.0.beta.1
216
216
  def initialize(base, target, metadata)
217
- init(base, Targets::Enumerable.new(target), metadata) do |proxy|
217
+ init(base, Targets::Enumerable.new(target), metadata) do
218
218
  raise_mixed if klass.embedded?
219
- batched do
220
- proxy.in_memory do |doc|
221
- characterize_one(doc)
222
- bind_one(doc)
223
- doc.save if persistable?
224
- end
225
- end
226
219
  end
227
220
  end
228
221
 
@@ -275,7 +268,7 @@ module Mongoid #:nodoc:
275
268
  def substitute(replacement)
276
269
  tap do |proxy|
277
270
  proxy.purge
278
- proxy.push(replacement) if replacement
271
+ proxy.push(replacement.compact) if replacement
279
272
  end
280
273
  end
281
274
 
@@ -132,36 +132,6 @@ module Mongoid # :nodoc:
132
132
  end
133
133
  end
134
134
 
135
- # Instantiate a new references_many relation. Will set the foreign key
136
- # and the base on the inverse object.
137
- #
138
- # @example Create the new relation.
139
- # Referenced::Many.new(base, target, metadata)
140
- #
141
- # @param [ Document ] base The document this relation hangs off of.
142
- # @param [ Array<Document> ] target The target of the relation.
143
- # @param [ Metadata ] metadata The relation's metadata.
144
- #
145
- # @since 2.0.0.beta.1
146
- def initialize(base, target, metadata)
147
- init(base, Targets::Enumerable.new(target), metadata) do |proxy|
148
- raise_mixed if klass.embedded?
149
- batched do
150
- proxy.in_memory do |doc|
151
- characterize_one(doc)
152
- bind_one(doc)
153
- if persistable?
154
- base.push(metadata.foreign_key, doc.id)
155
- base.synced[metadata.foreign_key] = false
156
- doc.save
157
- else
158
- base.send(metadata.foreign_key).push(doc.id)
159
- end
160
- end
161
- end
162
- end
163
- end
164
-
165
135
  # Removes all associations between the base document and the target
166
136
  # documents by deleting the foreign keys and the references, orphaning
167
137
  # the target documents in the process.
@@ -185,6 +155,27 @@ module Mongoid # :nodoc:
185
155
  alias :nullify_all :nullify
186
156
  alias :clear :nullify
187
157
 
158
+ # Clear the relation. Will delete the documents from the db if they are
159
+ # already persisted.
160
+ #
161
+ # @example Clear the relation.
162
+ # person.posts.clear
163
+ #
164
+ # @return [ Many ] The relation emptied.
165
+ #
166
+ # @since 2.0.0.beta.1
167
+ def purge
168
+ criteria.delete_all
169
+ base.set(
170
+ metadata.foreign_key,
171
+ base.send(metadata.foreign_key).clear
172
+ )
173
+ target.clear do |doc|
174
+ unbind_one(doc)
175
+ doc.destroyed = true
176
+ end
177
+ end
178
+
188
179
  private
189
180
 
190
181
  # Appends the document to the target array, updating the index on the
@@ -244,6 +235,19 @@ module Mongoid # :nodoc:
244
235
  Builders::Referenced::ManyToMany.new(meta, object, loading)
245
236
  end
246
237
 
238
+ # Create the standard criteria for this relation given the supplied
239
+ # metadata and object.
240
+ #
241
+ # @example Get the criteria.
242
+ # Proxy.criteria(meta, object)
243
+ #
244
+ # @param [ Metadata ] metadata The relation metadata.
245
+ # @param [ Object ] object The object for the criteria.
246
+ # @param [ Class ] type The criteria class.
247
+ #
248
+ # @return [ Criteria ] The criteria.
249
+ #
250
+ # @since 2.1.0
247
251
  def criteria(metadata, object, type = nil)
248
252
  metadata.klass.any_in(:_id => object)
249
253
  end
@@ -61,6 +61,7 @@ module Mongoid # :nodoc:
61
61
  #
62
62
  # @since 2.1.0
63
63
  def update_inverse_keys(meta)
64
+ return unless changes.has_key?(meta.foreign_key)
64
65
  old, new = changes[meta.foreign_key]
65
66
  meta.criteria(new - old).add_to_set(meta.inverse_foreign_key, id)
66
67
  meta.criteria(old - new).pull(meta.inverse_foreign_key, id)
@@ -67,6 +67,20 @@ module Mongoid #:nodoc:
67
67
  loaded.clear and added.clear
68
68
  end
69
69
 
70
+ # Clones each document in the enumerable.
71
+ #
72
+ # @note This loads all documents into memory.
73
+ #
74
+ # @example Clone the enumerable.
75
+ # enumerable.clone
76
+ #
77
+ # @return [ Array<Document> ] An array clone of the enumerable.
78
+ #
79
+ # @since 2.1.6
80
+ def clone
81
+ collect { |doc| doc.clone }
82
+ end
83
+
70
84
  # Delete the supplied document from the enumerable.
71
85
  #
72
86
  # @example Delete the document.
@@ -1,4 +1,4 @@
1
1
  # encoding: utf-8
2
2
  module Mongoid #:nodoc
3
- VERSION = "2.1.5"
3
+ VERSION = "2.1.6"
4
4
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mongoid
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.5
4
+ version: 2.1.6
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-08-05 00:00:00.000000000Z
12
+ date: 2011-08-08 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activemodel
16
- requirement: &70194026936900 !ruby/object:Gem::Requirement
16
+ requirement: &70184069667540 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '3.0'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70194026936900
24
+ version_requirements: *70184069667540
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: tzinfo
27
- requirement: &70194026936180 !ruby/object:Gem::Requirement
27
+ requirement: &70184069666660 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ~>
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: 0.3.22
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *70194026936180
35
+ version_requirements: *70184069666660
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: mongo
38
- requirement: &70194026935100 !ruby/object:Gem::Requirement
38
+ requirement: &70184069665680 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ~>
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: '1.3'
44
44
  type: :runtime
45
45
  prerelease: false
46
- version_requirements: *70194026935100
46
+ version_requirements: *70184069665680
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: rdoc
49
- requirement: &70194026934200 !ruby/object:Gem::Requirement
49
+ requirement: &70184069664720 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ~>
@@ -54,10 +54,10 @@ dependencies:
54
54
  version: 3.5.0
55
55
  type: :development
56
56
  prerelease: false
57
- version_requirements: *70194026934200
57
+ version_requirements: *70184069664720
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: bson_ext
60
- requirement: &70194026933020 !ruby/object:Gem::Requirement
60
+ requirement: &70184069663720 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - ~>
@@ -65,10 +65,10 @@ dependencies:
65
65
  version: '1.3'
66
66
  type: :development
67
67
  prerelease: false
68
- version_requirements: *70194026933020
68
+ version_requirements: *70184069663720
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: mocha
71
- requirement: &70194026932080 !ruby/object:Gem::Requirement
71
+ requirement: &70184069662540 !ruby/object:Gem::Requirement
72
72
  none: false
73
73
  requirements:
74
74
  - - ~>
@@ -76,10 +76,10 @@ dependencies:
76
76
  version: 0.9.8
77
77
  type: :development
78
78
  prerelease: false
79
- version_requirements: *70194026932080
79
+ version_requirements: *70184069662540
80
80
  - !ruby/object:Gem::Dependency
81
81
  name: rspec
82
- requirement: &70194026931080 !ruby/object:Gem::Requirement
82
+ requirement: &70184069661380 !ruby/object:Gem::Requirement
83
83
  none: false
84
84
  requirements:
85
85
  - - ~>
@@ -87,10 +87,10 @@ dependencies:
87
87
  version: '2.6'
88
88
  type: :development
89
89
  prerelease: false
90
- version_requirements: *70194026931080
90
+ version_requirements: *70184069661380
91
91
  - !ruby/object:Gem::Dependency
92
92
  name: watchr
93
- requirement: &70194026929800 !ruby/object:Gem::Requirement
93
+ requirement: &70184069660280 !ruby/object:Gem::Requirement
94
94
  none: false
95
95
  requirements:
96
96
  - - ~>
@@ -98,7 +98,7 @@ dependencies:
98
98
  version: '0.6'
99
99
  type: :development
100
100
  prerelease: false
101
- version_requirements: *70194026929800
101
+ version_requirements: *70184069660280
102
102
  description: Mongoid is an ODM (Object Document Mapper) Framework for MongoDB, written
103
103
  in Ruby.
104
104
  email:
@@ -186,6 +186,7 @@ files:
186
186
  - lib/mongoid/extensions/nil/collectionization.rb
187
187
  - lib/mongoid/extensions/object/checks.rb
188
188
  - lib/mongoid/extensions/object/reflections.rb
189
+ - lib/mongoid/extensions/object/substitutable.rb
189
190
  - lib/mongoid/extensions/object/yoda.rb
190
191
  - lib/mongoid/extensions/object_id/conversions.rb
191
192
  - lib/mongoid/extensions/proc/scoping.rb
@@ -378,7 +379,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
378
379
  version: '0'
379
380
  segments:
380
381
  - 0
381
- hash: 3142306228316146123
382
+ hash: -4360740221674892894
382
383
  required_rubygems_version: !ruby/object:Gem::Requirement
383
384
  none: false
384
385
  requirements: