djsun-mongomapper 0.3.1.1 → 0.3.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (34) hide show
  1. data/History +20 -1
  2. data/Rakefile +5 -3
  3. data/VERSION +1 -1
  4. data/lib/mongomapper/associations/base.rb +3 -5
  5. data/lib/mongomapper/associations/belongs_to_polymorphic_proxy.rb +5 -3
  6. data/lib/mongomapper/associations/belongs_to_proxy.rb +4 -4
  7. data/lib/mongomapper/associations/many_documents_proxy.rb +32 -14
  8. data/lib/mongomapper/associations/proxy.rb +2 -6
  9. data/lib/mongomapper/associations.rb +38 -15
  10. data/lib/mongomapper/document.rb +165 -95
  11. data/lib/mongomapper/dynamic_finder.rb +38 -0
  12. data/lib/mongomapper/embedded_document.rb +116 -88
  13. data/lib/mongomapper/finder_options.rb +3 -14
  14. data/lib/mongomapper/key.rb +12 -16
  15. data/lib/mongomapper/serializers/json_serializer.rb +15 -12
  16. data/lib/mongomapper/support.rb +30 -0
  17. data/lib/mongomapper.rb +7 -33
  18. data/mongomapper.gemspec +10 -7
  19. data/test/functional/associations/test_belongs_to_polymorphic_proxy.rb +14 -0
  20. data/test/functional/associations/test_belongs_to_proxy.rb +10 -0
  21. data/test/functional/associations/test_many_polymorphic_proxy.rb +46 -52
  22. data/test/functional/associations/test_many_proxy.rb +71 -12
  23. data/test/functional/test_associations.rb +9 -2
  24. data/test/functional/test_document.rb +281 -20
  25. data/test/functional/test_rails_compatibility.rb +2 -3
  26. data/test/models.rb +39 -8
  27. data/test/unit/serializers/test_json_serializer.rb +46 -12
  28. data/test/unit/test_association_base.rb +10 -2
  29. data/test/unit/test_document.rb +7 -9
  30. data/test/unit/test_embedded_document.rb +180 -24
  31. data/test/unit/test_finder_options.rb +7 -38
  32. data/test/unit/test_key.rb +54 -24
  33. metadata +5 -5
  34. data/test/unit/test_mongo_id.rb +0 -35
@@ -1,36 +1,36 @@
1
1
  require 'observer'
2
2
 
3
3
  module MongoMapper
4
- module EmbeddedDocument
4
+ module EmbeddedDocument
5
5
  def self.included(model)
6
6
  model.class_eval do
7
7
  extend ClassMethods
8
8
  include InstanceMethods
9
-
9
+
10
10
  extend Associations::ClassMethods
11
11
  include Associations::InstanceMethods
12
-
12
+
13
13
  include RailsCompatibility::EmbeddedDocument
14
14
  include Validatable
15
15
  include Serialization
16
16
 
17
- key :_id, MongoID
17
+ key :_id, String
18
18
  end
19
19
  end
20
-
20
+
21
21
  module ClassMethods
22
22
  def inherited(subclass)
23
23
  unless subclass.embeddable?
24
24
  subclass.collection(self.collection.name)
25
25
  end
26
-
26
+
27
27
  (@subclasses ||= []) << subclass
28
28
  end
29
-
29
+
30
30
  def subclasses
31
31
  @subclasses
32
32
  end
33
-
33
+
34
34
  def keys
35
35
  @keys ||= if parent = parent_model
36
36
  parent.keys.dup
@@ -38,90 +38,104 @@ module MongoMapper
38
38
  HashWithIndifferentAccess.new
39
39
  end
40
40
  end
