mongodoc 0.2.1 → 0.2.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.
Files changed (44) hide show
  1. data/README.textile +42 -12
  2. data/Rakefile +4 -4
  3. data/TODO +26 -0
  4. data/VERSION +1 -1
  5. data/examples/simple_document.rb +1 -1
  6. data/examples/simple_object.rb +0 -2
  7. data/features/mongodb.yml +6 -5
  8. data/features/removing_documents.feature +68 -0
  9. data/features/step_definitions/collection_steps.rb +3 -3
  10. data/features/step_definitions/document_steps.rb +2 -2
  11. data/features/step_definitions/removing_documents_steps.rb +14 -0
  12. data/features/support/support.rb +2 -2
  13. data/lib/mongodoc.rb +4 -7
  14. data/lib/mongodoc/associations/collection_proxy.rb +103 -0
  15. data/lib/mongodoc/associations/document_proxy.rb +53 -0
  16. data/lib/mongodoc/associations/hash_proxy.rb +96 -0
  17. data/lib/mongodoc/associations/proxy_base.rb +51 -0
  18. data/lib/mongodoc/attributes.rb +49 -17
  19. data/lib/mongodoc/collection.rb +15 -5
  20. data/lib/mongodoc/connection.rb +83 -20
  21. data/lib/mongodoc/criteria.rb +9 -4
  22. data/lib/mongodoc/cursor.rb +9 -3
  23. data/lib/mongodoc/document.rb +37 -24
  24. data/lib/mongodoc/validations/macros.rb +11 -0
  25. data/lib/mongodoc/validations/validates_embedded.rb +13 -0
  26. data/mongodb.example.yml +13 -5
  27. data/mongodoc.gemspec +33 -23
  28. data/spec/associations/collection_proxy_spec.rb +200 -0
  29. data/spec/associations/document_proxy_spec.rb +42 -0
  30. data/spec/associations/hash_proxy_spec.rb +163 -0
  31. data/spec/attributes_spec.rb +113 -47
  32. data/spec/bson_spec.rb +24 -24
  33. data/spec/collection_spec.rb +67 -86
  34. data/spec/connection_spec.rb +98 -150
  35. data/spec/criteria_spec.rb +4 -3
  36. data/spec/cursor_spec.rb +33 -27
  37. data/spec/document_spec.rb +173 -156
  38. data/spec/embedded_save_spec.rb +8 -3
  39. data/spec/new_record_spec.rb +33 -121
  40. metadata +80 -39
  41. data/lib/mongodoc/parent_proxy.rb +0 -44
  42. data/lib/mongodoc/proxy.rb +0 -83
  43. data/spec/parent_proxy_spec.rb +0 -44
  44. data/spec/proxy_spec.rb +0 -80
@@ -2,13 +2,19 @@ module MongoDoc
2
2
  class Cursor
3
3
  include Enumerable
4
4
 
5
- attr_accessor :_cursor
6
- delegate :close, :closed?, :count, :explain, :limit, :query_options_hash, :query_opts, :skip, :sort, :to => :_cursor
5
+ attr_accessor :_collection, :_cursor
7
6
 
8
- def initialize(cursor)
7
+ delegate :admin, :close, :closed?, :count, :explain, :fields, :full_collection_name, :hint, :limit, :order, :query_options_hash, :query_opts, :selector, :skip, :snapshot, :sort, :timeout, :to => :_cursor
8
+
9
+ def initialize(mongodoc_collection, cursor)
10
+ self._collection = mongodoc_collection
9
11
  self._cursor = cursor
10
12
  end
11
13
 
14
+ def collection
15
+ _collection
16
+ end
17
+
12
18
  def each
13
19
  _cursor.each do |next_document|
14
20
  yield MongoDoc::BSON.decode(next_document)
@@ -4,8 +4,10 @@ require 'mongodoc/attributes'
4
4
  require 'mongodoc/criteria'
5
5
  require 'mongodoc/finders'
6
6
  require 'mongodoc/named_scope'
7
+ require 'mongodoc/validations/macros'
7
8
 
8
9
  module MongoDoc
