Handle unsupported types: Complex, Rational, and BigDecimal RUBY-85

This commit is contained in:
Kyle Banker 2010-01-21 14:49:20 -05:00
parent bf7ffcfa82
commit 95d9d6b4f6
3 changed files with 44 additions and 14 deletions

View File

@ -274,7 +274,7 @@ static int write_element_allow_id(VALUE key, VALUE value, VALUE extra, int allow
case T_STRING: case T_STRING:
{ {
if (strcmp(rb_class2name(RBASIC(value)->klass), if (strcmp(rb_class2name(RBASIC(value)->klass),
"Mongo::Code") == 0) { "Mongo::Code") == 0) {
buffer_position length_location, start_position, total_length; buffer_position length_location, start_position, total_length;
int length; int length;
write_name_and_type(buffer, key, 0x0F); write_name_and_type(buffer, key, 0x0F);
@ -380,10 +380,14 @@ static int write_element_allow_id(VALUE key, VALUE value, VALUE extra, int allow
break; break;
} }
if (strcmp(cls, "DateTime") == 0 || strcmp(cls, "Date") == 0 || strcmp(cls, "ActiveSupport::TimeWithZone") == 0) { if (strcmp(cls, "DateTime") == 0 || strcmp(cls, "Date") == 0 || strcmp(cls, "ActiveSupport::TimeWithZone") == 0) {
buffer_free(buffer); buffer_free(buffer);
rb_raise(InvalidDocument, rb_raise(InvalidDocument, "%s is not currently supported; use a UTC Time instance instead.", cls);
"Trying to serialize and instance of Date, DateTime, or TimeWithZone; the MongoDB Ruby driver currently supports Time objects only.", break;
TYPE(value)); }
if(strcmp(cls, "Complex") == 0 || strcmp(cls, "Rational") == 0 || strcmp(cls, "BigDecimal") == 0) {
buffer_free(buffer);
rb_raise(InvalidDocument, "The Numeric type %s cannot be encoded as BSON; only Bignum, Fixnum, and Float are supported.", cls);
break;
} }
buffer_free(buffer); buffer_free(buffer);
rb_raise(InvalidDocument, "Cannot serialize an object of class %s into BSON.", cls); rb_raise(InvalidDocument, "Cannot serialize an object of class %s into BSON.", cls);
@ -391,7 +395,6 @@ static int write_element_allow_id(VALUE key, VALUE value, VALUE extra, int allow
} }
case T_DATA: case T_DATA:
{ {
// TODO again, is this really the only way to do this?
const char* cls = rb_class2name(RBASIC(value)->klass); const char* cls = rb_class2name(RBASIC(value)->klass);
if (strcmp(cls, "Time") == 0) { if (strcmp(cls, "Time") == 0) {
double t = NUM2DBL(rb_funcall(value, rb_intern("to_f"), 0)); double t = NUM2DBL(rb_funcall(value, rb_intern("to_f"), 0));
@ -400,6 +403,14 @@ static int write_element_allow_id(VALUE key, VALUE value, VALUE extra, int allow
SAFE_WRITE(buffer, (const char*)&time_since_epoch, 8); SAFE_WRITE(buffer, (const char*)&time_since_epoch, 8);
break; break;
} }
if(strcmp(cls, "BigDecimal") == 0) {
buffer_free(buffer);
rb_raise(InvalidDocument, "The Numeric type %s cannot be encoded as BSON; only Bignum, Fixnum, and Float are supported.", cls);
break;
}
buffer_free(buffer);
rb_raise(InvalidDocument, "Cannot serialize an object of class %s into BSON.", cls);
break;
} }
case T_REGEXP: case T_REGEXP:
{ {
@ -441,7 +452,7 @@ static int write_element_allow_id(VALUE key, VALUE value, VALUE extra, int allow
{ {
const char* cls = rb_class2name(RBASIC(value)->klass); const char* cls = rb_class2name(RBASIC(value)->klass);
buffer_free(buffer); buffer_free(buffer);
rb_raise(InvalidDocument, "Cannot serialize an object of class %s into BSON.", cls); rb_raise(InvalidDocument, "Cannot serialize an object of class %s (type %d) into BSON.", cls, TYPE(value));
break; break;
} }
} }

View File

@ -549,7 +549,7 @@ class BSON_RUBY
NULL NULL
when Integer when Integer
NUMBER_INT NUMBER_INT
when Numeric when Float
NUMBER NUMBER
when ByteBuffer when ByteBuffer
BINARY BINARY
@ -577,15 +577,17 @@ class BSON_RUBY
MAXKEY MAXKEY
when MinKey when MinKey
MINKEY MINKEY
when Numeric
raise InvalidDocument, "The Numeric type #{o.class} cannot be encoded as BSON; only Fixum, Bignum, and Float are supported."
when Date, DateTime when Date, DateTime
raise InvalidDocument, "Trying to serialize an instance of #{o.class}; " + raise InvalidDocument, "#{o.class} is not currently supported; " +
"the MongoDB Ruby driver currently supports Time objects only." "use a UTC Time instance instead."
else else
if defined?(ActiveSupport::TimeWithZone) && o.is_a?(ActiveSupport::TimeWithZone) if defined?(ActiveSupport::TimeWithZone) && o.is_a?(ActiveSupport::TimeWithZone)
raise InvalidDocument, "Trying to serialize an instance of ActiveSupport::TimeWithZone; " + raise InvalidDocument, "ActiveSupport::TimeWithZone is not currently supported; " +
"the MongoDB Ruby driver currently supports Time objects only." "use a UTC Time instance instead."
else else
raise InvalidDocument, "Unknown type of object: #{o.class.name}" raise InvalidDocument, "#{o.class} isn't supported as a BSON type."
end end
end end
end end

View File

@ -1,5 +1,8 @@
# encoding:utf-8 # encoding:utf-8
require 'test/test_helper' require 'test/test_helper'
require 'complex'
require 'bigdecimal'
require 'rational'
# Need to simulating this class # Need to simulating this class
# without actually loading it. # without actually loading it.
@ -197,7 +200,7 @@ class BSONTest < Test::Unit::TestCase
ensure ensure
puts e.message puts e.message
assert_equal InvalidDocument, e.class assert_equal InvalidDocument, e.class
assert_match /Time objects only/, e.message assert_match /UTC Time/, e.message
end end
end end
end end
@ -314,6 +317,20 @@ class BSONTest < Test::Unit::TestCase
end end
end end
def test_invalid_numeric_types
[BigDecimal.new("1.0"), Complex.new(0, 1), Rational.new!(2, 3)].each do |type|
print type.class
doc = {"x" => type}
begin
BSON.serialize(doc)
rescue => e
ensure
assert_equal InvalidDocument, e.class
assert_match /Numeric type #{type.class}/, e.message
end
end
end
def test_do_not_change_original_object def test_do_not_change_original_object
val = OrderedHash.new val = OrderedHash.new
val['not_id'] = 1 val['not_id'] = 1