mongo 0.0.1 → 0.0.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.
- data/Rakefile +1 -1
- data/lib/mongo.rb +1 -0
- data/lib/mongo/dbref.rb +37 -0
- data/lib/mongo/objectid.rb +12 -0
- data/lib/mongo/util/bson.rb +38 -15
- data/lib/mongo/util/ordered_hash.rb +6 -0
- data/tests/test_bson.rb +10 -0
- data/tests/test_objectid.rb +8 -0
- data/tests/test_ordered_hash.rb +4 -0
- data/tests/test_round_trip.rb +132 -0
- metadata +4 -2
data/Rakefile
CHANGED
@@ -7,7 +7,7 @@ require 'rake/gempackagetask'
|
|
7
7
|
require 'rake/contrib/rubyforgepublisher'
|
8
8
|
|
9
9
|
GEM = "mongo"
|
10
|
-
GEM_VERSION = '0.0.
|
10
|
+
GEM_VERSION = '0.0.2'
|
11
11
|
SUMMARY = 'Simple pure-Ruby driver for the 10gen Mongo DB'
|
12
12
|
DESCRIPTION = 'This is a simple pure-Ruby driver for the 10gen Mongo DB. For more information about Mongo, see http://www.mongodb.org.'
|
13
13
|
AUTHOR = 'Jim Menard'
|
data/lib/mongo.rb
CHANGED
data/lib/mongo/dbref.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
# --
|
2
|
+
# Copyright (C) 2008-2009 10gen Inc.
|
3
|
+
#
|
4
|
+
# This program is free software: you can redistribute it and/or modify it
|
5
|
+
# under the terms of the GNU Affero General Public License, version 3, as
|
6
|
+
# published by the Free Software Foundation.
|
7
|
+
#
|
8
|
+
# This program is distributed in the hope that it will be useful, but WITHOUT
|
9
|
+
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
10
|
+
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License
|
11
|
+
# for more details.
|
12
|
+
#
|
13
|
+
# You should have received a copy of the GNU Affero General Public License
|
14
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
15
|
+
# ++
|
16
|
+
|
17
|
+
module XGen
|
18
|
+
module Mongo
|
19
|
+
module Driver
|
20
|
+
|
21
|
+
class DBRef
|
22
|
+
|
23
|
+
attr_reader :parent, :field_name, :db, :namespace, :object_id
|
24
|
+
|
25
|
+
def initialize(parent, field_name, db, namespace, object_id)
|
26
|
+
@parent, @field_name, @db, @namespace, @object_id =
|
27
|
+
parent, field_name, db, namespace, object_id
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_s
|
31
|
+
"ns: #{namespace}, id: #{object_id}"
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/lib/mongo/objectid.rb
CHANGED
@@ -53,6 +53,18 @@ module XGen
|
|
53
53
|
@@index_time = Time.new.to_i
|
54
54
|
@@index = 0
|
55
55
|
|
56
|
+
# Given a string representation of an ObjectID, return a new ObjectID
|
57
|
+
# with that value.
|
58
|
+
def self.from_string(str)
|
59
|
+
data = []
|
60
|
+
i = str.to_i(16)
|
61
|
+
while i > 0
|
62
|
+
data << (i & 0xff)
|
63
|
+
i >>= 8
|
64
|
+
end
|
65
|
+
self.new(data.reverse)
|
66
|
+
end
|
67
|
+
|
56
68
|
# +data+ is an array of bytes. If nil, a new id will be generated.
|
57
69
|
# The time +t+ is only used for testing; leave it nil.
|
58
70
|
def initialize(data=nil, t=nil)
|
data/lib/mongo/util/bson.rb
CHANGED
@@ -17,6 +17,7 @@
|
|
17
17
|
require 'mongo/util/byte_buffer'
|
18
18
|
require 'mongo/util/ordered_hash'
|
19
19
|
require 'mongo/objectid'
|
20
|
+
require 'mongo/dbref'
|
20
21
|
|
21
22
|
# A BSON seralizer/deserializer.
|
22
23
|
class BSON
|
@@ -81,7 +82,9 @@ class BSON
|
|
81
82
|
serialize_date_element(@buf, k, v)
|
82
83
|
when NULL
|
83
84
|
serialize_null_element(@buf, k)
|
84
|
-
when
|
85
|
+
when REF
|
86
|
+
serialize_dbref_element(@buf, k, v)
|
87
|
+
when BINARY, UNDEFINED, SYMBOL, CODE_W_SCOPE
|
85
88
|
# TODO
|
86
89
|
raise "unimplemented type #{type}"
|
87
90
|
else
|
@@ -104,36 +107,39 @@ class BSON
|
|
104
107
|
type = @buf.get
|
105
108
|
case type
|
106
109
|
when STRING, CODE
|
107
|
-
key =
|
110
|
+
key = deserialize_cstr(@buf)
|
108
111
|
doc[key] = deserialize_string_data(@buf)
|
109
112
|
when NUMBER
|
110
|
-
key =
|
113
|
+
key = deserialize_cstr(@buf)
|
111
114
|
doc[key] = deserialize_number_data(@buf)
|
112
115
|
when NUMBER_INT
|
113
|
-
key =
|
116
|
+
key = deserialize_cstr(@buf)
|
114
117
|
doc[key] = deserialize_number_int_data(@buf)
|
115
118
|
when OID
|
116
|
-
key =
|
119
|
+
key = deserialize_cstr(@buf)
|
117
120
|
doc[key] = deserialize_oid_data(@buf)
|
118
121
|
when ARRAY
|
119
|
-
key =
|
122
|
+
key = deserialize_cstr(@buf)
|
120
123
|
doc[key] = deserialize_array_data(@buf)
|
121
124
|
when REGEX
|
122
|
-
key =
|
125
|
+
key = deserialize_cstr(@buf)
|
123
126
|
doc[key] = deserialize_regex_data(@buf)
|
124
127
|
when OBJECT
|
125
|
-
key =
|
128
|
+
key = deserialize_cstr(@buf)
|
126
129
|
doc[key] = deserialize_object_data(@buf)
|
127
130
|
when BOOLEAN
|
128
|
-
key =
|
131
|
+
key = deserialize_cstr(@buf)
|
129
132
|
doc[key] = deserialize_boolean_data(@buf)
|
130
133
|
when DATE
|
131
|
-
key =
|
134
|
+
key = deserialize_cstr(@buf)
|
132
135
|
doc[key] = deserialize_date_data(@buf)
|
133
136
|
when NULL
|
134
|
-
key =
|
137
|
+
key = deserialize_cstr(@buf)
|
135
138
|
doc[key] = nil
|
136
|
-
when
|
139
|
+
when REF
|
140
|
+
key = deserialize_cstr(@buf)
|
141
|
+
doc[key] = deserialize_dbref_data(@buf)
|
142
|
+
when BINARY, UNDEFINED, SYMBOL, CODE_W_SCOPE
|
137
143
|
# TODO
|
138
144
|
raise "unimplemented type #{type}"
|
139
145
|
when EOO
|
@@ -191,8 +197,8 @@ class BSON
|
|
191
197
|
end
|
192
198
|
|
193
199
|
def deserialize_regex_data(buf)
|
194
|
-
str =
|
195
|
-
options_str =
|
200
|
+
str = deserialize_cstr(buf)
|
201
|
+
options_str = deserialize_cstr(buf)
|
196
202
|
options = 0
|
197
203
|
options |= Regexp::IGNORECASE if options_str.include?('i')
|
198
204
|
options |= Regexp::MULTILINE if options_str.include?('m')
|
@@ -210,6 +216,14 @@ class BSON
|
|
210
216
|
XGen::Mongo::Driver::ObjectID.new(buf.get(12))
|
211
217
|
end
|
212
218
|
|
219
|
+
def deserialize_dbref_data(buf)
|
220
|
+
ns = deserialize_cstr(buf)
|
221
|
+
oid = deserialize_oid_data(buf)
|
222
|
+
# TODO fix parent, field_name, db of DBRef. Does that need to be done here
|
223
|
+
# or by the caller?
|
224
|
+
XGen::Mongo::Driver::DBRef.new(nil, nil, nil, ns, oid)
|
225
|
+
end
|
226
|
+
|
213
227
|
def serialize_eoo_element(buf)
|
214
228
|
buf.put(EOO)
|
215
229
|
end
|
@@ -219,6 +233,13 @@ class BSON
|
|
219
233
|
self.class.serialize_cstr(buf, key)
|
220
234
|
end
|
221
235
|
|
236
|
+
def serialize_dbref_element(buf, key, val)
|
237
|
+
buf.put(REF)
|
238
|
+
self.class.serialize_cstr(buf, key)
|
239
|
+
self.class.serialize_cstr(buf, val.namespace)
|
240
|
+
buf.put_array(val.object_id.to_a)
|
241
|
+
end
|
242
|
+
|
222
243
|
def serialize_boolean_element(buf, key, val)
|
223
244
|
buf.put(BOOLEAN)
|
224
245
|
self.class.serialize_cstr(buf, key)
|
@@ -298,7 +319,7 @@ class BSON
|
|
298
319
|
buf.position = end_pos
|
299
320
|
end
|
300
321
|
|
301
|
-
def
|
322
|
+
def deserialize_cstr(buf)
|
302
323
|
chars = ""
|
303
324
|
while 1
|
304
325
|
b = buf.get
|
@@ -325,6 +346,8 @@ class BSON
|
|
325
346
|
REGEX
|
326
347
|
when XGen::Mongo::Driver::ObjectID
|
327
348
|
OID
|
349
|
+
when XGen::Mongo::Driver::DBRef
|
350
|
+
REF
|
328
351
|
when true, false
|
329
352
|
BOOLEAN
|
330
353
|
when Time
|
data/tests/test_bson.rb
CHANGED
@@ -76,4 +76,14 @@ class BSONTest < Test::Unit::TestCase
|
|
76
76
|
|
77
77
|
def test_null
|
78
78
|
end
|
79
|
+
|
80
|
+
def test_dbref
|
81
|
+
oid = ObjectID.new
|
82
|
+
doc = {'dbref' => DBRef.new(nil, nil, nil, 'namespace', oid)}
|
83
|
+
@b.serialize(doc)
|
84
|
+
doc2 = @b.deserialize
|
85
|
+
assert_equal 'namespace', doc2['dbref'].namespace
|
86
|
+
assert_equal oid, doc2['dbref'].object_id
|
87
|
+
end
|
88
|
+
|
79
89
|
end
|
data/tests/test_objectid.rb
CHANGED
@@ -65,4 +65,12 @@ class ObjectIDTest < Test::Unit::TestCase
|
|
65
65
|
assert_equal @o, row['_id']
|
66
66
|
end
|
67
67
|
|
68
|
+
def test_from_string
|
69
|
+
hex_str = @o.to_s
|
70
|
+
o2 = ObjectID.from_string(hex_str)
|
71
|
+
assert_equal hex_str, o2.to_s
|
72
|
+
assert_equal @o, o2
|
73
|
+
assert_equal @o.to_s, o2.to_s
|
74
|
+
end
|
75
|
+
|
68
76
|
end
|
data/tests/test_ordered_hash.rb
CHANGED
@@ -0,0 +1,132 @@
|
|
1
|
+
HERE = File.dirname(__FILE__)
|
2
|
+
$LOAD_PATH[0,0] = File.join(HERE, '..', 'lib')
|
3
|
+
require 'mongo'
|
4
|
+
require 'rexml/document'
|
5
|
+
require 'test/unit'
|
6
|
+
|
7
|
+
# For each xml/bson file in the data subdirectory, we turn the XML into an
|
8
|
+
# OrderedHash and then test both Ruby-to-BSON and BSON-to-Ruby translations.
|
9
|
+
class RoundTripTest < Test::Unit::TestCase
|
10
|
+
|
11
|
+
include XGen::Mongo::Driver
|
12
|
+
|
13
|
+
@@ruby = nil
|
14
|
+
|
15
|
+
def setup
|
16
|
+
unless @@ruby
|
17
|
+
names = Dir[File.join(HERE, 'data', '*.xml')].collect {|f| File.basename(f).sub(/\.xml$/, '') }
|
18
|
+
@@ruby = {}
|
19
|
+
names.each { |name| @@ruby[name] = xml_to_ruby(name) }
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def xml_to_ruby(name)
|
24
|
+
File.open(File.join(HERE, 'data', "#{name}.xml")) { |f|
|
25
|
+
doc = REXML::Document.new(f)
|
26
|
+
doc_to_ruby(doc.root.elements['doc'])
|
27
|
+
}
|
28
|
+
end
|
29
|
+
|
30
|
+
def element_to_ruby(e)
|
31
|
+
type = e.name
|
32
|
+
child = e.elements[1]
|
33
|
+
case type
|
34
|
+
when 'oid'
|
35
|
+
ObjectID.from_string(e.text)
|
36
|
+
when 'ref'
|
37
|
+
dbref_to_ruby(e.elements)
|
38
|
+
when 'int'
|
39
|
+
e.text.to_i
|
40
|
+
when 'number'
|
41
|
+
e.text.to_f
|
42
|
+
when 'string', 'code'
|
43
|
+
e.text.to_s
|
44
|
+
when 'boolean'
|
45
|
+
e.text.to_s == 'true'
|
46
|
+
when 'array'
|
47
|
+
array_to_ruby(e.elements)
|
48
|
+
when 'date'
|
49
|
+
Time.at(e.text.to_f / 1000.0)
|
50
|
+
when 'regex'
|
51
|
+
regex_to_ruby(e.elements)
|
52
|
+
when 'null'
|
53
|
+
nil
|
54
|
+
when 'doc'
|
55
|
+
doc_to_ruby(e)
|
56
|
+
else
|
57
|
+
raise "Unknown type #{type} in element with name #{e.attributes['name']}"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def doc_to_ruby(element)
|
62
|
+
oh = OrderedHash.new
|
63
|
+
element.elements.each { |e| oh[e.attributes['name']] = element_to_ruby(e) }
|
64
|
+
oh
|
65
|
+
end
|
66
|
+
|
67
|
+
def array_to_ruby(elements)
|
68
|
+
a = []
|
69
|
+
elements.each { |e|
|
70
|
+
index_str = e.attributes['name']
|
71
|
+
a[index_str.to_i] = element_to_ruby(e)
|
72
|
+
}
|
73
|
+
a
|
74
|
+
end
|
75
|
+
|
76
|
+
def regex_to_ruby(elements)
|
77
|
+
pattern = elements['pattern'].text
|
78
|
+
options_str = elements['options'].text || ''
|
79
|
+
|
80
|
+
options = 0
|
81
|
+
options |= Regexp::IGNORECASE if options_str.include?('i')
|
82
|
+
options |= Regexp::MULTILINE if options_str.include?('m')
|
83
|
+
options |= Regexp::EXTENDED if options_str.include?('x')
|
84
|
+
Regexp.new(pattern, options)
|
85
|
+
end
|
86
|
+
|
87
|
+
def dbref_to_ruby(elements)
|
88
|
+
ns = elements['ns'].text
|
89
|
+
oid_str = elements['oid'].text
|
90
|
+
DBRef.new(nil, nil, nil, ns, ObjectID.from_string(oid_str))
|
91
|
+
end
|
92
|
+
|
93
|
+
# DEBUG
|
94
|
+
# def test_foo
|
95
|
+
# $stderr.puts "#{@@ruby['smorgasbord'].class.name}" # DEBUG
|
96
|
+
# $stderr.puts "@@ruby['smorgasbord'] = #{@@ruby['smorgasbord'].inspect.gsub(/, /, ",\n")}" # DEBUG
|
97
|
+
# end
|
98
|
+
|
99
|
+
def test_ruby_to_bson
|
100
|
+
@@ruby.each { |name, obj|
|
101
|
+
File.open(File.join(HERE, 'data', "#{name}.bson"), 'r') { |f|
|
102
|
+
bson = f.read
|
103
|
+
bson = if RUBY_VERSION >= '1.9'
|
104
|
+
bson.bytes
|
105
|
+
else
|
106
|
+
bson.split(//).collect { |c| c[0] }
|
107
|
+
end
|
108
|
+
bson_from_ruby = BSON.new.serialize(obj).to_a
|
109
|
+
assert_equal bson.length, bson_from_ruby.length
|
110
|
+
assert_equal bson, bson_from_ruby
|
111
|
+
}
|
112
|
+
}
|
113
|
+
end
|
114
|
+
|
115
|
+
# def test_bson_to_ruby
|
116
|
+
# @@ruby.each { |name, obj|
|
117
|
+
# File.open(File.join(HERE, 'data', "#{name}.bson"), 'r') { |f|
|
118
|
+
# bson = f.read
|
119
|
+
# obj_from_bson = BSON.new.deserialize(ByteBuffer.new(bson.split(//)))
|
120
|
+
# assert_equal obj, obj_from_bson
|
121
|
+
# }
|
122
|
+
# }
|
123
|
+
# end
|
124
|
+
|
125
|
+
# # Technically reduntant, given the other tests
|
126
|
+
# def test_roundtrips
|
127
|
+
# @@ruby.each { |name, obj|
|
128
|
+
|
129
|
+
# }
|
130
|
+
# end
|
131
|
+
|
132
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mongo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jim Menard
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-01-
|
12
|
+
date: 2009-01-09 00:00:00 -05:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -27,6 +27,7 @@ files:
|
|
27
27
|
- lib/mongo/collection.rb
|
28
28
|
- lib/mongo/cursor.rb
|
29
29
|
- lib/mongo/db.rb
|
30
|
+
- lib/mongo/dbref.rb
|
30
31
|
- lib/mongo/message/get_more_message.rb
|
31
32
|
- lib/mongo/message/insert_message.rb
|
32
33
|
- lib/mongo/message/kill_cursors_message.rb
|
@@ -53,6 +54,7 @@ files:
|
|
53
54
|
- tests/test_message.rb
|
54
55
|
- tests/test_objectid.rb
|
55
56
|
- tests/test_ordered_hash.rb
|
57
|
+
- tests/test_round_trip.rb
|
56
58
|
- Rakefile
|
57
59
|
- README.rdoc
|
58
60
|
has_rdoc: true
|