mongo_doc 0.4.1 → 0.4.2

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.
data/HISTORY.md ADDED
@@ -0,0 +1,4 @@
1
+ ## 0.4.2
2
+
3
+ * 'Document#update_attributes' uses $ positional operator when used from within an embed_many association
4
+ * Require MongoDB 1.3.4 or greater
data/README.textile CHANGED
@@ -1,6 +1,10 @@
1
1
  h1. MongoDoc
2
2
 
3
- Version: Turbulence (0.4.1) 2010/03/17
3
+ Version: Turbulence (0.4.2) 2010/03/23
4
+
5
+ h2. What's New in Turbulence (0.4.2)
6
+
7
+ Support for the $ positional operator for in-place array updates. This requires MongoDB version 1.3.4 or higher.
4
8
 
5
9
  h2. What's New in Turbulence (0.4.1)
6
10
 
data/Rakefile CHANGED
@@ -10,8 +10,8 @@ begin
10
10
  gem.homepage = "http://github.com/leshill/mongodoc"
11
11
  gem.authors = ["Les Hill"]
12
12
  gem.add_dependency "activesupport", ">= 2.3.4"
13
- gem.add_dependency "mongo", "= 0.19"
14
- gem.add_dependency "mongo_ext", "= 0.19"
13
+ gem.add_dependency "mongo", "= 0.19.1"
14
+ gem.add_dependency "mongo_ext", "= 0.19.1"
15
15
  gem.add_dependency "durran-validatable", "= 2.0.1"
16
16
  gem.add_dependency "leshill-will_paginate", "= 2.3.11"
17
17
  gem.add_development_dependency "rspec", "= 1.3.0"
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.4.1
1
+ 0.4.2
@@ -59,47 +59,37 @@ Feature: Partial Updates
59
59
  | 1 Main St. | Jacksonville | FL | 32218 |
60
60
  And I save the document 'hashrocket_hq'
61
61
 
62
- Scenario: Naive Update
62
+ Scenario: Update
63
63
  When I update the 'note' for 'contractor' to 'Knows MongoDB and MongoDoc'
64
- Then the document 'contractor' roundtrips
64
+ Then the last return value is true
65
+ And the document 'contractor' roundtrips
65
66
 
66
- Scenario: Naive Update on a has one
67
+ Scenario: Update on a has one
67
68
  When I update the 'street' for 'hq_address' to '320 1st Street North'
68
- Then the document 'hashrocket_hq' roundtrips
69
+ Then the last return value is true
70
+ And the document 'hashrocket_hq' roundtrips
69
71
 
70
- Scenario: Naive Update on a has many
72
+ Scenario: Update on a has many
71
73
  When 'hq_address' is the first address of 'hashrocket'
72
74
  And I update the 'street' for 'hq_address' to '320 1st Street North'
73
- Then the document 'hashrocket' roundtrips
75
+ Then the last return value is true
76
+ And the document 'hashrocket' roundtrips
74
77
 
75
- Scenario: Strict Update
76
- When I strict update the 'note' for 'contractor' to 'Knows MongoDB and MongoDoc'
77
- Then the document 'contractor' roundtrips
78
-
79
- Scenario: Strict Update on a has one
80
- When I strict update the 'street' for 'hq_address' to '320 1st Street North'
81
- Then the document 'hashrocket_hq' roundtrips
82
-
83
- Scenario: Strict Update on a has many
84
- When 'hq_address' is the first address of 'hashrocket'
85
- And I strict update the 'street' for 'hq_address' to '320 1st Street North'
86
- Then the document 'hashrocket' roundtrips
87
-
88
- Scenario: Failing Strict Update on a has one
78
+ Scenario: Failing Update on a has one
89
79
  When someone else changes the Address 'address' of 'hashrocket_hq' to
90
80
  | Street | City | State | Zip Code |
91
81
  | 1 Ocean Blvd. | Jacksonville | FL | 32218 |
92
- And I strict update the 'street' for 'hq_address' to '320 1st Street North'
82
+ And I update the 'street' for 'hq_address' to '320 1st Street North'
93
83
  Then the last return value is false
94
84
  And the document 'hashrocket_hq' does not roundtrip
95
85
 
96
- Scenario: Failing Strict Update on a has many
86
+ Scenario: Failing Update on a has many
97
87
  When 'hq_address' is the first address of 'hashrocket'
98
88
  And someone else changes the addresses of 'hashrocket':
99
89
  | Street | City | State | Zip Code |
100
90
  | 320 1st N, #712 | Jacksonville Beach | FL | 32250 |
101
91
  | 1001 Mulligan Street | Chicago | IL | 60611 |
102
92
  | 345 Avenida Grande | Santiago | Chile | |
103
- And I strict update the 'street' for 'hq_address' to '320 1st Street North'
93
+ And I update the 'street' for 'hq_address' to '320 1st Street North'
104
94
  Then the last return value is false
