diff --git a/README b/README.rdoc similarity index 94% rename from README rename to README.rdoc index 4f8a33f..f283ce0 100644 --- a/README +++ b/README.rdoc @@ -3,9 +3,9 @@ This is a simple pure-Ruby driver for the 10gen Mongo DB. For more information about Mongo, see http://www.mongodb.org. -Note: this driver is still alpha quality. The API will change, as will the +Note: this driver is still alpha quality. The API will change, as may the data saved to the database (especially primary key values). Do *_not_* use this -for any production data. +for any production data yet. = Demo @@ -27,7 +27,7 @@ The tests assume that the Mongo database is running on the default port. $ rake rdoc Then open the file doc/index.html. (I need to figure out where to put this on -the Web, or even how to publish this to the Wiki at +the Web, or perhaps how to publish this to the Wiki at http://github.com/jimm/mongo-ruby-driver/wikis automatically.) @@ -53,7 +53,7 @@ type = To Do * Tests that prove that this driver's ObjectID and Geir's Java version do the - same thing. + same thing. (I've done so manually.) * Capped collection support. @@ -100,9 +100,3 @@ details. See http://www.gnu.org/licenses/ for a copy of the GNU Affero General Public License. - --- -# Local Variables: -# mode:rdoc -# End: -++ diff --git a/lib/mongo/util/bson.rb b/lib/mongo/util/bson.rb index 82af042..6632d01 100644 --- a/lib/mongo/util/bson.rb +++ b/lib/mongo/util/bson.rb @@ -3,35 +3,34 @@ require 'mongo/util/ordered_hash' require 'mongo/objectid' # See http://github.com/10gen/mongo/tree/master/db/jsobj.h -# and class BSON - EOO = 0 # x - MAXKEY = -1 # x - NUMBER = 1 # x t - STRING = 2 # x t - OBJECT = 3 # x t + MINKEY = -1 + EOO = 0 + NUMBER = 1 + STRING = 2 + OBJECT = 3 ARRAY = 4 BINARY = 5 UNDEFINED = 6 - OID = 7 # x - BOOLEAN = 8 # x t - DATE = 9 # x t - NULL = 10 # x t + OID = 7 + BOOLEAN = 8 + DATE = 9 + NULL = 10 REGEX = 11 REF = 12 CODE = 13 SYMBOL = 14 CODE_W_SCOPE = 15 NUMBER_INT = 16 + MAXKEY = 127 def self.serialize_cstr(buf, val) buf.put_array(val.to_s.unpack("C*") + [0]) end def initialize - @private_buf = ByteBuffer.new @buf = ByteBuffer.new end @@ -67,8 +66,10 @@ class BSON serialize_date_element(@buf, k, v) when NULL serialize_null_element(@buf, k) + when BINARY, UNDEFINED, REF, SYMBOL, CODE_W_SCOPE + raise "unimplemented type #{type}" else - raise "Unhandled Type #{type}" + raise "unhandled type #{type}" end } serialize_eoo_element(@buf) @@ -76,15 +77,17 @@ class BSON self end - def deserialize(buf) - @buf = ByteBuffer.new(buf.to_a) + def deserialize(buf=nil) + # If buf is nil, use @buf, assumed to contain already-serialized BSON. + # This is only true during testing. + @buf = ByteBuffer.new(buf.to_a) if buf @buf.rewind @buf.get_int # eat message size doc = {} while @buf.more? type = @buf.get case type - when STRING + when STRING, CODE key = deserialize_element_name(@buf) doc[key] = deserialize_string_data(@buf) when NUMBER @@ -302,7 +305,7 @@ class BSON when XGen::Mongo::Driver::ObjectID OID when true, false - Boolean + BOOLEAN when Time DATE when Hash diff --git a/lib/mongo/util/byte_buffer.rb b/lib/mongo/util/byte_buffer.rb index 55ef39c..dcede06 100644 --- a/lib/mongo/util/byte_buffer.rb +++ b/lib/mongo/util/byte_buffer.rb @@ -49,8 +49,14 @@ class ByteBuffer @cursor += array.length end - def put_int(i, offset=nil) - put_array([i].pack(@int_pack_order).split(//).collect{|c| c[0]}, offset) + if RUBY_VERSION >= '1.9' + def put_int(i, offset=nil) + put_array([i].pack(@int_pack_order).split(//).collect{|c| c.bytes.first}, offset) + end + else + def put_int(i, offset=nil) + put_array([i].pack(@int_pack_order).split(//).collect{|c| c[0]}, offset) + end end def put_long(i, offset=nil) @@ -64,8 +70,14 @@ class ByteBuffer end end - def put_double(d, offset=nil) - put_array([d].pack(@double_pack_order).split(//), offset) + if RUBY_VERSION >= '1.9' + def put_double(d, offset=nil) + put_array([d].pack(@double_pack_order).split(//).collect{|c| c.bytes.first}, offset) + end + else + def put_double(d, offset=nil) + put_array([d].pack(@double_pack_order).split(//).collect{|c| c[0]}, offset) + end end # If +size+ == 1, returns one byte. Else returns array of bytes of length diff --git a/tests/test_bson.rb b/tests/test_bson.rb new file mode 100644 index 0000000..da38a3b --- /dev/null +++ b/tests/test_bson.rb @@ -0,0 +1,77 @@ +$LOAD_PATH[0,0] = File.join(File.dirname(__FILE__), '..', 'lib') +require 'mongo' +require 'test/unit' + +# NOTE: assumes Mongo is running +class BSONTest < Test::Unit::TestCase + + def setup + @b = BSON.new + end + + def test_string + doc = {'doc' => 'hello, world'} + @b.serialize(doc) + assert_equal doc, @b.deserialize + end + + def test_code + doc = {'$where' => 'this.a.b < this.b'} + @b.serialize(doc) + assert_equal doc, @b.deserialize + end + + def test_number + doc = {'doc' => 41.99} + @b.serialize(doc) + assert_equal doc, @b.deserialize + end + + def test_int + doc = {'doc' => 42} + @b.serialize(doc) + assert_equal doc, @b.deserialize + end + + def test_object + doc = {'doc' => {'age' => 42, 'name' => 'Spongebob', 'shoe_size' => 9.5}} + @b.serialize(doc) + assert_equal doc, @b.deserialize + end + + def test_oid + doc = {'doc' => XGen::Mongo::Driver::ObjectID.new} + @b.serialize(doc) + assert_equal doc, @b.deserialize + end + + def test_array + doc = {'doc' => [1, 2, 'a', 'b']} + @b.serialize(doc) + assert_equal doc, @b.deserialize + end + + def test_regex + doc = {'doc' => /foobar/i} + @b.serialize(doc) + assert_equal doc, @b.deserialize + end + + def test_boolean + doc = {'doc' => true} + @b.serialize(doc) + assert_equal doc, @b.deserialize + end + + def test_date + doc = {'date' => Time.now} + @b.serialize(doc) + doc2 = @b.deserialize + # Mongo only stores seconds, so comparing raw Time objects will fail + # because the fractional seconds will be different. + assert_equal doc['date'].to_i, doc2['date'].to_i + end + + def test_null + end +end diff --git a/tests/test_byte_buffer.rb b/tests/test_byte_buffer.rb index 63ac6d9..5025fab 100644 --- a/tests/test_byte_buffer.rb +++ b/tests/test_byte_buffer.rb @@ -32,6 +32,12 @@ class ByteBufferTest < Test::Unit::TestCase assert_equal 1027, @buf.get_long end + def test_get_double + @buf.put_double 41.2 + @buf.rewind + assert_equal 41.2, @buf.get_double + end + def test_rewrite @buf.put_int(0) @buf.rewind