10
+ class UnsupportedOperation < RuntimeError; end
9
11
  class DocumentInvalidError < RuntimeError; end
10
12
  class NotADocumentError < RuntimeError; end
11
13
 
@@ -17,10 +19,10 @@ module MongoDoc
17
19
  extend ClassMethods
18
20
  extend Finders
19
21
  extend NamedScope
20
- include Validatable
22
+ include ::Validatable
23
+ extend Validations::Macros
21
24
 
22
25
  alias :id :_id
23
- alias :to_param :_id
24
26
  end
25
27
  end
26
28
 
@@ -34,10 +36,11 @@ module MongoDoc
34
36
  end
35
37
 
36
38
  def attributes
37
- self.class._attributes.inject({}) do |hash, attr|
39
+ hash = {}
40
+ self.class._attributes.each do |attr|
38
41
  hash[attr] = send(attr)
39
- hash
40
42
  end
43
+ hash
41
44
  end
42
45
 
43
46
  def attributes=(attrs)
@@ -50,6 +53,16 @@ module MongoDoc
50
53
  _id.nil?
51
54
  end
52
55
 
56
+ def remove
57
+ raise UnsupportedOperation.new('Document#remove is not supported for embedded documents') if _root
58
+ remove_document
59
+ end
60
+
61
+ def remove_document
62
+ return _root.remove_document if _root
63
+ _remove
64
+ end
65
+
53
66
  def save(validate = true)
54
67
  return _root.save(validate) if _root
55
68
  return _save(false) unless validate and not valid?
@@ -64,16 +77,21 @@ module MongoDoc
64
77
 
65
78
  def to_bson(*args)
66
79
  {MongoDoc::BSON::CLASS_KEY => self.class.name}.tap do |bson_hash|
67
- bson_hash['_id'] = _id unless _id.nil?
80
+ bson_hash['_id'] = _id unless new_record?
68
81
  self.class._attributes.each do |name|
69
82
  bson_hash[name.to_s] = send(name).to_bson(args)
70
83
  end
71
84
  end
72
85
  end
73
86
 
87
+ def to_param
88
+ _id.to_s
89
+ end
90
+
74
91
  def update_attributes(attrs)
75
92
  strict = attrs.delete(:__strict__)
76
93
  self.attributes = attrs
94
+ return save if new_record?
77
95
  return false unless valid?
78
96
  if strict
79
97
  _strict_update_attributes(_path_to_root(self, attrs), false)
@@ -85,6 +103,7 @@ module MongoDoc
85
103
  def update_attributes!(attrs)
86
104
  strict = attrs.delete(:__strict__)
87
105
  self.attributes = attrs
106
+ return save! if new_record?
88
107
  raise DocumentInvalidError unless valid?
89
108
  if strict
90
109
  _strict_update_attributes(_path_to_root(self, attrs), true)
@@ -112,28 +131,15 @@ module MongoDoc
112
131
 
113
132
  def create(attrs = {})
114
133
  instance = new(attrs)
115
- _create(instance, false) if instance.valid?
134
+ instance.save(false)
116
135
  instance
117
136
  end
118
137
 
119
138
  def create!(attrs = {})
120
139
  instance = new(attrs)
121
- raise MongoDoc::DocumentInvalidError unless instance.valid?
122
- _create(instance, true)
140
+ instance.save!(true)
123
141
  instance
124
142
  end
125
-
126
- protected
127
-
128
- def _create(instance, safe)
129
- instance.send(:notify_before_save_observers)
130
- instance._id = collection.insert(instance, :safe => safe)
131
- instance.send(:notify_save_success_observers)
132
- instance._id
133
- rescue Mongo::MongoDBError => e
134
- instance.send(:notify_save_failed_observers)
135
- raise e
136
- end
137
143
  end
138
144
 
139
145
  protected
@@ -144,12 +150,20 @@ module MongoDoc
144
150
 
145
151
  def _naive_update_attributes(attrs, safe)
146
152
  return _root.send(:_naive_update_attributes, attrs, safe) if _root
147
- _collection.update({'_id' => self._id}, MongoDoc::Query.set_modifier(attrs), :safe => safe)
153
+ _update({}, attrs, safe)
154
+ end
155
+
156
+ def _remove
157
+ _collection.remove({'_id' => _id})
148
158
  end