105
95
  And the document 'hashrocket' does not roundtrip
@@ -1,7 +1,6 @@
1
- When /^I(\sstrict\s|\s)update the '(.+)' for '(.+)' to '(.+)'$/ do |strict, attr, doc_name, value|
1
+ When /^I update the '(.+)' for '(.+)' to '(.+)'$/ do |attr, doc_name, value|
2
2
  doc = instance_variable_get("@#{doc_name}")
3
3
  attrs = {attr => value}
4
- attrs.merge!(:__strict__ => true) unless strict.blank?
5
4
  @last_return = doc.update_attributes(attrs)
6
5
  end
7
6
 
@@ -92,8 +92,8 @@ module MongoDoc
92
92
 
93
93
  protected
94
94
 
95
- def annotated_keys(src, attrs)
96
- assoc_path = "#{assoc_name}.#{index(src)}"
95
+ def annotated_keys(src, attrs, selector = false)
96
+ assoc_path = "#{assoc_name}" + (selector ? "" : ".$")
97
97
  annotated = {}
98
98
  attrs.each do |(key, value)|
99
99
  annotated["#{assoc_path}.#{key}"] = value
@@ -81,7 +81,7 @@ module MongoDoc
81
81
 
82
82
  protected
83
83
 
84
- def annotated_keys(src, attrs)
84
+ def annotated_keys(src, attrs, selector = false)
85
85
  assoc_path = "#{assoc_name}.#{index(src)}"
86
86
  annotated = {}
87
87
  attrs.each do |(key, value)|
@@ -11,8 +11,8 @@ module MongoDoc
11
11
  @_parent = parent
12
12
  end
13
13
 
14
- def _path_to_root(src, attrs)
15
- _parent._path_to_root(src, annotated_keys(src, attrs))
14
+ def _path_to_root(src, attrs, selector = false)
15
+ _parent._path_to_root(src, annotated_keys(src, attrs, selector), selector)
16
16
  end
17
17
 
18
18
  def _root=(root)
@@ -37,7 +37,7 @@ module MongoDoc
37
37
 
38
38
  protected
39
39
 
40
- def annotated_keys(src, hash)
40
+ def annotated_keys(src, hash, selector = false)
41
41
  annotated = {}
42
42
  hash.each do |(key, value)|
43
43
  annotated["#{assoc_name}.#{key}"] = value
@@ -40,9 +40,9 @@ module MongoDoc
40
40
  end
41
41
  end
42
42
 
43
- def _path_to_root(src, attrs)
43
+ def _path_to_root(src, attrs, selector = false)
44
44
  return attrs unless _parent
45
- _parent._path_to_root(self, attrs)
45
+ _parent._path_to_root(self, attrs, selector)
46
46
  end
47
47
 
48
48
  module ClassMethods
@@ -82,7 +82,7 @@ module MongoDoc
82
82
  end
83
83
 
84
84
  def verify_server_version(connection)
85
- raise UnsupportedServerVersionError.new('MongoDoc requires at least mongoDB version 1.3.2') unless connection.server_version >= "1.3.2"
85
+ raise UnsupportedServerVersionError.new('MongoDoc requires at least mongoDB version 1.3.2') unless connection.server_version >= "1.3.4"
86
86
  end
87
87
  end
88
88
  end
@@ -80,15 +80,10 @@ module MongoDoc
80
80
  end
81
81
 
82
82
  def update_attributes(attrs)
83
- strict = attrs.delete(:__strict__)
84
83
  self.attributes = attrs
85
84
  return save if new_record?
86
85
  return false unless valid?
87
- if strict
88
- _strict_update_attributes(_path_to_root(self, attrs), false)
89
- else
90
- _naive_update_attributes(_path_to_root(self, attrs), false)
91
- end
86
+ _update({}, attrs, false)
92
87
  end
93
88
 
94
89
  def update_attributes!(attrs)
@@ -96,11 +91,7 @@ module MongoDoc
96
91
  self.attributes = attrs
97
92
  return save! if new_record?
98
93
  raise DocumentInvalidError unless valid?
99
- if strict
100
- _strict_update_attributes(_path_to_root(self, attrs), true)
101
- else
102
- _naive_update_attributes(_path_to_root(self, attrs), true)
103
- end
94
+ _update({}, attrs, true)
104
95
  end
105
96
 
106
97
  module ClassMethods
@@ -139,21 +130,12 @@ module MongoDoc
139
130
  self.class.collection
140
131
  end
141
132
 
142
- def _naive_update_attributes(attrs, safe)
143
- return _root.send(:_naive_update_attributes, attrs, safe) if _root
144
- _update({}, attrs, safe)
145
- end
146
-
147
133
  def _remove
148
134
  _collection.remove({'_id' => _id})
149
135
  end