41
-
42
- def key(name, type, options={})
43
- key = Key.new(name, type, options)
44
- keys[key.name] = key
45
-
46
- create_accessors_for(key)
47
- add_to_subclasses(name, type, options)
48
- apply_validations_for(key)
49
- create_indexes_for(key)
50
-
51
- key
52
- end
53
-
54
- def create_accessors_for(key)
55
- define_method(key.name) do
56
- read_attribute(key.name)
57
- end
58
-
59
- define_method("#{key.name}_before_typecast") do
60
- read_attribute_before_typecast(key.name)
61
- end
62
-
63
- define_method("#{key.name}=") do |value|
64
- write_attribute(key.name, value)
65
- end
41
+
42
+ def key(*args)
43
+ key = Key.new(*args)
66
44
 
67
- define_method("#{key.name}?") do
68
- read_attribute(key.name).present?
45
+ if keys[key.name].blank?
46
+ keys[key.name] = key
47
+
48
+ create_accessors_for(key)
49
+ add_to_subclasses(*args)
50
+ apply_validations_for(key)
51
+ create_indexes_for(key)
52
+
53
+ key
69
54
  end
70
55
  end
71
-
72
- def add_to_subclasses(name, type, options)
56
+
57
+ def add_to_subclasses(*args)
73
58
  return if subclasses.blank?
74
-
59
+
75
60
  subclasses.each do |subclass|
76
- subclass.key name, type, options
61
+ subclass.key(*args)
77
62
  end
78
63
  end
79
-
64
+
80
65
  def ensure_index(name_or_array, options={})
81
66
  keys_to_index = if name_or_array.is_a?(Array)
82
67
  name_or_array.map { |pair| [pair[0], pair[1]] }
83
68
  else
84
69
  name_or_array
85
70
  end
86
-
71
+
87
72
  collection.create_index(keys_to_index, options.delete(:unique))
88
73
  end
89
-
74
+
90
75
  def embeddable?
91
76
  !self.ancestors.include?(Document)
92
77
  end
93
-
78
+
94
79
  def parent_model
95
- if parent = ancestors[1]
96
- parent if parent.ancestors.include?(EmbeddedDocument)
80
+ (ancestors - [self,EmbeddedDocument]).find do |parent_class|
81
+ parent_class.ancestors.include?(EmbeddedDocument)
97
82
  end
98
83
  end
99
-
84
+
100
85
  private
