mongodoc 0.2.1 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
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