150
136
 
151
- def _strict_update_attributes(attrs, safe, selector = {})
152
- return _root.send(:_strict_update_attributes, attrs, safe, _path_to_root(self, '_id' => _id)) if _root
153
- _update(selector, attrs, safe)
154
- end
155
-
156
137
  def _update(selector, data, safe)
138
+ return _root.send(:_update, _path_to_root(self, {'_id' => _id}, true), _path_to_root(self, data), safe) if _root
157
139
  _collection.update({'_id' => _id}.merge(selector), MongoDoc::Query.set_modifier(data), :safe => safe)
158
140
  end
159
141
 
data/lib/mongo_doc.rb CHANGED
@@ -4,7 +4,7 @@ require 'validatable'
4
4
  require 'will_paginate/collection'
5
5
 
6
6
  module MongoDoc
7
- VERSION = '0.4.1'
7
+ VERSION = '0.4.2'
8
8
  end
9
9
 
10
10
  require 'mongo_doc/connection'
data/mongo_doc.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{mongo_doc}
8
- s.version = "0.4.1"
8
+ s.version = "0.4.2"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Les Hill"]
12
- s.date = %q{2010-03-17}
12
+ s.date = %q{2010-03-23}
13
13
  s.description = %q{ODM for MongoDB}
14
14
  s.email = %q{leshill@gmail.com}