149
159
 
150
160
  def _strict_update_attributes(attrs, safe, selector = {})
151
- return _root.send(:_strict_update_attributes, attrs, safe, _selector_path_to_root('_id' => _id)) if _root
152
- _collection.update({'_id' => _id}.merge(selector), MongoDoc::Query.set_modifier(attrs), :safe => safe)
161
+ return _root.send(:_strict_update_attributes, attrs, safe, _path_to_root(self, '_id' => _id)) if _root
162
+ _update(selector, attrs, safe)
163
+ end
164
+
165
+ def _update(selector, data, safe)
166
+ _collection.update({'_id' => _id}.merge(selector), MongoDoc::Query.set_modifier(data), :safe => safe)
153
167
  end
154
168
 
155
169
  def _save(safe)
@@ -197,6 +211,5 @@ module MongoDoc
197
211
  def notify_save_failed_observers
198
212
  save_observers.each {|obs| obs.save_failed_callback(self) }
199
213
  end
200
-
201
214
  end
202
215
  end
@@ -0,0 +1,11 @@
1
+ require 'mongodoc/validations/validates_embedded'
2
+
3
+ module MongoDoc
4
+ module Validations
5
+ module Macros
6
+ def validates_embedded(*args)
7
+ add_validations(args, MongoDoc::Validations::ValidatesEmbedded)
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,13 @@
1
+ module MongoDoc
2
+ module Validations
3
+ class ValidatesEmbedded < ::Validatable::ValidationBase
4
+ def valid?(instance)
5
+ instance.send(attribute).valid?
6
+ end
7
+
8
+ def message(instance)
9
+ super || "is invalid"
10
+ end
11
+ end
12
+ end
13
+ end
@@ -1,6 +1,14 @@
1
- name: test
2
- host: localhost
3
- port: 27017
4
- options:
5
- auto_reconnect: true
1
+ development:
2
+ name: development
3
+ host: localhost
4
+ port: 27017
5
+ options:
6
+ auto_reconnect: true
7
+
8
+ test:
9
+ name: test
10
+ host: localhost
11
+ port: 27017
12
+ options:
13
+ auto_reconnect: true
6
14
 
@@ -5,16 +5,17 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{mongodoc}
8
- s.version = "0.2.1"
8
+ s.version = "0.2.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-01-18}
12
+ s.date = %q{2010-02-16}
13
13
  s.description = %q{ODM for MongoDB}
14
14
  s.email = %q{leshill@gmail.com}
15
15
  s.extra_rdoc_files = [
16
16
  "LICENSE",
17
- "README.textile"
17
+ "README.textile",
18
+ "TODO"
18
19
  ]
