bson 1.2.0-jruby
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of bson might be problematic. Click here for more details.
- data/LICENSE.txt +190 -0
- data/bin/b2json +65 -0
- data/bin/j2bson +72 -0
- data/ext/java/jar/bson-2.2.jar +0 -0
- data/ext/java/jar/jbson.jar +0 -0
- data/ext/java/jar/mongo-2.4.jar +0 -0
- data/lib/bson.rb +108 -0
- data/lib/bson/bson_c.rb +39 -0
- data/lib/bson/bson_java.rb +28 -0
- data/lib/bson/bson_ruby.rb +612 -0
- data/lib/bson/byte_buffer.rb +276 -0
- data/lib/bson/exceptions.rb +44 -0
- data/lib/bson/ordered_hash.rb +159 -0
- data/lib/bson/types/binary.rb +56 -0
- data/lib/bson/types/code.rb +59 -0
- data/lib/bson/types/dbref.rb +46 -0
- data/lib/bson/types/min_max_keys.rb +60 -0
- data/lib/bson/types/object_id.rb +194 -0
- data/test/bson/binary_test.rb +15 -0
- data/test/bson/bson_test.rb +565 -0
- data/test/bson/byte_buffer_test.rb +190 -0
- data/test/bson/hash_with_indifferent_access_test.rb +38 -0
- data/test/bson/json_test.rb +17 -0
- data/test/bson/object_id_test.rb +141 -0
- data/test/bson/ordered_hash_test.rb +197 -0
- metadata +100 -0
@@ -0,0 +1,276 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
# --
|
4
|
+
# Copyright (C) 2008-2011 10gen Inc.
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License.
|
8
|
+
# You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
# ++
|
18
|
+
|
19
|
+
# A byte buffer.
|
20
|
+
module BSON
|
21
|
+
class ByteBuffer
|
22
|
+
|
23
|
+
attr_reader :order
|
24
|
+
|
25
|
+
def initialize(initial_data="")
|
26
|
+
@str = case initial_data
|
27
|
+
when String then
|
28
|
+
if initial_data.respond_to?(:force_encoding)
|
29
|
+
initial_data.force_encoding('binary')
|
30
|
+
else
|
31
|
+
initial_data
|
32
|
+
end
|
33
|
+
when BSON::ByteBuffer then
|
34
|
+
initial_data.to_a.pack('C*')
|
35
|
+
else
|
36
|
+
initial_data.pack('C*')
|
37
|
+
end
|
38
|
+
|
39
|
+
@cursor = @str.length
|
40
|
+
@order = :little_endian
|
41
|
+
@int_pack_order = 'V'
|
42
|
+
@double_pack_order = 'E'
|
43
|
+
end
|
44
|
+
|
45
|
+
if RUBY_VERSION >= '1.9'
|
46
|
+
NULL_BYTE = "\0".force_encoding('binary').freeze
|
47
|
+
UTF8_ENCODING = Encoding.find('utf-8')
|
48
|
+
BINARY_ENCODING = Encoding.find('binary')
|
49
|
+
|
50
|
+
def self.to_utf8_binary(str)
|
51
|
+
str.encode(UTF8_ENCODING).force_encoding(BINARY_ENCODING)
|
52
|
+
end
|
53
|
+
else
|
54
|
+
NULL_BYTE = "\0"
|
55
|
+
|
56
|
+
def self.to_utf8_binary(str)
|
57
|
+
begin
|
58
|
+
str.unpack("U*")
|
59
|
+
rescue => ex
|
60
|
+
raise InvalidStringEncoding, "String not valid utf-8: #{str.inspect}"
|
61
|
+
end
|
62
|
+
str
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def self.serialize_cstr(buf, val)
|
67
|
+
buf.append!(to_utf8_binary(val.to_s))
|
68
|
+
buf.append!(NULL_BYTE)
|
69
|
+
end
|
70
|
+
|
71
|
+
# +endianness+ should be :little_endian or :big_endian. Default is :little_endian
|
72
|
+
def order=(endianness)
|
73
|
+
@order = endianness
|
74
|
+
@int_pack_order = endianness == :little_endian ? 'V' : 'N'
|
75
|
+
@double_pack_order = endianness == :little_endian ? 'E' : 'G'
|
76
|
+
end
|
77
|
+
|
78
|
+
def rewind
|
79
|
+
@cursor = 0
|
80
|
+
end
|
81
|
+
|
82
|
+
def position
|
83
|
+
@cursor
|
84
|
+
end
|
85
|
+
|
86
|
+
def position=(val)
|
87
|
+
@cursor = val
|
88
|
+
end
|
89
|
+
|
90
|
+
def clear
|
91
|
+
@str = ""
|
92
|
+
@str.force_encoding('binary') if @str.respond_to?(:force_encoding)
|
93
|
+
rewind
|
94
|
+
end
|
95
|
+
|
96
|
+
def size
|
97
|
+
@str.size
|
98
|
+
end
|
99
|
+
alias_method :length, :size
|
100
|
+
|
101
|
+
# Appends a second ByteBuffer object, +buffer+, to the current buffer.
|
102
|
+
def append!(buffer)
|
103
|
+
@str << buffer.to_s
|
104
|
+
self
|
105
|
+
end
|
106
|
+
|
107
|
+
# Prepends a second ByteBuffer object, +buffer+, to the current buffer.
|
108
|
+
def prepend!(buffer)
|
109
|
+
@str = buffer.to_s + @str
|
110
|
+
self
|
111
|
+
end
|
112
|
+
|
113
|
+
def put(byte, offset=nil)
|
114
|
+
@cursor = offset if offset
|
115
|
+
if more?
|
116
|
+
@str[@cursor] = chr(byte)
|
117
|
+
else
|
118
|
+
ensure_length(@cursor)
|
119
|
+
@str << chr(byte)
|
120
|
+
end
|
121
|
+
@cursor += 1
|
122
|
+
end
|
123
|
+
|
124
|
+
def put_binary(data, offset=nil)
|
125
|
+
@cursor = offset if offset
|
126
|
+
if defined?(BINARY_ENCODING)
|
127
|
+
data = data.dup.force_encoding(BINARY_ENCODING)
|
128
|
+
end
|
129
|
+
if more?
|
130
|
+
@str[@cursor, data.length] = data
|
131
|
+
else
|
132
|
+
ensure_length(@cursor)
|
133
|
+
@str << data
|
134
|
+
end
|
135
|
+
@cursor += data.length
|
136
|
+
end
|
137
|
+
|
138
|
+
def put_array(array, offset=nil)
|
139
|
+
@cursor = offset if offset
|
140
|
+
if more?
|
141
|
+
@str[@cursor, array.length] = array.pack("C*")
|
142
|
+
else
|
143
|
+
ensure_length(@cursor)
|
144
|
+
@str << array.pack("C*")
|
145
|
+
end
|
146
|
+
@cursor += array.length
|
147
|
+
end
|
148
|
+
|
149
|
+
def put_int(i, offset=nil)
|
150
|
+
@cursor = offset if offset
|
151
|
+
if more?
|
152
|
+
@str[@cursor, 4] = [i].pack(@int_pack_order)
|
153
|
+
else
|
154
|
+
ensure_length(@cursor)
|
155
|
+
@str << [i].pack(@int_pack_order)
|
156
|
+
end
|
157
|
+
@cursor += 4
|
158
|
+
end
|
159
|
+
|
160
|
+
def put_long(i, offset=nil)
|
161
|
+
offset = @cursor unless offset
|
162
|
+
if @int_pack_order == 'N'
|
163
|
+
put_int(i >> 32, offset)
|
164
|
+
put_int(i & 0xffffffff, offset + 4)
|
165
|
+
else
|
166
|
+
put_int(i & 0xffffffff, offset)
|
167
|
+
put_int(i >> 32, offset + 4)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
def put_double(d, offset=nil)
|
172
|
+
a = []
|
173
|
+
[d].pack(@double_pack_order).each_byte { |b| a << b }
|
174
|
+
put_array(a, offset)
|
175
|
+
end
|
176
|
+
|
177
|
+
# If +size+ == nil, returns one byte. Else returns array of bytes of length
|
178
|
+
# # +size+.
|
179
|
+
if "x"[0].is_a?(Integer)
|
180
|
+
def get(len=nil)
|
181
|
+
one_byte = len.nil?
|
182
|
+
len ||= 1
|
183
|
+
check_read_length(len)
|
184
|
+
start = @cursor
|
185
|
+
@cursor += len
|
186
|
+
if one_byte
|
187
|
+
@str[start]
|
188
|
+
else
|
189
|
+
@str[start, len].unpack("C*")
|
190
|
+
end
|
191
|
+
end
|
192
|
+
else
|
193
|
+
def get(len=nil)
|
194
|
+
one_byte = len.nil?
|
195
|
+
len ||= 1
|
196
|
+
check_read_length(len)
|
197
|
+
start = @cursor
|
198
|
+
@cursor += len
|
199
|
+
if one_byte
|
200
|
+
@str[start, 1].ord
|
201
|
+
else
|
202
|
+
@str[start, len].unpack("C*")
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
def get_int
|
208
|
+
check_read_length(4)
|
209
|
+
vals = @str[@cursor..@cursor+3]
|
210
|
+
@cursor += 4
|
211
|
+
vals.unpack(@int_pack_order)[0]
|
212
|
+
end
|
213
|
+
|
214
|
+
def get_long
|
215
|
+
i1 = get_int
|
216
|
+
i2 = get_int
|
217
|
+
if @int_pack_order == 'N'
|
218
|
+
(i1 << 32) + i2
|
219
|
+
else
|
220
|
+
(i2 << 32) + i1
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
def get_double
|
225
|
+
check_read_length(8)
|
226
|
+
vals = @str[@cursor..@cursor+7]
|
227
|
+
@cursor += 8
|
228
|
+
vals.unpack(@double_pack_order)[0]
|
229
|
+
end
|
230
|
+
|
231
|
+
def more?
|
232
|
+
@cursor < @str.size
|
233
|
+
end
|
234
|
+
|
235
|
+
def to_a
|
236
|
+
@str.unpack("C*")
|
237
|
+
end
|
238
|
+
|
239
|
+
def unpack(args)
|
240
|
+
to_a
|
241
|
+
end
|
242
|
+
|
243
|
+
def to_s
|
244
|
+
@str
|
245
|
+
end
|
246
|
+
|
247
|
+
def dump
|
248
|
+
i = 0
|
249
|
+
@str.each_byte do |c, i|
|
250
|
+
$stderr.puts "#{'%04d' % i}: #{'%02x' % c} #{'%03o' % c} #{'%s' % c.chr} #{'%3d' % c}"
|
251
|
+
i += 1
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
private
|
256
|
+
|
257
|
+
def ensure_length(length)
|
258
|
+
if @str.size < length
|
259
|
+
@str << NULL_BYTE * (length - @str.size)
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
def chr(byte)
|
264
|
+
if byte < 0
|
265
|
+
[byte].pack('c')
|
266
|
+
else
|
267
|
+
byte.chr
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
def check_read_length(len)
|
272
|
+
raise "attempt to read past end of buffer" if @cursor + len > @str.length
|
273
|
+
end
|
274
|
+
|
275
|
+
end
|
276
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
# --
|
4
|
+
# Copyright (C) 2008-2011 10gen Inc.
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License.
|
8
|
+
# You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
# ++
|
18
|
+
|
19
|
+
module BSON
|
20
|
+
# Generic Mongo Ruby Driver exception class.
|
21
|
+
class MongoRubyError < StandardError; end
|
22
|
+
|
23
|
+
# Raised when MongoDB itself has returned an error.
|
24
|
+
class MongoDBError < RuntimeError; end
|
25
|
+
|
26
|
+
# This will replace MongoDBError.
|
27
|
+
class BSONError < MongoDBError; end
|
28
|
+
|
29
|
+
# Raised when given a string is not valid utf-8 (Ruby 1.8 only).
|
30
|
+
class InvalidStringEncoding < BSONError; end
|
31
|
+
|
32
|
+
# Raised when attempting to initialize an invalid ObjectID.
|
33
|
+
class InvalidObjectID < BSONError; end
|
34
|
+
|
35
|
+
# Raised when attempting to initialize an invalid ObjectID.
|
36
|
+
class InvalidObjectId < BSONError; end
|
37
|
+
|
38
|
+
# Raised when trying to insert a document that exceeds the 4MB limit or
|
39
|
+
# when the document contains objects that can't be serialized as BSON.
|
40
|
+
class InvalidDocument < BSONError; end
|
41
|
+
|
42
|
+
# Raised when an invalid name is used.
|
43
|
+
class InvalidKeyName < BSONError; end
|
44
|
+
end
|
@@ -0,0 +1,159 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
# --
|
4
|
+
# Copyright (C) 2008-2011 10gen Inc.
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License.
|
8
|
+
# You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
# ++
|
18
|
+
|
19
|
+
# A hash in which the order of keys are preserved.
|
20
|
+
#
|
21
|
+
# Under Ruby 1.9 and greater, this class has no added methods because Ruby's
|
22
|
+
# Hash already keeps its keys ordered by order of insertion.
|
23
|
+
|
24
|
+
module BSON
|
25
|
+
class OrderedHash < Hash
|
26
|
+
|
27
|
+
def ==(other)
|
28
|
+
begin
|
29
|
+
case other
|
30
|
+
when BSON::OrderedHash
|
31
|
+
keys == other.keys && values == other.values
|
32
|
+
else
|
33
|
+
super
|
34
|
+
end
|
35
|
+
rescue
|
36
|
+
false
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# We only need the body of this class if the RUBY_VERSION is before 1.9
|
41
|
+
if RUBY_VERSION < '1.9'
|
42
|
+
attr_accessor :ordered_keys
|
43
|
+
|
44
|
+
def self.[] *args
|
45
|
+
oh = BSON::OrderedHash.new
|
46
|
+
if Hash === args[0]
|
47
|
+
oh.merge! args[0]
|
48
|
+
elsif (args.size % 2) != 0
|
49
|
+
raise ArgumentError, "odd number of elements for Hash"
|
50
|
+
else
|
51
|
+
0.step(args.size - 1, 2) do |key|
|
52
|
+
value = key + 1
|
53
|
+
oh[args[key]] = args[value]
|
54
|
+
end
|
55
|
+
end
|
56
|
+
oh
|
57
|
+
end
|
58
|
+
|
59
|
+
def initialize(*a, &b)
|
60
|
+
super
|
61
|
+
@ordered_keys = []
|
62
|
+
end
|
63
|
+
|
64
|
+
def keys
|
65
|
+
@ordered_keys || []
|
66
|
+
end
|
67
|
+
|
68
|
+
def []=(key, value)
|
69
|
+
@ordered_keys ||= []
|
70
|
+
unless has_key?(key)
|
71
|
+
@ordered_keys << key
|
72
|
+
end
|
73
|
+
super(key, value)
|
74
|
+
end
|
75
|
+
|
76
|
+
def each
|
77
|
+
@ordered_keys ||= []
|
78
|
+
@ordered_keys.each { |k| yield k, self[k] }
|
79
|
+
self
|
80
|
+
end
|
81
|
+
alias :each_pair :each
|
82
|
+
|
83
|
+
def to_a
|
84
|
+
@ordered_keys ||= []
|
85
|
+
@ordered_keys.map { |k| [k, self[k]] }
|
86
|
+
end
|
87
|
+
|
88
|
+
def values
|
89
|
+
collect { |k, v| v }
|
90
|
+
end
|
91
|
+
|
92
|
+
def merge(other)
|
93
|
+
oh = self.dup
|
94
|
+
oh.merge!(other)
|
95
|
+
oh
|
96
|
+
end
|
97
|
+
|
98
|
+
def merge!(other)
|
99
|
+
@ordered_keys ||= []
|
100
|
+
@ordered_keys += other.keys # unordered if not an BSON::OrderedHash
|
101
|
+
@ordered_keys.uniq!
|
102
|
+
super(other)
|
103
|
+
end
|
104
|
+
|
105
|
+
alias :update :merge!
|
106
|
+
|
107
|
+
def inspect
|
108
|
+
str = '{'
|
109
|
+
str << (@ordered_keys || []).collect { |k| "\"#{k}\"=>#{self.[](k).inspect}" }.join(", ")
|
110
|
+
str << '}'
|
111
|
+
end
|
112
|
+
|
113
|
+
def delete(key, &block)
|
114
|
+
@ordered_keys.delete(key) if @ordered_keys
|
115
|
+
super
|
116
|
+
end
|
117
|
+
|
118
|
+
def delete_if(&block)
|
119
|
+
self.each { |k,v|
|
120
|
+
if yield k, v
|
121
|
+
delete(k)
|
122
|
+
end
|
123
|
+
}
|
124
|
+
end
|
125
|
+
|
126
|
+
def reject(&block)
|
127
|
+
clone = self.clone
|
128
|
+
return clone unless block_given?
|
129
|
+
clone.delete_if(&block)
|
130
|
+
end
|
131
|
+
|
132
|
+
def clear
|
133
|
+
super
|
134
|
+
@ordered_keys = []
|
135
|
+
end
|
136
|
+
|
137
|
+
def hash
|
138
|
+
code = 17
|
139
|
+
each_pair do |key, value|
|
140
|
+
code = 37 * code + key.hash
|
141
|
+
code = 37 * code + value.hash
|
142
|
+
end
|
143
|
+
code & 0x7fffffff
|
144
|
+
end
|
145
|
+
|
146
|
+
def eql?(o)
|
147
|
+
if o.instance_of? BSON::OrderedHash
|
148
|
+
self.hash == o.hash
|
149
|
+
else
|
150
|
+
false
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
def clone
|
155
|
+
Marshal::load(Marshal.dump(self))
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|