15
15
  s.extra_rdoc_files = [
@@ -20,6 +20,7 @@ Gem::Specification.new do |s|
20
20
  s.files = [
21
21
  ".document",
22
22
  ".gitignore",
23
+ "HISTORY.md",
23
24
  "LICENSE",
24
25
  "README.textile",
25
26
  "Rakefile",
@@ -120,6 +121,7 @@ Gem::Specification.new do |s|
120
121
  "perf/mongo_doc_runner.rb",
121
122
  "perf/ruby_driver_runner.rb",
122
123
  "script/console",
124
+ "spec/array_including_argument_matcher.rb",
123
125
  "spec/associations/collection_proxy_spec.rb",
124
126
  "spec/associations/document_proxy_spec.rb",
125
127
  "spec/associations/hash_proxy_spec.rb",
@@ -157,7 +159,8 @@ Gem::Specification.new do |s|
157
159
  s.rubygems_version = %q{1.3.6}
158
160
  s.summary = %q{ODM for MongoDB}
159
161
  s.test_files = [
160
- "spec/associations/collection_proxy_spec.rb",
162
+ "spec/array_including_argument_matcher.rb",
163
+ "spec/associations/collection_proxy_spec.rb",
161
164
  "spec/associations/document_proxy_spec.rb",
162
165
  "spec/associations/hash_proxy_spec.rb",
163
166
  "spec/associations_spec.rb",
@@ -194,16 +197,16 @@ Gem::Specification.new do |s|
194
197
 
195
198
  if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
196
199
  s.add_runtime_dependency(%q<activesupport>, [">= 2.3.4"])
197
- s.add_runtime_dependency(%q<mongo>, ["= 0.19"])
198
- s.add_runtime_dependency(%q<mongo_ext>, ["= 0.19"])
200
+ s.add_runtime_dependency(%q<mongo>, ["= 0.19.1"])
201
+ s.add_runtime_dependency(%q<mongo_ext>, ["= 0.19.1"])
199
202
  s.add_runtime_dependency(%q<durran-validatable>, ["= 2.0.1"])
200
203
  s.add_runtime_dependency(%q<leshill-will_paginate>, ["= 2.3.11"])
201
204
  s.add_development_dependency(%q<rspec>, ["= 1.3.0"])
202
205
  s.add_development_dependency(%q<cucumber>, ["= 0.6.2"])
203
206
  else
204
207
  s.add_dependency(%q<activesupport>, [">= 2.3.4"])
205
- s.add_dependency(%q<mongo>, ["= 0.19"])
206
- s.add_dependency(%q<mongo_ext>, ["= 0.19"])
208
+ s.add_dependency(%q<mongo>, ["= 0.19.1"])
209
+ s.add_dependency(%q<mongo_ext>, ["= 0.19.1"])
207
210
  s.add_dependency(%q<durran-validatable>, ["= 2.0.1"])
208
211
  s.add_dependency(%q<leshill-will_paginate>, ["= 2.3.11"])
209
212
  s.add_dependency(%q<rspec>, ["= 1.3.0"])
@@ -211,8 +214,8 @@ Gem::Specification.new do |s|
211
214
  end
212
215
  else
213
216
  s.add_dependency(%q<activesupport>, [">= 2.3.4"])
214
- s.add_dependency(%q<mongo>, ["= 0.19"])
215
- s.add_dependency(%q<mongo_ext>, ["= 0.19"])
217
+ s.add_dependency(%q<mongo>, ["= 0.19.1"])
218
+ s.add_dependency(%q<mongo_ext>, ["= 0.19.1"])
216
219
  s.add_dependency(%q<durran-validatable>, ["= 2.0.1"])
217
220
  s.add_dependency(%q<leshill-will_paginate>, ["= 2.3.11"])
218
221
  s.add_dependency(%q<rspec>, ["= 1.3.0"])
@@ -0,0 +1,62 @@
1
+ # From http://gist.github.com/62943
2
+ # Author http://github.com/trotter
3
+ module Spec
4
+ module Mocks
5
+ module ArgumentMatchers
6
+
7
+ class ArrayIncludingMatcher
8
+ # We'll allow an array of arguments to be passed in, so that you can do
9
+ # things like obj.should_receive(:blah).with(array_including('a', 'b'))
10
+ def initialize(*expected)
11
+ @expected = expected
12
+ end
13
+
14
+ # actual is the array (hopefully) passed to the method by the user.
15
+ # We'll check that it includes all the expected values, and return false
16
+ # if it doesn't or if we blow up because #include? is not defined.
17
+ def ==(actual)
18
+ @expected.each do |expected|
19
+ return false unless actual.include?(expected)
20
+ end
21
+ true
22
+ rescue NoMethodError => ex
23
+ return false
24
+ end
25
+
26
+ def description
27
+ "array_including(#{@expected.join(', ')})"
28
+ end
29
+ end
30
+
31
+ class ArrayNotIncludingMatcher
32
+ def initialize(*expected)
33
+ @expected = expected
34
+ end
35
+
36
+ def ==(actual)
37
+ @expected.each do |expected|
38
+ return false if actual.include?(expected)
39
+ end
40
+ true
41
+ rescue NoMethodError => ex
42
+ return false
43
+ end
44
+
45
+ def description
46
+ "array_not_including(#{@expected.join(', ')})"
47
+ end
48
+ end
49
+
50
+ # array_including is a helpful wrapper that allows us to actually type
51
+ # #with(array_including(...)) instead of ArrayIncludingMatcher.new(...)
52
+ def array_including(*args)
53
+ ArrayIncludingMatcher.new(*args)
54
+ end
55
+
56
+ def array_not_including(*args)
57
+ ArrayNotIncludingMatcher.new(*args)
58
+ end
59
+
60
+ end
61
+ end
62
+ end
@@ -7,10 +7,20 @@ describe MongoDoc::Associations::CollectionProxy do
7
7
  attr_accessor :name
8
8
  end
9
9
 
10
- let(:root) { stub('root', :register_save_observer => nil) }
10
+ let(:root) { CollectionProxyTest.new }
11
11
  let(:proxy) { MongoDoc::Associations::CollectionProxy.new(:assoc_name => 'embed_many_name', :assoc_class => CollectionProxyTest, :root => root, :parent => root) }
12
12
  let(:item) { CollectionProxyTest.new }
13
13
 
14
+ describe "#_path_to_root" do
15
+ it "inserts the association name and '$' when not a selector" do
16
+ proxy._path_to_root(CollectionProxyTest.new, 'name' => 'value').should == {"embed_many_name.$.name" => 'value'}
17
+ end
18
+
19
+ it "inserts the association name when a selector" do
20
+ proxy._path_to_root(CollectionProxyTest.new, {'name' => 'value'}, true).should == {"embed_many_name.name" => 'value'}
21
+ end
22
+ end
23
+
14
24
  context "#<<" do
15
25
  it "appends the item to the collection" do
16
26
  (proxy << item).should include(item)
@@ -7,11 +7,16 @@ describe MongoDoc::Associations::HashProxy do
7
7
  attr_accessor :name
8
8
  end
9
9
 
10
- let(:root) { stub('root', :register_save_observer => nil) }
10
+ let(:root) { HashProxyTest.new }
11
11
  let(:proxy) { MongoDoc::Associations::HashProxy.new(:assoc_name => 'embed_hash_name', :assoc_class => HashProxyTest, :root => root, :parent => root) }
12
12
  let(:item) { HashProxyTest.new }
13
13
  let(:other_item) {[1,2]}
14
14
 
15
+ it "inserts the association name and key into the _path_to_root" do
16
+ proxy.stub(:index).and_return('key')
17
+ proxy._path_to_root(HashProxyTest.new, 'name' => 'value').should == {"embed_hash_name.key.name" => 'value'}
18
+ end
19
+
15
20
  context "#[]=" do
16
21
  it "adds the item to the hash" do
17
22
  proxy['new'] = item
@@ -105,12 +105,12 @@ describe "MongoDoc::Connection.Connections" do
105
105
  let(:connection) { stub('connection') }
106
106
 
107
107
  it "raises when the server version is unsupported" do
108
- connection.stub(:server_version).and_return(Mongo::ServerVersion.new('1.3.1'))
108
+ connection.stub(:server_version).and_return(Mongo::ServerVersion.new('1.3.2'))
109
109
  lambda { MongoDoc::Connection.send(:verify_server_version, connection) }.should raise_error(MongoDoc::UnsupportedServerVersionError)
110
110
  end
111
111
 
112
112
  it "returns when the server version is supported" do
113
- connection.stub(:server_version).and_return(Mongo::ServerVersion.new('1.3.2'))
113
+ connection.stub(:server_version).and_return(Mongo::ServerVersion.new('1.3.4'))
114
114
  lambda { MongoDoc::Connection.send(:verify_server_version, connection) }.should_not raise_error(MongoDoc::UnsupportedServerVersionError)
115
115
  end
116
116
  end
@@ -258,219 +258,114 @@ describe "MongoDoc::Document" do
258
258
  end
259
259
 
260
260
  context "updating attributes" do
261
- class UpdateAttributesRoot
261
+ class UpdateAttributesChild
262
262
  include MongoDoc::Document
263
263
 
264
- embed :update_attributes_child
264
+ attr_accessor :child_data
265
265
  end
266
266
 
267
- class UpdateAttributesChild
267
+ class UpdateAttributes
268
268
  include MongoDoc::Document
269
269
 
270
270
  attr_accessor :data
271
+ embed :child
271
272
  end
272
273
 
273
- let(:data) {'data'}
274
+ let(:collection) { stub(:update => nil) }
274
275
 
275
- let(:attrs) {{:data => data}}
276
+ let(:new_doc) { UpdateAttributes.new }
276
277
 
277
- let(:path_attrs) {{'update_attributes_child.data' => data}}
278
-
279
- let(:doc) do
280
- doc = UpdateAttributesChild.new
281
- doc._id = 'id'
282
- doc.stub(:_naive_update_attributes)
278
+ let(:existing_doc) do
279
+ doc = UpdateAttributes.new
280
+ doc._id = 'exists'
281
+ doc.stub(:_collection).and_return(collection)
283
282
  doc
284
283
  end
285
284
 
286
- before do
287
- root = UpdateAttributesRoot.new
288
- root.update_attributes_child = doc
289
- root._id = 'id'
285
+ let(:child) do
286
+ child = UpdateAttributesChild.new
287
+ child._id = 'child exists'
288
+ existing_doc.child = child
289
+ child
290
290
  end
291
291
 
292
- context "#update_attributes" do
293
- it "delegates to save if the object is a new record" do
294
- check = 'check'
295
- doc.stub(:new_record?).and_return(true)
296
- doc.should_receive(:save).and_return(check)
297
- doc.update_attributes(attrs).should == check
292
+ describe "#update_attributes" do
293
+ it "delegates to save if the doc is a new record" do
294
+ new_doc.should_receive(:save)
295
+ new_doc.update_attributes(:data => 'data')
298
296
  end
299
297
 
300
- it "sets the attributes" do
301
- doc.update_attributes(attrs)
302
- doc.data.should == data
303
- end
298
+ context "with an existing doc" do
304
299
 
305
- it "normalizes the attributes to the parent" do
306
- doc.should_receive(:_path_to_root)
307
- doc.update_attributes(attrs)
308
- end
300
+ subject { existing_doc.update_attributes(:data => 'data') }
309
301
 
310
- it "validates" do
311
- doc.should_receive(:valid?)
312
- doc.update_attributes(attrs)
313
- end
302
+ it "sets the attributes" do
303
+ subject
304
+ existing_doc.data.should == 'data'
305
+ end
314
306
 
315
- it "returns false if the object is not valid" do
316
- doc.stub(:valid?).and_return(false)
317
- doc.update_attributes(attrs).should be_false
318
- end
307
+ it "validates the doc" do
308
+ existing_doc.should_receive(:valid?)
309
+ subject
310
+ end
319
311
 
320
- context "if valid" do
321
- context "and strict" do
322
- it "delegates to _strict_update_attributes" do
323
- strict_attrs = attrs.merge(:__strict__ => true)
324
- doc.should_receive(:_strict_update_attributes).with(path_attrs, false)
325
- doc.update_attributes(strict_attrs)
326
- end
312
+ it "returns false if the doc is not valid" do
313
+ existing_doc.stub(:valid?).and_return(false)
314
+ should be_false
327
315
  end
328
316
 
329
- context "and naive" do
330
- it "delegates to _naive_update_attributes" do
331
- doc.should_receive(:_naive_update_attributes).with(path_attrs, false)
332
- doc.update_attributes(attrs)
333
- end
317
+ it "delegates to collection update" do
318
+ collection.should_receive(:update).with({'_id' => existing_doc._id}, {'$set' => {:data => 'data'}}, :safe => false)
319
+ subject
334
320
  end
335
321
 
336
- it "returns the result of _naive_update_attributes" do
337
- result = 'check'
338
- doc.stub(:_naive_update_attributes).and_return(result)
339
- doc.update_attributes(attrs).should == result
322
+ context "that is embedded" do
323
+ it "delegates to the root's collection update" do
324
+ collection.should_receive(:update).with({'_id' => existing_doc._id, 'child._id' => child._id}, {'$set' => {'child.child_data' => 'data'}}, :safe => false)
325
+ child.update_attributes(:child_data => 'data')
326
+ end
340
327
  end
341
328
  end
342
329
  end
343
330
 
344
- context "#update_attributes!" do
345
- it "delegates to save! if the object is a new record" do
346
- check = 'check'
347
- doc.stub(:new_record?).and_return(true)
348
- doc.should_receive(:save!).and_return(check)
349
- doc.update_attributes!(attrs).should == check
350
- end
351
-
352
- it "sets the attributes" do
353
- doc.update_attributes!(attrs)
354
- doc.data.should == data
331
+ describe "#update_attributes!" do
332
+ it "delegates to save! if the doc is a new record" do
333
+ new_doc.should_receive(:save!)
334
+ new_doc.update_attributes!(:data => 'data')
355
335
  end
356
336
 
357
- it "normalizes the attributes to the parent" do
358
- doc.should_receive(:_path_to_root)
359
- doc.update_attributes!(attrs)
360
- end
361
-
362
- it "validates" do
363
- doc.should_receive(:valid?).and_return(true)
364
- doc.update_attributes!(attrs)
365
- end
337
+ context "with an existing doc" do
366
338
 
367
- it "raises if not valid" do
368
- doc.stub(:valid?).and_return(false)
369
- expect do
370
- doc.update_attributes!(attrs)
371
- end.should raise_error(MongoDoc::DocumentInvalidError)
372
- end
339
+ subject { existing_doc.update_attributes!(:data => 'data') }
373
340
 
374
- context "if valid" do
375
- context "and strict" do
376
- it "delegates to _strict_update_attributes with safe == true" do
377
- strict_attrs = attrs.merge(:__strict__ => true)
378
- doc.should_receive(:_strict_update_attributes).with(path_attrs, true)
379
- doc.update_attributes!(strict_attrs)
380
- end
341
+ it "sets the attributes" do
342
+ subject
343
+ existing_doc.data.should == 'data'
381
344
  end
382
345
 
383
- context "and naive" do
384
- it "delegates to _naive_update_attributes with safe == true" do
385
- doc.should_receive(:_naive_update_attributes).with(path_attrs, true)
386
- doc.update_attributes!(attrs)
387
- end
346
+ it "validates the doc" do
347
+ existing_doc.should_receive(:valid?).and_return(true)
348
+ subject
388
349
  end
389
350
 
390
- it "returns the result of _naive_update_attributes" do
391
- result = 'check'
392
- doc.stub(:_naive_update_attributes).and_return(result)
393
- doc.update_attributes!(attrs).should == result
351
+ it "raises if not valid" do
352
+ existing_doc.stub(:valid?).and_return(false)
353
+ expect do
354
+ subject
355
+ end.should raise_error(MongoDoc::DocumentInvalidError)
394
356
  end
395
- end
396
- end
397
- end
398
-
399
- context "#_naive_update_attributes" do
400
- class NaiveUpdateAttributes
401
- include MongoDoc::Document
402
- end
403
-
404
357
 
405
- let(:id) { 'id' }
406
-
407
- let(:attrs) { {:data => 'data'} }
408
-
409
- let(:safe) { false }
410
-
411
- let(:doc) do
412
- doc = NaiveUpdateAttributes.new
413
- doc.stub(:_id).and_return(id)
414
- doc
415
- end
416
-
417
- it "without a root delegates to _update" do
418
- doc.should_receive(:_update).with({}, attrs, safe)
419
- doc.send(:_naive_update_attributes, attrs, safe)
420
- end
421
-
422
- it "with a root, calls _naive_update_attributes on the root" do
423
- root = NaiveUpdateAttributes.new
424
- doc.stub(:_root).and_return(root)
425
- root.should_receive(:_naive_update_attributes).with(attrs, safe)
426
- doc.send(:_naive_update_attributes, attrs, safe)
427
- end
428
- end
429
-
430
- context "#_strict_update_attributes" do
431
- class StrictUpdateAttributes
432
- include MongoDoc::Document
433
- end
434
-
435
- let(:id) { 'id' }
436
-
437
- let(:attrs) { {:data => 'data'} }
438
-
439
- let(:selector) { {:selector => 'selector'} }
440
-
441
- let(:safe) { false }
442
-
443
- let(:doc) do
444
- doc = StrictUpdateAttributes.new
445
- doc.stub(:_id).and_return(id)
446
- doc
447
- end
448
-
449
- context "without a root" do
450
- it "without a root delegates to _update" do
451
- doc.should_receive(:_update).with(selector, attrs, safe)
452
- doc.send(:_strict_update_attributes, attrs, safe, selector)
453
- end
454
- end
455
-
456
- context "with a root" do
457
- let(:root) { StrictUpdateAttributes.new }
458
-
459
- before do
460
- doc.stub(:_root).and_return(root)
461
- end
462
-
463
- it "calls _path_to_root on our id" do
464
- root.stub(:_strict_update_attributes)
465
- doc.should_receive(:_path_to_root).with(doc, '_id' => id)
466
- doc.send(:_strict_update_attributes, attrs, safe)
467
- end
358
+ it "delegates to collection update" do
359
+ collection.should_receive(:update).with({'_id' => existing_doc._id}, {'$set' => {:data => 'data'}}, :safe => true)
360
+ subject
361
+ end
468
362
 
469
- it "calls _strict_update_attributes on the root with our selector" do
470
- selector = {'path._id' => id}
471
- doc.stub(:_path_to_root).with(doc, '_id' => id).and_return(selector)
472
- root.should_receive(:_strict_update_attributes).with(attrs, safe, selector)
473
- doc.send(:_strict_update_attributes, attrs, safe)
363
+ context "that is embedded" do
364
+ it "delegates to the root's collection update" do
365
+ collection.should_receive(:update).with({'_id' => existing_doc._id, 'child._id' => child._id}, {'$set' => {'child.child_data' => 'data'}}, :safe => true)
366
+ child.update_attributes!(:child_data => 'data')
367
+ end
368
+ end
474
369
  end
475
370
  end
476
371
  end
@@ -41,17 +41,17 @@ describe "Saving embedded documents" do
41
41
  end
42
42
  end
43
43
 
44
- context "update_attributes naive" do
44
+ context "update_attributes" do
45
45
  context "with no embed_many, update_attributes" do
46
46
  let(:root) { NestedChild.new(:leaf => leaf) }
47
47
 
48
- it "calls the root document's _naive_update_attributes with a full attribute path and not safe" do
49
- root.should_receive(:_naive_update_attributes).with({'leaf.data' => data}, false)
48
+ it "calls the root document's _update with a full attribute path and not safe" do
49
+ root.should_receive(:_update).with({"leaf._id"=>"id"}, {'leaf.data' => data}, false)
50
50
  leaf.update_attributes(:data => data)
51
51
  end
52
52
 
53
- it "(with bang!) calls the root document's _naive_update_attributes with a full attribute path and safe" do
54
- root.should_receive(:_naive_update_attributes).with({'leaf.data' => data}, true)
53
+ it "(with bang!) calls the root document's _update with a full attribute path and safe" do
54
+ root.should_receive(:_update).with({"leaf._id"=>"id"}, {'leaf.data' => data}, true)
55
55
  leaf.update_attributes!(:data => data)
56
56
  end
57
57
  end
@@ -59,51 +59,15 @@ describe "Saving embedded documents" do
59
59
  context "with embed_many, update_attributes" do
60
60
  let(:root) { NestedDocsRoot.new(:nested_children => [NestedChild.new(:leaf => leaf)]) }
61
61
 
62
- it "calls the root document's _naive_update_attributes with a full attribute path and not safe" do
63
- root.should_receive(:_naive_update_attributes).with({'nested_children.0.leaf.data' => data}, false)
62
+ it "calls the root document's _update with a full attribute path and not safe" do
63
+ root.should_receive(:_update).with({"nested_children.leaf._id"=>"id"}, {'nested_children.$.leaf.data' => data}, false)
64
64
  leaf.update_attributes(:data => data)
65
65
  end
66
66
 
67
- it "(with bang!) calls the root document's _naive_update_attributes with a full attribute path and safe" do
68
- root.should_receive(:_naive_update_attributes).with({'nested_children.0.leaf.data' => data}, true)
67
+ it "(with bang!) calls the root document's _update with a full attribute path and safe" do
68
+ root.should_receive(:_update).with({"nested_children.leaf._id"=>"id"}, {'nested_children.$.leaf.data' => data}, true)
69
69
  leaf.update_attributes!(:data => data)
70
70
  end
71
71
  end
72
72
  end
73
-
74
- context "update_attributes strict" do
75
- let(:leaf_id) { 'leaf_id' }
76
-
77
- before do
78
- leaf.stub(:_id).and_return(leaf_id)
79
- end
80
-
81
- context "with no embed_many, update_attributes" do
82
- let(:root) { NestedChild.new(:leaf => leaf) }
83
-
84
- it "calls the root document's _strict_update_attributes with a full attribute path and not safe" do
85
- root.should_receive(:_strict_update_attributes).with({'leaf.data' => data}, false, 'leaf._id' => leaf_id)
86
- leaf.update_attributes(:data => data, :__strict__ => true)
87
- end
88
-
89
- it "(with bang!) calls the root document's _naive_update_attributes with a full attribute path and safe" do
90
- root.should_receive(:_strict_update_attributes).with({'leaf.data' => data}, true, 'leaf._id' => leaf_id)
91
- leaf.update_attributes!(:data => data, :__strict__ => true)
92
- end
93
- end
94
-
95
- context "with embed_many, update_attributes" do
96
- let(:root) { NestedDocsRoot.new(:nested_children => [NestedChild.new(:leaf => leaf)]) }
97
-
98
- it "calls the root document's _naive_update_attributes with a full attribute path and not safe" do
99
- root.should_receive(:_strict_update_attributes).with({'nested_children.0.leaf.data' => data}, false, 'nested_children.0.leaf._id' => leaf_id)
100
- leaf.update_attributes(:data => data, :__strict__ => true)
101
- end
102
-
103
- it "(with bang!) calls the root document's _naive_update_attributes with a full attribute path and safe" do
104
- root.should_receive(:_strict_update_attributes).with({'nested_children.0.leaf.data' => data}, true, 'nested_children.0.leaf._id' => leaf_id)
105
- leaf.update_attributes!(:data => data, :__strict__ => true)
106
- end
107
- end
108
- end
109
73
  end
data/spec/index_spec.rb CHANGED
@@ -51,12 +51,12 @@ describe MongoDoc::Index do
51
51
  context "Compound index" do
52
52
 
53
53
  it "creates a compound index" do
54
- collection.should_receive(:create_index).with([[:first_name, Mongo::ASCENDING], [:last_name, Mongo::ASCENDING]], false)
54
+ collection.should_receive(:create_index).with(array_including([:first_name, Mongo::ASCENDING], [:last_name, Mongo::ASCENDING]), false)
55
55
  IndexTest.index(:first_name => :asc, :last_name => :asc)
56
56
  end
57
57
 
58
58
  it "creates a unique compound index" do
59
- collection.should_receive(:create_index).with([[:first_name, Mongo::ASCENDING], [:last_name, Mongo::ASCENDING]], true)
59
+ collection.should_receive(:create_index).with(array_including([:first_name, Mongo::ASCENDING], [:last_name, Mongo::ASCENDING]), true)
60
60
  IndexTest.index(:first_name => :asc, :last_name => :asc, :unique => true)
61
61
  end
62
62
  end
data/spec/spec_helper.rb CHANGED
@@ -5,6 +5,7 @@ require 'spec'
5
5
  require 'spec/autorun'
6
6
  require 'bson_matchers'
7
7
  require 'hash_matchers'
8
+ require 'array_including_argument_matcher'
8
9
  require 'document_ext'
9
10
 
10
11
  Spec::Runner.configure do |config|
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 4
8
- - 1
9
- version: 0.4.1
8
+ - 2
9
+ version: 0.4.2
10
10
  platform: ruby
11
11
  authors:
12
12
  - Les Hill
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-03-17 00:00:00 -04:00
17
+ date: 2010-03-23 00:00:00 -04:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -41,7 +41,8 @@ dependencies:
41
41
  segments:
42
42
  - 0
43
43
  - 19
44
- version: "0.19"
44
+ - 1
45
+ version: 0.19.1
45
46
  type: :runtime
46
47
  version_requirements: *id002
47
48
  - !ruby/object:Gem::Dependency
@@ -54,7 +55,8 @@ dependencies:
54
55
  segments:
55
56
  - 0
56
57
  - 19
57
- version: "0.19"
58
+ - 1
59
+ version: 0.19.1
58
60
  type: :runtime
59
61
  version_requirements: *id003
60
62
  - !ruby/object:Gem::Dependency
@@ -126,6 +128,7 @@ extra_rdoc_files:
126
128
  files:
127
129
  - .document
128
130
  - .gitignore
131
+ - HISTORY.md
129
132
  - LICENSE
130
133
  - README.textile
131
134
  - Rakefile
@@ -226,6 +229,7 @@ files:
226
229
  - perf/mongo_doc_runner.rb
227
230
  - perf/ruby_driver_runner.rb
228
231
  - script/console
232
+ - spec/array_including_argument_matcher.rb
229
233
  - spec/associations/collection_proxy_spec.rb
230
234
  - spec/associations/document_proxy_spec.rb
231
235
  - spec/associations/hash_proxy_spec.rb
@@ -287,6 +291,7 @@ signing_key:
287
291
  specification_version: 3
288
292
  summary: ODM for MongoDB
289
293
  test_files:
294
+ - spec/array_including_argument_matcher.rb
290
295
  - spec/associations/collection_proxy_spec.rb
291
296
  - spec/associations/document_proxy_spec.rb
292
297
  - spec/associations/hash_proxy_spec.rb