86
+ def accessors_module
87
+ if const_defined?('MongoMapperKeys') && constants.include?( 'MongoMapperKeys' )
88
+ const_get 'MongoMapperKeys'
89
+ else
90
+ const_set 'MongoMapperKeys', Module.new
91
+ end
92
+ end
93
+
94
+ def create_accessors_for(key)
95
+ accessors_module.module_eval <<-end_eval
96
+ def #{key.name}
97
+ read_attribute( :'#{key.name}' )
98
+ end
99
+
100
+ def #{key.name}_before_typecast
101
+ read_attribute_before_typecast(:'#{key.name}')
102
+ end
103
+
104
+ def #{key.name}=(value)
105
+ write_attribute(:'#{key.name}', value)
106
+ end
107
+
108
+ def #{key.name}?
109
+ read_attribute(:#{key.name}).present?
110
+ end
111
+ end_eval
112
+ include accessors_module
113
+ end
114
+
101
115
  def create_indexes_for(key)
102
116
  ensure_index key.name if key.options[:index]
103
117
  end
104
-
118
+
105
119
  def apply_validations_for(key)
106
120
  attribute = key.name.to_sym
107
-
121
+
108
122
  if key.options[:required]
109
123
  validates_presence_of(attribute)
110
124
  end
111
-
125
+
112
126
  if key.options[:unique]
113
127
  validates_uniqueness_of(attribute)
114
128
  end
115
-
129
+
116
130
  if key.options[:numeric]
117
131
  number_options = key.type == Integer ? {:only_integer => true} : {}
118
132
  validates_numericality_of(attribute, number_options)
119
133
  end
120
-
134
+
121
135
  if key.options[:format]
122
136
  validates_format_of(attribute, :with => key.options[:format])
123
137
  end
124
-
138
+
125
139
  if key.options[:length]
126
140
  length_options = case key.options[:length]
127
141
  when Integer
@@ -135,7 +149,7 @@ module MongoMapper
135
149
  end
136
150
  end
137
151
  end
138
-
152
+
139
153
  module InstanceMethods
140
154
  def initialize(attrs={})
141
155
  unless attrs.nil?
@@ -144,90 +158,104 @@ module MongoMapper
144
158
  send("#{association.name}=", collection)
145
159
  end
146
160
  end
147
-
161
+
148
162
  self.attributes = attrs
149
163
  end
150
-
164
+
151
165
  if self.class.embeddable? && read_attribute(:_id).blank?
152
- write_attribute :_id, XGen::Mongo::Driver::ObjectID.new
166
+ write_attribute :_id, XGen::Mongo::Driver::ObjectID.new.to_s
153
167
  end
154
168
  end
155
-
169
+
156
170
  def attributes=(attrs)
157
171
  return if attrs.blank?
158
- attrs.each_pair do |method, value|
159
- self.send("#{method}=", value)
172
+ attrs.each_pair do |name, value|
173
+ writer_method = "#{name}="
174
+
175
+ if respond_to?(writer_method)
176
+ self.send(writer_method, value)
177
+ else
178
+ self[name.to_s] = value
179
+ end
160
180
  end
161
181
  end
162
-
182
+
163
183
  def attributes
164
- returning HashWithIndifferentAccess.new do |attributes|
165
- self.class.keys.each_pair do |name, key|
166
- value = value_for_key(key)
167
- attributes[name] = value unless value.nil?
168
- end
184
+ attrs = HashWithIndifferentAccess.new
185
+ self.class.keys.each_pair do |name, key|
186
+ value =
187
+ if key.native?
188
+ read_attribute(key.name)
189
+ else
190
+ if embedded_document = read_attribute(key.name)
191
+ embedded_document.attributes
192
+ end
193
+ end
169
194
 
170
- attributes.merge!(embedded_association_attributes)
195
+ attrs[name] = value unless value.nil?
171
196
  end
197
+ attrs.merge!(embedded_association_attributes)
172
198
  end
173
-
199
+
174
200
  def [](name)
175
201
  read_attribute(name)
176
202
  end
177
-
203
+
178
204
  def []=(name, value)
205
+ ensure_key_exists(name)
179
206
  write_attribute(name, value)
180
207
  end
181
-
208
+
182
209
  def ==(other)
183
210
  other.is_a?(self.class) && id == other.id
184
211
  end
185
-
212
+
186
213
  def id
187
- self._id.to_s
214
+ read_attribute(:_id)
188
215
  end
189
-
216
+
190
217
  def id=(value)
191
- self._id = value
218
+ @using_custom_id = true
219
+ write_attribute :_id, value
192
220
  end
193
221
 
222
+ def using_custom_id?
223
+ !!@using_custom_id
224
+ end
225
+
194
226
  def inspect
195
227
  attributes_as_nice_string = self.class.keys.keys.collect do |name|
196
228
  "#{name}: #{read_attribute(name)}"
197
229
  end.join(", ")
198
230
  "#<#{self.class} #{attributes_as_nice_string}>"
199
231
  end
200
-
232
+
201
233
  private
202
- def value_for_key(key)
203
- if key.native?
204
- read_attribute(key.name)
205
- else
206
- embedded_document = read_attribute(key.name)
207
- embedded_document && embedded_document.attributes
208
- end
234
+ def ensure_key_exists(name)
235
+ self.class.key(name) unless respond_to?("#{name}=")
209
236
  end
210
-
237
+
211
238
  def read_attribute(name)
212
- val = self.class.keys[name].get(instance_variable_get("@#{name}"))
213
- instance_variable_set "@#{name}", val
239
+ value = self.class.keys[name].get(instance_variable_get("@#{name}"))
240
+ instance_variable_set "@#{name}", value if !frozen?
241
+ value
214
242
  end
215
-
243
+
216
244
  def read_attribute_before_typecast(name)
217
245
  instance_variable_get("@#{name}_before_typecast")
218
246
  end
219
-
247
+
220
248
  def write_attribute(name, value)
221
249
  instance_variable_set "@#{name}_before_typecast", value
222
250
  instance_variable_set "@#{name}", self.class.keys[name].set(value)
223
251
  end
224
-
252
+
225
253
  def embedded_association_attributes
226
254
  returning HashWithIndifferentAccess.new do |attrs|
227
255
  self.class.associations.each_pair do |name, association|
228
256
  next unless association.embeddable?
229
257
  next unless documents = instance_variable_get(association.ivar)
230
-
258
+
231
259
  attrs[name] = documents.collect { |doc| doc.attributes }
232
260
  end
233
261
  end
@@ -7,26 +7,15 @@ module MongoMapper
7
7
  conditions.each_pair do |field, value|
8
8
  case value
9
9
  when Array
10
- operator_present = field.to_s =~ /^\$/
11
-
12
- dealing_with_ids = field.to_s == '_id' ||
13
- (parent_key && parent_key.to_s == '_id')
14
-
15
- criteria[field] = if dealing_with_ids
16
- ids = value.map { |id| MongoID.mm_typecast(id) }
17
- operator_present ? ids : {'$in' => ids}
18
- elsif operator_present
10
+ operator_present = field.to_s =~ /^\$/
11
+ criteria[field] = if operator_present
19
12
  value
20
13
  else
21
14
  {'$in' => value}
22
15
  end
23
16
  when Hash
24
17
  criteria[field] = to_mongo_criteria(value, field)
25
- else
26
- if field.to_s == '_id'
27
- value = MongoID.mm_typecast(value)
28
- end
29
-
18
+ else
30
19
  criteria[field] = value
31
20
  end
32
21
  end
@@ -1,12 +1,13 @@
1
1
  module MongoMapper
2
2
  class Key
3
3
  # DateTime and Date are currently not supported by mongo's bson so just use Time
4
- NativeTypes = [String, Float, Time, Integer, Boolean, Array, Hash, MongoID]
4
+ NativeTypes = [String, Float, Time, Integer, Boolean, Array, Hash]
5
5
 
6
6
  attr_accessor :name, :type, :options, :default_value
7
-
8
- def initialize(name, type, options={})
9
- @name, @type = name.to_s, type
7
+
8
+ def initialize(*args)
9
+ options = args.extract_options!
10
+ @name, @type = args.shift.to_s, args.shift
10
11
  self.options = (options || {}).symbolize_keys
11
12
  self.default_value = self.options.delete(:default)
12
13
  end
@@ -20,11 +21,11 @@ module MongoMapper
20
21
  end
21
22
 
22
23
  def native?
23
- @native ||= NativeTypes.include?(type)
24
+ @native ||= NativeTypes.include?(type) || type.nil?
24
25
  end
25
26
 
26
27
  def embedded_document?
27
- type.ancestors.include?(EmbeddedDocument) && !type.ancestors.include?(Document)
28
+ type.respond_to?(:embeddable?) && type.embeddable?
28
29
  end
29
30
 
30
31
  def get(value)
@@ -40,26 +41,21 @@ module MongoMapper
40
41
 
41
42
  private
42
43
  def typecast(value)
44
+ return value if type.nil?
43
45
  return HashWithIndifferentAccess.new(value) if value.is_a?(Hash) && type == Hash
46
+ return value.utc if type == Time && value.kind_of?(type)
44
47
  return value if value.kind_of?(type) || value.nil?
45
48
  begin
46
49
  if type == String then value.to_s
47
50
  elsif type == Float then value.to_f
48
51
  elsif type == Array then value.to_a
49
- elsif type == Time then Time.parse(value.to_s)
50
- elsif type == MongoID then MongoID.mm_typecast(value)
51
- #elsif type == Date then Date.parse(value.to_s)
52
+ elsif type == Time then Time.parse(value.to_s).utc
52
53
  elsif type == Boolean then Boolean.mm_typecast(value)
53
54
  elsif type == Integer
54
55
  # ganked from datamapper
55
56
  value_to_i = value.to_i
56
- if value_to_i == 0 && value != '0'
57
- value_to_s = value.to_s
58
- begin
59
- Integer(value_to_s =~ /^(\d+)/ ? $1 : value_to_s)
60
- rescue ArgumentError
61
- nil
62
- end
57
+ if value_to_i == 0
58
+ value.to_s =~ /^(0x|0b)?0+/ ? 0 : nil
63
59
  else
64
60
  value_to_i
65
61
  end
@@ -50,18 +50,8 @@ module MongoMapper #:nodoc:
50
50
  # "created_at": "2006/08/01", "awesome": true,
51
51
  # "permalink": "1-konata-izumi"}
52
52
  def to_json(options = {})
53
- unless options[:only]
54
- o = options[:methods]
55
- if o && o.is_a?(Array)
56
- o << :id
57
- elsif o
58
- o = [o, :id]
59
- else
60
- o = :id
61
- end
62
- options[:methods] = o
63
- end
64
- options.reverse_merge!(:except => :_id)
53
+ apply_to_json_defaults(options)
54
+
65
55
  if include_root_in_json
66
56
  "{#{self.class.json_class_name}: #{JsonSerializer.new(self, options).to_s}}"
67
57
  else
@@ -85,5 +75,18 @@ module MongoMapper #:nodoc:
85
75
  @json_class_name ||= name.demodulize.underscore.inspect
86
76
  end
87
77
  end
78
+
79
+ private
80
+ def apply_to_json_defaults(options)
81
+ unless options[:only]
82
+ methods = [options.delete(:methods)].flatten.compact
83
+ methods << :id
84
+ options[:methods] = methods.uniq
85
+ end
86
+
87
+ except = [options.delete(:except)].flatten.compact
88
+ except << :_id
89
+ options[:except] = except
90
+ end
88
91
  end
89
92
  end
@@ -0,0 +1,30 @@
1
+ class BasicObject #:nodoc:
2
+ instance_methods.each { |m| undef_method m unless m =~ /(^__|^nil\?$|^send$|instance_eval|proxy_|^object_id$)/ }
3
+ end unless defined?(BasicObject)
4
+
5
+ class Boolean
6
+ def self.mm_typecast(value)
7
+ ['true', 't', '1'].include?(value.to_s.downcase)
8
+ end
9
+ end
10
+
11
+ class Object
12
+ # The hidden singleton lurks behind everyone
13
+ def metaclass
14
+ class << self; self end
15
+ end
16
+
17
+ def meta_eval(&blk)
18
+ metaclass.instance_eval(&blk)
19
+ end
20
+
21
+ # Adds methods to a metaclass
22
+ def meta_def(name, &blk)
23
+ meta_eval { define_method(name, &blk) }
24
+ end
25
+
26
+ # Defines an instance method within a class
27
+ def class_def(name, &blk)
28
+ class_eval { define_method(name, &blk) }
29
+ end
30
+ end
data/lib/mongomapper.rb CHANGED
@@ -2,43 +2,17 @@ require 'pathname'
2
2
  require 'rubygems'
3
3
 
4
4
  gem 'activesupport'
5
- gem 'mongodb-mongo', '0.10.1'
5
+ gem 'mongodb-mongo', '0.11.1'
6
6
  gem 'jnunemaker-validatable', '1.7.2'
7
7
 
8
8
  require 'activesupport'
9
9
  require 'mongo'
10
10
  require 'validatable'
11
11
 
12
- class BasicObject #:nodoc:
13
- instance_methods.each { |m| undef_method m unless m =~ /^__|instance_eval/ }
14
- end unless defined?(BasicObject)
15
-
16
- class Boolean
17
- def self.mm_typecast(value)
18
- ['true', 't', '1'].include?(value.to_s.downcase)
19
- end
20
- end
21
-
22
- class MongoID < XGen::Mongo::Driver::ObjectID
23
- def self.mm_typecast(value)
24
- begin
25
- if value.is_a?(XGen::Mongo::Driver::ObjectID)
26
- value
27
- else
28
- XGen::Mongo::Driver::ObjectID::from_string(value.to_s)
29
- end
30
- rescue => exception
31
- if exception.message == 'illegal ObjectID format'
32
- raise MongoMapper::IllegalID
33
- else
34
- raise exception
35
- end
36
- end
37
- end
38
- end
39
-
40
12
  dir = Pathname(__FILE__).dirname.expand_path + 'mongomapper'
41
13
 
14
+ require dir + 'support'
15
+
42
16
  require dir + 'associations'
43
17
  require dir + 'associations/base'
44
18
 
@@ -54,6 +28,7 @@ require dir + 'associations/many_embedded_polymorphic_proxy'
54
28
 
55
29
  require dir + 'callbacks'
56
30
  require dir + 'finder_options'
31
+ require dir + 'dynamic_finder'
57
32
  require dir + 'key'
58
33
  require dir + 'observing'
59
34
  require dir + 'pagination'
@@ -68,16 +43,15 @@ require dir + 'embedded_document'
68
43
  require dir + 'document'
69
44
 
70
45
  module MongoMapper
71
- DocumentNotFound = Class.new(StandardError)
72
- IllegalID = Class.new(StandardError)
46
+ DocumentNotFound = Class.new(StandardError)
73
47
 
74
- DocumentNotValid = Class.new(StandardError) do
48
+ DocumentNotValid = Class.new(StandardError) do
75
49
  def initialize(document)
76
50
  @document = document
77
51
  super("Validation failed: #{@document.errors.full_messages.join(", ")}")
78
52
  end
79
53
  end
80
-
54
+
81
55
  def self.connection
82
56
  @@connection ||= XGen::Mongo::Driver::Mongo.new
83
57
  end
data/mongomapper.gemspec CHANGED
@@ -1,12 +1,15 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`
1
4
  # -*- encoding: utf-8 -*-
2
5
 
3
6
  Gem::Specification.new do |s|
4
7
  s.name = %q{mongomapper}
5
- s.version = "0.3.1.1"
8
+ s.version = "0.3.3"
6
9
 
7
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
11
  s.authors = ["John Nunemaker"]
9
- s.date = %q{2009-08-06}
12
+ s.date = %q{2009-08-16}
10
13
  s.default_executable = %q{mmconsole}
11
14
  s.email = %q{nunemaker@gmail.com}
12
15
  s.executables = ["mmconsole"]
@@ -35,6 +38,7 @@ Gem::Specification.new do |s|
35
38
  "lib/mongomapper/associations/proxy.rb",
36
39
  "lib/mongomapper/callbacks.rb",
37
40
  "lib/mongomapper/document.rb",
41
+ "lib/mongomapper/dynamic_finder.rb",
38
42
  "lib/mongomapper/embedded_document.rb",
39
43
  "lib/mongomapper/finder_options.rb",
40
44
  "lib/mongomapper/key.rb",
@@ -45,6 +49,7 @@ Gem::Specification.new do |s|
45
49
  "lib/mongomapper/save_with_validation.rb",
46
50
  "lib/mongomapper/serialization.rb",
47
51
  "lib/mongomapper/serializers/json_serializer.rb",
52
+ "lib/mongomapper/support.rb",
48
53
  "lib/mongomapper/validations.rb",
49
54
  "mongomapper.gemspec",
50
55
  "test/NOTE_ON_TESTING",
@@ -68,7 +73,6 @@ Gem::Specification.new do |s|
68
73
  "test/unit/test_embedded_document.rb",
69
74
  "test/unit/test_finder_options.rb",
70
75
  "test/unit/test_key.rb",
71
- "test/unit/test_mongo_id.rb",
72
76
  "test/unit/test_mongomapper.rb",
73
77
  "test/unit/test_observing.rb",
74
78
  "test/unit/test_pagination.rb",
@@ -103,7 +107,6 @@ Gem::Specification.new do |s|
103
107
  "test/unit/test_embedded_document.rb",
104
108
  "test/unit/test_finder_options.rb",
105
109
  "test/unit/test_key.rb",
106
- "test/unit/test_mongo_id.rb",
107
110
  "test/unit/test_mongomapper.rb",
108
111
  "test/unit/test_observing.rb",
109
112
  "test/unit/test_pagination.rb",
@@ -118,20 +121,20 @@ Gem::Specification.new do |s|
118
121
 
119
122
  if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
120
123
  s.add_runtime_dependency(%q<activesupport>, [">= 0"])
121
- s.add_runtime_dependency(%q<mongodb-mongo>, ["= 0.10.1"])
124
+ s.add_runtime_dependency(%q<mongodb-mongo>, ["= 0.11.1"])
122
125
  s.add_runtime_dependency(%q<jnunemaker-validatable>, ["= 1.7.2"])
123
126
  s.add_development_dependency(%q<mocha>, ["= 0.9.4"])
124
127
  s.add_development_dependency(%q<jnunemaker-matchy>, ["= 0.4.0"])
125
128
  else
126
129
  s.add_dependency(%q<activesupport>, [">= 0"])
127
- s.add_dependency(%q<mongodb-mongo>, ["= 0.10.1"])
130
+ s.add_dependency(%q<mongodb-mongo>, ["= 0.11.1"])
128
131
  s.add_dependency(%q<jnunemaker-validatable>, ["= 1.7.2"])
129
132
  s.add_dependency(%q<mocha>, ["= 0.9.4"])
130
133
  s.add_dependency(%q<jnunemaker-matchy>, ["= 0.4.0"])
131
134
  end
132
135
  else
133
136
  s.add_dependency(%q<activesupport>, [">= 0"])
134
- s.add_dependency(%q<mongodb-mongo>, ["= 0.10.1"])
137
+ s.add_dependency(%q<mongodb-mongo>, ["= 0.11.1"])
135
138
  s.add_dependency(%q<jnunemaker-validatable>, ["= 1.7.2"])
136
139
  s.add_dependency(%q<mocha>, ["= 0.9.4"])
137
140
  s.add_dependency(%q<jnunemaker-matchy>, ["= 0.4.0"])
@@ -36,4 +36,18 @@ class BelongsToPolymorphicProxyTest < Test::Unit::TestCase
36
36
  from_db.target_id.should be_nil
37
37
  from_db.target.should be_nil
38
38
  end
39
+
40
+ context "association id set but document not found" do
41
+ setup do
42
+ @status = Status.new
43
+ project = Project.new(:name => "mongomapper")
44
+ @status.target = project
45
+ @status.save.should be_true
46
+ project.destroy
47
+ end
48
+
49
+ should "return nil instead of raising error" do
50
+ @status.target.should be_nil
51
+ end
52
+ end
39
53
  end
@@ -32,4 +32,14 @@ class BelongsToProxyTest < Test::Unit::TestCase
32
32
  from_db.project = nil
33
33
  from_db.project.should be_nil
34
34
  end
35
+
36
+ context "association id set but document not found" do
37
+ setup do
38
+ @status = Status.new(:name => 'Foo', :project_id => '1234')
39
+ end
40
+
41
+ should "return nil instead of raising error" do
42
+ @status.project.should be_nil
43
+ end
44
+ end
35
45
  end