19
20
  s.files = [
20
21
  ".document",
@@ -22,6 +23,7 @@ Gem::Specification.new do |s|
22
23
  "LICENSE",
23
24
  "README.textile",
24
25
  "Rakefile",
26
+ "TODO",
25
27
  "VERSION",
26
28
  "data/.gitignore",
27
29
  "examples/simple_document.rb",
@@ -32,6 +34,7 @@ Gem::Specification.new do |s|
32
34
  "features/named_scopes.feature",
33
35
  "features/new_record.feature",
34
36
  "features/partial_updates.feature",
37
+ "features/removing_documents.feature",
35
38
  "features/saving_an_object.feature",
36
39
  "features/step_definitions/collection_steps.rb",
37
40
  "features/step_definitions/criteria_steps.rb",
@@ -44,10 +47,15 @@ Gem::Specification.new do |s|
44
47
  "features/step_definitions/objects.rb",
45
48
  "features/step_definitions/partial_update_steps.rb",
46
49
  "features/step_definitions/query_steps.rb",
50
+ "features/step_definitions/removing_documents_steps.rb",
47
51
  "features/step_definitions/util_steps.rb",
48
52
  "features/support/support.rb",
49
53
  "features/using_criteria.feature",
50
54
  "lib/mongodoc.rb",
55
+ "lib/mongodoc/associations/collection_proxy.rb",
56
+ "lib/mongodoc/associations/document_proxy.rb",
57
+ "lib/mongodoc/associations/hash_proxy.rb",
58
+ "lib/mongodoc/associations/proxy_base.rb",
51
59
  "lib/mongodoc/attributes.rb",
52
60
  "lib/mongodoc/bson.rb",
53
61
  "lib/mongodoc/collection.rb",
@@ -72,15 +80,18 @@ Gem::Specification.new do |s|
72
80
  "lib/mongodoc/ext/time.rb",
73
81
  "lib/mongodoc/finders.rb",
74
82
  "lib/mongodoc/named_scope.rb",
75
- "lib/mongodoc/parent_proxy.rb",
76
- "lib/mongodoc/proxy.rb",
77
83
  "lib/mongodoc/query.rb",
84
+ "lib/mongodoc/validations/macros.rb",
85
+ "lib/mongodoc/validations/validates_embedded.rb",
78
86
  "mongod.example.yml",
79
87
  "mongodb.example.yml",
80
88
  "mongodoc.gemspec",
81
89
  "perf/mongodoc_runner.rb",
82
90
  "perf/ruby_driver_runner.rb",
83
91
  "script/console",
92
+ "spec/associations/collection_proxy_spec.rb",
93
+ "spec/associations/document_proxy_spec.rb",
94
+ "spec/associations/hash_proxy_spec.rb",
84
95
  "spec/attributes_spec.rb",
85
96
  "spec/bson_matchers.rb",
86
97
  "spec/bson_spec.rb",
@@ -97,8 +108,6 @@ Gem::Specification.new do |s|
97
108
  "spec/mongodb_pairs.yml",
98
109
  "spec/named_scope_spec.rb",
99
110
  "spec/new_record_spec.rb",
100
- "spec/parent_proxy_spec.rb",
101
- "spec/proxy_spec.rb",
102
111
  "spec/query_spec.rb",
103
112
  "spec/spec.opts",
104
113
  "spec/spec_helper.rb"
@@ -106,10 +115,13 @@ Gem::Specification.new do |s|
106
115
  s.homepage = %q{http://github.com/leshill/mongodoc}
107
116
  s.rdoc_options = ["--charset=UTF-8"]
108
117
  s.require_paths = ["lib"]
109
- s.rubygems_version = %q{1.3.5}
118
+ s.rubygems_version = %q{1.3.6.pre.3}
110
119
  s.summary = %q{ODM for MongoDB}
111
120
  s.test_files = [
112
- "spec/attributes_spec.rb",
121
+ "spec/associations/collection_proxy_spec.rb",
122
+ "spec/associations/document_proxy_spec.rb",
123
+ "spec/associations/hash_proxy_spec.rb",
124
+ "spec/attributes_spec.rb",
113
125
  "spec/bson_matchers.rb",
114
126
  "spec/bson_spec.rb",
115
127
  "spec/collection_spec.rb",
@@ -123,8 +135,6 @@ Gem::Specification.new do |s|
123
135
  "spec/hash_matchers.rb",
124
136
  "spec/named_scope_spec.rb",
125
137
  "spec/new_record_spec.rb",
126
- "spec/parent_proxy_spec.rb",
127
- "spec/proxy_spec.rb",
128
138
  "spec/query_spec.rb",
129
139
  "spec/spec_helper.rb",
130
140
  "examples/simple_document.rb",
@@ -136,27 +146,27 @@ Gem::Specification.new do |s|
136
146
  s.specification_version = 3
137
147
 
138
148
  if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
139
- s.add_runtime_dependency(%q<mongo>, ["= 0.18.2"])
140
- s.add_runtime_dependency(%q<mongo_ext>, ["= 0.18.2"])
149
+ s.add_runtime_dependency(%q<mongo>, ["= 0.18.3"])
150
+ s.add_runtime_dependency(%q<mongo_ext>, ["= 0.18.3"])
141
151
  s.add_runtime_dependency(%q<durran-validatable>, ["= 2.0.1"])
142
152
  s.add_runtime_dependency(%q<leshill-will_paginate>, ["= 2.3.11"])
143
- s.add_development_dependency(%q<rspec>, ["= 1.2.9"])
144
- s.add_development_dependency(%q<cucumber>, ["= 0.4.4"])
153
+ s.add_development_dependency(%q<rspec>, ["= 1.3.0"])
154
+ s.add_development_dependency(%q<cucumber>, ["= 0.6.2"])
145
155
  else
146
- s.add_dependency(%q<mongo>, ["= 0.18.2"])
147
- s.add_dependency(%q<mongo_ext>, ["= 0.18.2"])
156
+ s.add_dependency(%q<mongo>, ["= 0.18.3"])
157
+ s.add_dependency(%q<mongo_ext>, ["= 0.18.3"])
148
158
  s.add_dependency(%q<durran-validatable>, ["= 2.0.1"])
149
159
  s.add_dependency(%q<leshill-will_paginate>, ["= 2.3.11"])
150
- s.add_dependency(%q<rspec>, ["= 1.2.9"])
151
- s.add_dependency(%q<cucumber>, ["= 0.4.4"])
160
+ s.add_dependency(%q<rspec>, ["= 1.3.0"])
161
+ s.add_dependency(%q<cucumber>, ["= 0.6.2"])
152
162
  end
153
163
  else
154
- s.add_dependency(%q<mongo>, ["= 0.18.2"])
155
- s.add_dependency(%q<mongo_ext>, ["= 0.18.2"])
164
+ s.add_dependency(%q<mongo>, ["= 0.18.3"])
165
+ s.add_dependency(%q<mongo_ext>, ["= 0.18.3"])
156
166
  s.add_dependency(%q<durran-validatable>, ["= 2.0.1"])
157
167
  s.add_dependency(%q<leshill-will_paginate>, ["= 2.3.11"])
158
- s.add_dependency(%q<rspec>, ["= 1.2.9"])
159
- s.add_dependency(%q<cucumber>, ["= 0.4.4"])
168
+ s.add_dependency(%q<rspec>, ["= 1.3.0"])
169
+ s.add_dependency(%q<cucumber>, ["= 0.6.2"])
160
170
  end
161
171
  end
162
172
 
@@ -0,0 +1,200 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', '/spec_helper'))
2
+
3
+ describe MongoDoc::Associations::CollectionProxy do
4
+ class CollectionProxyTest
5
+ include MongoDoc::Document
6
+
7
+ key :name
8
+ end
9
+
10
+ let(:root) { stub('root', :register_save_observer => nil) }
11
+ let(:proxy) { MongoDoc::Associations::CollectionProxy.new(:assoc_name => 'has_many_name', :assoc_class => CollectionProxyTest, :root => root, :parent => root) }
12
+ let(:item) { CollectionProxyTest.new }
13
+
14
+ context "#<<" do
15
+ it "appends the item to the collection" do
16
+ (proxy << item).should include(item)
17
+ end
18
+
19
+ context "when the item is a Hash" do
20
+ let(:hash) {{:name => 'hash'}}
21
+
22
+ it "does not register a save observer" do
23
+ root.should_not_receive(:register_save_observer)
24
+ proxy << hash
25
+ end
26
+
27
+ it "does not set the root" do
28
+ hash.should_not_receive(:_root=)
29
+ proxy << hash
30
+ end
31
+
32
+ it "adds the hash to the collection" do
33
+ proxy << hash
34
+ proxy.should include(hash)
35
+ end
36
+ end
37
+
38
+ context "when the item is not a MongoDoc::Document" do
39
+ let(:other_item) {'not a doc'}
40
+
41
+ it "does not register a save observer" do
42
+ root.should_not_receive(:register_save_observer)
43
+ proxy << other_item
44
+ end
45
+
46
+ it "does not set the root" do
47
+ other_item.should_not_receive(:_root=)
48
+ proxy << other_item
49
+ end
50
+
51
+ it "adds the item to the collection" do
52
+ proxy << other_item
53
+ proxy.should include(other_item)
54
+ end
55
+ end
56
+
57
+ context "when the item is a MongoDoc::Document" do
58
+ it "registers a save observer" do
59
+ root.should_receive(:register_save_observer)
60
+ proxy << item
61
+ end
62
+
63
+ it "sets the root" do
64
+ proxy << item
65
+ item._root.should == root
66
+ end
67
+ end
68
+
69
+ context "when the item is an array" do
70
+ it "adds the array" do
71
+ array = ['something else']
72
+ proxy << array
73
+ proxy.should include(array)
74
+ end
75
+ end
76
+ end
77
+
78
+ context "#[]=" do
79
+ it "sets the item at the index" do
80
+ proxy[1] = item
81
+ proxy[1].should == item
82
+ end
83
+
84
+ context "when the item is not a MongoDoc::Document" do
85
+ let(:other_item) {'not a doc'}
86
+
87
+ it "does not register a save observer" do
88
+ root.should_not_receive(:register_save_observer)
89
+ proxy[1] = other_item
90
+ end
91
+
92
+ it "does not set the root" do
93
+ other_item.should_not_receive(:_root=)
94
+ proxy[1] = other_item
95
+ end
96
+
97
+ it "adds the item to the collection" do
98
+ proxy[1] = other_item
99
+ proxy.should include(other_item)
100
+ end
101
+ end
102
+
103
+ context "when the item is a MongoDoc::Document" do
104
+ it "registers a save observer" do
105
+ root.should_receive(:register_save_observer)
106
+ proxy[1] = item
107
+ end
108
+
109
+ it "sets the root" do
110
+ proxy[1] = item
111
+ item._root.should == root
112
+ end
113
+ end
114
+ end
115
+
116
+ context "#concat" do
117
+ it "appends the items from the array to self" do
118
+ proxy.concat([item])
119
+ proxy.should include(item)
120
+ end
121
+ end
122
+
123
+ context "#replace" do
124
+ it "clears the existing collection" do
125
+ proxy.should_receive(:clear)
126
+ proxy.replace([item])
127
+ end
128
+
129
+ it "concats the other onto self" do
130
+ other = [item]
131
+ proxy.should_receive(:concat).with(other)
132
+ proxy.replace(other)
133
+ end
134
+ end
135
+
136
+ context "#unshift" do
137
+ let(:proxy_with_item) { proxy << 'other' }
138
+
139
+ it "adds the item to the front of the collection" do
140
+ proxy_with_item.unshift(item)
141
+ proxy_with_item[0].should == item
142
+ end
143
+
144
+ context "when the item is not a MongoDoc::Document" do
145
+ let(:other_item) {'not a doc'}
146
+
147
+ it "does not register a save observer" do
148
+ root.should_not_receive(:register_save_observer)
149
+ proxy_with_item.unshift(other_item)
150
+ end
151
+
152
+ it "does not set the root" do
153
+ other_item.should_not_receive(:_root=)
154
+ proxy_with_item.unshift(other_item)
155
+ end
156
+
157
+ it "adds the item to the front of the collection" do
158
+ proxy_with_item.unshift(other_item)
159
+ proxy_with_item[0].should == other_item
160
+ end
161
+ end
162
+
163
+ context "when the item is a MongoDoc::Document" do
164
+ let(:new_item) { CollectionProxyTest.new }
165
+
166
+ it "registers a save observer" do
167
+ root.should_receive(:register_save_observer)
168
+ proxy_with_item.unshift(new_item)
169
+ end
170
+
171
+ it "sets the root" do
172
+ proxy_with_item.unshift(new_item)
173
+ new_item._root.should == root
174
+ end
175
+
176
+ it "adds the item to the front of the collection" do
177
+ proxy_with_item.unshift(new_item)
178
+ proxy_with_item[0].should == new_item
179
+ end
180
+ end
181
+ end
182
+
183
+ context "#build" do
184
+ let(:name) {'built'}
185
+
186
+ it "adds a built item to the collection" do
187
+ proxy.build({:name => name}).last.name.should == name
188
+ end
189
+
190
+ it "registers a save observer" do
191
+ root.should_receive(:register_save_observer)
192
+ proxy.build({:name => name})
193
+ end
194
+
195
+ it "sets the root" do
196
+ proxy.build({:name => name})
197
+ proxy.last._root.should == root
198
+ end
199
+ end
200
+ end