bson 3.2.7 → 4.0.0.beta

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/Rakefile +2 -10
  5. data/ext/bson/native-endian.h +120 -0
  6. data/ext/bson/native.c +547 -581
  7. data/lib/bson.rb +0 -1
  8. data/lib/bson/array.rb +15 -14
  9. data/lib/bson/binary.rb +13 -13
  10. data/lib/bson/boolean.rb +3 -3
  11. data/lib/bson/code.rb +5 -8
  12. data/lib/bson/code_with_scope.rb +10 -13
  13. data/lib/bson/date.rb +2 -2
  14. data/lib/bson/date_time.rb +2 -2
  15. data/lib/bson/document.rb +33 -0
  16. data/lib/bson/false_class.rb +2 -2
  17. data/lib/bson/float.rb +5 -11
  18. data/lib/bson/hash.rb +15 -14
  19. data/lib/bson/int32.rb +8 -9
  20. data/lib/bson/int64.rb +3 -9
  21. data/lib/bson/integer.rb +6 -20
  22. data/lib/bson/nil_class.rb +4 -16
  23. data/lib/bson/object.rb +1 -1
  24. data/lib/bson/object_id.rb +14 -16
  25. data/lib/bson/regexp.rb +7 -7
  26. data/lib/bson/specialized.rb +6 -6
  27. data/lib/bson/string.rb +7 -91
  28. data/lib/bson/symbol.rb +8 -7
  29. data/lib/bson/time.rb +5 -5
  30. data/lib/bson/timestamp.rb +8 -6
  31. data/lib/bson/true_class.rb +2 -2
  32. data/lib/bson/undefined.rb +1 -26
  33. data/lib/bson/version.rb +1 -1
  34. data/spec/bson/array_spec.rb +1 -1
  35. data/spec/bson/byte_buffer_spec.rb +445 -0
  36. data/spec/bson/code_with_scope_spec.rb +3 -7
  37. data/spec/bson/document_spec.rb +66 -10
  38. data/spec/bson/hash_spec.rb +5 -5
  39. data/spec/bson/int32_spec.rb +7 -5
  40. data/spec/bson/integer_spec.rb +1 -6
  41. data/spec/bson/object_id_spec.rb +2 -39
  42. data/spec/bson/regexp_spec.rb +1 -1
  43. data/spec/bson/string_spec.rb +2 -204
  44. data/spec/bson/symbol_spec.rb +2 -17
  45. data/spec/support/shared_examples.rb +3 -26
  46. metadata +13 -11
  47. metadata.gz.sig +0 -0
  48. data/lib/bson/encodable.rb +0 -86
@@ -37,23 +37,23 @@ module BSON
37
37
  # @see http://bsonspec.org/#/specification
38
38
  #
39
39
  # @since 2.0.0
40
- def to_bson(encoded = ''.force_encoding(BINARY))
41
- encoded << [ (to_i * 1000) + (usec / 1000) ].pack(Int64::PACK)
40
+ def to_bson(buffer = ByteBuffer.new)
41
+ buffer.put_int64((to_i * 1000) + (usec / 1000))
42
42
  end
43
43
 
44
44
  module ClassMethods
45
45
 
46
46
  # Deserialize UTC datetime from BSON.
47
47
  #
48
- # @param [ BSON ] bson The bson representing UTC datetime.
48
+ # @param [ ByteBuffer ] buffer The byte buffer.
49
49
  #
50
50
  # @return [ Time ] The decoded UTC datetime.
51
51
  #
52
52
  # @see http://bsonspec.org/#/specification
53
53
  #
54
54
  # @since 2.0.0
55
- def from_bson(bson)
56
- seconds, fragment = Int64.from_bson(bson).divmod(1000)
55
+ def from_bson(buffer)
56
+ seconds, fragment = Int64.from_bson(buffer).divmod(1000)
57
57
  at(seconds, fragment * 1000).utc
58
58
  end
59
59
  end
@@ -87,22 +87,24 @@ module BSON
87
87
  # @see http://bsonspec.org/#/specification
88
88
  #
89
89
  # @since 2.0.0
90
- def to_bson(encoded = ''.force_encoding(BINARY))
91
- increment.to_bson_int32(encoded)
92
- seconds.to_bson_int32(encoded)
90
+ def to_bson(buffer = ByteBuffer.new)
91
+ buffer.put_int32(increment)
92
+ buffer.put_int32(seconds)
93
93
  end
94
94
 
95
95
  # Deserialize timestamp from BSON.
96
96
  #
97
- # @param [ BSON ] bson The bson representing a timestamp.
97
+ # @param [ ByteBuffer ] buffer The byte buffer.
98
98
  #
99
99
  # @return [ Timestamp ] The decoded timestamp.
100
100
  #
101
101
  # @see http://bsonspec.org/#/specification
102
102
  #
103
103
  # @since 2.0.0
104
- def self.from_bson(bson)
105
- new(*bson.read(8).unpack(Int32::PACK * 2).reverse)
104
+ def self.from_bson(buffer)
105
+ increment = buffer.get_int32
106
+ seconds = buffer.get_int32
107
+ new(seconds, increment)
106
108
  end
107
109
 
108
110
  # Register this type when the module is loaded.
@@ -49,8 +49,8 @@ module BSON
49
49
  # @see http://bsonspec.org/#/specification
50
50
  #
51
51
  # @since 2.0.0
52
- def to_bson(encoded = ''.force_encoding(BINARY))
53
- encoded << TRUE_BYTE
52
+ def to_bson(buffer = ByteBuffer.new)
53
+ buffer.put_byte(TRUE_BYTE)
54
54
  end
55
55
  end
56
56
 
@@ -20,6 +20,7 @@ module BSON
20
20
  #
21
21
  # @since 2.0.0
22
22
  class Undefined
23
+ include Specialized
23
24
 
24
25
  # Undefined is type 0x06 in the BSON spec.
25
26
  #
@@ -40,32 +41,6 @@ module BSON
40
41
  self.class == other.class
41
42
  end
42
43
 
43
- # Encode the Undefined field - has no value since it only needs the type
44
- # and field name when being encoded.
45
- #
46
- # @example Encode the undefined value.
47
- # Undefined.to_bson
48
- #
49
- # @return [ String ] An empty string.
50
- #
51
- # @since 2.0.0
52
- def to_bson(encoded = ''.force_encoding(BINARY))
53
- encoded
54
- end
55
-
56
- # Deserialize undefined BSON type from BSON.
57
- #
58
- # @param [ BSON ] bson The encoded undefined value.
59
- #
60
- # @return [ Undefined ] The decoded undefined value.
61
- #
62
- # @see http://bsonspec.org/#/specification
63
- #
64
- # @since 2.0.0
65
- def self.from_bson(bson)
66
- new
67
- end
68
-
69
44
  # Register this type when the module is loaded.
70
45
  #
71
46
  # @since 2.0.0
@@ -13,5 +13,5 @@
13
13
  # limitations under the License.
14
14
 
15
15
  module BSON
16
- VERSION = "3.2.7"
16
+ VERSION = "4.0.0.beta"
17
17
  end
@@ -21,7 +21,7 @@ describe Array do
21
21
  let(:type) { 4.chr }
22
22
  let(:obj) {[ "one", "two" ]}
23
23
  let(:bson) do
24
- BSON::Document["0", "one", "1", "two"].to_bson
24
+ BSON::Document["0", "one", "1", "two"].to_bson.to_s
25
25
  end
26
26
 
27
27
  it_behaves_like "a bson element"
@@ -0,0 +1,445 @@
1
+ require 'spec_helper'
2
+
3
+ describe BSON::ByteBuffer do
4
+
5
+ describe '#allocate' do
6
+
7
+ let(:buffer) do
8
+ described_class.allocate
9
+ end
10
+
11
+ it 'allocates a buffer' do
12
+ expect(buffer).to be_a(BSON::ByteBuffer)
13
+ end
14
+ end
15
+
16
+ describe '#get_byte' do
17
+
18
+ let(:buffer) do
19
+ described_class.new(BSON::Int32::BSON_TYPE)
20
+ end
21
+
22
+ let!(:byte) do
23
+ buffer.get_byte
24
+ end
25
+
26
+ it 'gets the byte from the buffer' do
27
+ expect(byte).to eq(BSON::Int32::BSON_TYPE)
28
+ end
29
+
30
+ it 'increments the read position by 1' do
31
+ expect(buffer.read_position).to eq(1)
32
+ end
33
+ end
34
+
35
+ describe '#get_bytes' do
36
+
37
+ let(:string) do
38
+ "#{BSON::Int32::BSON_TYPE}#{BSON::Int32::BSON_TYPE}"
39
+ end
40
+
41
+ let(:buffer) do
42
+ described_class.new(string)
43
+ end
44
+
45
+ let!(:bytes) do
46
+ buffer.get_bytes(2)
47
+ end
48
+
49
+ it 'gets the bytes from the buffer' do
50
+ expect(bytes).to eq(string)
51
+ end
52
+
53
+ it 'increments the position by the length' do
54
+ expect(buffer.read_position).to eq(string.bytesize)
55
+ end
56
+ end
57
+
58
+ describe '#get_cstring' do
59
+
60
+ let(:buffer) do
61
+ described_class.new("testing#{BSON::NULL_BYTE}")
62
+ end
63
+
64
+ let!(:string) do
65
+ buffer.get_cstring
66
+ end
67
+
68
+ it 'gets the cstring from the buffer' do
69
+ expect(string).to eq("testing")
70
+ end
71
+
72
+ it 'increments the position by string length + 1' do
73
+ expect(buffer.read_position).to eq(8)
74
+ end
75
+ end
76
+
77
+ describe '#get_double' do
78
+
79
+ let(:buffer) do
80
+ described_class.new("#{12.5.to_bson.to_s}")
81
+ end
82
+
83
+ let!(:double) do
84
+ buffer.get_double
85
+ end
86
+
87
+ it 'gets the double from the buffer' do
88
+ expect(double).to eq(12.5)
89
+ end
90
+
91
+ it 'increments the read position by 8' do
92
+ expect(buffer.read_position).to eq(8)
93
+ end
94
+ end
95
+
96
+ describe '#get_int32' do
97
+
98
+ let(:buffer) do
99
+ described_class.new("#{12.to_bson.to_s}")
100
+ end
101
+
102
+ let!(:int32) do
103
+ buffer.get_int32
104
+ end
105
+
106
+ it 'gets the int32 from the buffer' do
107
+ expect(int32).to eq(12)
108
+ end
109
+
110
+ it 'increments the position by 4' do
111
+ expect(buffer.read_position).to eq(4)
112
+ end
113
+ end
114
+
115
+ describe '#get_int64' do
116
+
117
+ let(:buffer) do
118
+ described_class.new("#{(Integer::MAX_64BIT - 1).to_bson.to_s}")
119
+ end
120
+
121
+ let!(:int64) do
122
+ buffer.get_int64
123
+ end
124
+
125
+ it 'gets the int64 from the buffer' do
126
+ expect(int64).to eq(Integer::MAX_64BIT - 1)
127
+ end
128
+
129
+ it 'increments the position by 8' do
130
+ expect(buffer.read_position).to eq(8)
131
+ end
132
+ end
133
+
134
+ describe '#get_string' do
135
+
136
+ let(:buffer) do
137
+ described_class.new("#{8.to_bson.to_s}testing#{BSON::NULL_BYTE}")
138
+ end
139
+
140
+ let!(:string) do
141
+ buffer.get_string
142
+ end
143
+
144
+ it 'gets the string from the buffer' do
145
+ expect(string).to eq("testing")
146
+ end
147
+
148
+ it 'increments the position by string length + 5' do
149
+ expect(buffer.read_position).to eq(12)
150
+ end
151
+ end
152
+
153
+ describe '#length' do
154
+
155
+ let(:buffer) do
156
+ described_class.new
157
+ end
158
+
159
+ before do
160
+ buffer.put_int32(5)
161
+ end
162
+
163
+ it 'returns the length of the buffer' do
164
+ expect(buffer.length).to eq(4)
165
+ end
166
+ end
167
+
168
+ describe '#put_byte' do
169
+
170
+ let(:buffer) do
171
+ described_class.new
172
+ end
173
+
174
+ let!(:modified) do
175
+ buffer.put_byte(BSON::Int32::BSON_TYPE)
176
+ end
177
+
178
+ it 'appends the byte to the byte buffer' do
179
+ expect(modified.to_s).to eq(BSON::Int32::BSON_TYPE.chr)
180
+ end
181
+
182
+ it 'increments the write position by 1' do
183
+ expect(modified.write_position).to eq(1)
184
+ end
185
+ end
186
+
187
+ describe '#put_cstring' do
188
+
189
+ let(:buffer) do
190
+ described_class.new
191
+ end
192
+
193
+ context 'when the string is valid' do
194
+
195
+ let!(:modified) do
196
+ buffer.put_cstring('testing')
197
+ end
198
+
199
+ it 'appends the string plus null byte to the byte buffer' do
200
+ expect(modified.to_s).to eq("testing#{BSON::NULL_BYTE}")
201
+ end
202
+
203
+ it 'increments the write position by the length + 1' do
204
+ expect(modified.write_position).to eq(8)
205
+ end
206
+ end
207
+
208
+ context "when the string contains a null byte" do
209
+
210
+ let(:string) do
211
+ "test#{BSON::NULL_BYTE}ing"
212
+ end
213
+
214
+ it "raises an error" do
215
+ expect {
216
+ buffer.put_cstring(string)
217
+ }.to raise_error(ArgumentError)
218
+ end
219
+ end
220
+ end
221
+
222
+ describe '#put_double' do
223
+
224
+ let(:buffer) do
225
+ described_class.new
226
+ end
227
+
228
+ let!(:modified) do
229
+ buffer.put_double(1.2332)
230
+ end
231
+
232
+ it 'appends the double to the buffer' do
233
+ expect(modified.to_s).to eq([ 1.2332 ].pack(Float::PACK))
234
+ end
235
+
236
+ it 'increments the write position by 8' do
237
+ expect(modified.write_position).to eq(8)
238
+ end
239
+ end
240
+
241
+ describe '#put_int32' do
242
+
243
+ let(:buffer) do
244
+ described_class.new
245
+ end
246
+
247
+ context 'when the integer is 32 bit' do
248
+
249
+ context 'when the integer is positive' do
250
+
251
+ let!(:modified) do
252
+ buffer.put_int32(Integer::MAX_32BIT - 1)
253
+ end
254
+
255
+ let(:expected) do
256
+ [ Integer::MAX_32BIT - 1 ].pack(BSON::Int32::PACK)
257
+ end
258
+
259
+ it 'appends the int32 to the byte buffer' do
260
+ expect(modified.to_s).to eq(expected)
261
+ end
262
+
263
+ it 'increments the write position by 4' do
264
+ expect(modified.write_position).to eq(4)
265
+ end
266
+ end
267
+
268
+ context 'when the integer is negative' do
269
+
270
+ let!(:modified) do
271
+ buffer.put_int32(Integer::MIN_32BIT + 1)
272
+ end
273
+
274
+ let(:expected) do
275
+ [ Integer::MIN_32BIT + 1 ].pack(BSON::Int32::PACK)
276
+ end
277
+
278
+ it 'appends the int32 to the byte buffer' do
279
+ expect(modified.to_s).to eq(expected)
280
+ end
281
+
282
+ it 'increments the write position by 4' do
283
+ expect(modified.write_position).to eq(4)
284
+ end
285
+ end
286
+
287
+ context 'when the integer is not 32 bit' do
288
+
289
+ it 'raises an exception' do
290
+ expect {
291
+ buffer.put_int32(Integer::MAX_64BIT - 1)
292
+ }.to raise_error(RangeError)
293
+ end
294
+ end
295
+ end
296
+ end
297
+
298
+ describe '#put_int64' do
299
+
300
+ let(:buffer) do
301
+ described_class.new
302
+ end
303
+
304
+ context 'when the integer is 64 bit' do
305
+
306
+ context 'when the integer is positive' do
307
+
308
+ let!(:modified) do
309
+ buffer.put_int64(Integer::MAX_64BIT - 1)
310
+ end
311
+
312
+ let(:expected) do
313
+ [ Integer::MAX_64BIT - 1 ].pack(BSON::Int64::PACK)
314
+ end
315
+
316
+ it 'appends the int64 to the byte buffer' do
317
+ expect(modified.to_s).to eq(expected)
318
+ end
319
+
320
+ it 'increments the write position by 8' do
321
+ expect(modified.write_position).to eq(8)
322
+ end
323
+ end
324
+
325
+ context 'when the integer is negative' do
326
+
327
+ let!(:modified) do
328
+ buffer.put_int64(Integer::MIN_64BIT + 1)
329
+ end
330
+
331
+ let(:expected) do
332
+ [ Integer::MIN_64BIT + 1 ].pack(BSON::Int64::PACK)
333
+ end
334
+
335
+ it 'appends the int64 to the byte buffer' do
336
+ expect(modified.to_s).to eq(expected)
337
+ end
338
+
339
+ it 'increments the write position by 8' do
340
+ expect(modified.write_position).to eq(8)
341
+ end
342
+ end
343
+
344
+ context 'when the integer is larger than 64 bit' do
345
+
346
+ it 'raises an exception' do
347
+ expect {
348
+ buffer.put_int64(Integer::MAX_64BIT + 1)
349
+ }.to raise_error(RangeError)
350
+ end
351
+ end
352
+ end
353
+ end
354
+
355
+ describe '#put_string' do
356
+
357
+ context 'when the buffer does not need to be expanded' do
358
+
359
+ let(:buffer) do
360
+ described_class.new
361
+ end
362
+
363
+ context 'when the string is UTF-8' do
364
+
365
+ let!(:modified) do
366
+ buffer.put_string('testing')
367
+ end
368
+
369
+ it 'appends the string to the byte buffer' do
370
+ expect(modified.to_s).to eq("#{8.to_bson.to_s}testing#{BSON::NULL_BYTE}")
371
+ end
372
+
373
+ it 'increments the write position by length + 5' do
374
+ expect(modified.write_position).to eq(12)
375
+ end
376
+ end
377
+ end
378
+
379
+ context 'when the buffer needs to be expanded' do
380
+
381
+ let(:buffer) do
382
+ described_class.new
383
+ end
384
+
385
+ let(:string) do
386
+ 300.times.inject(""){ |s, i| s << "#{i}" }
387
+ end
388
+
389
+ context 'when no bytes exist in the buffer' do
390
+
391
+ let!(:modified) do
392
+ buffer.put_string(string)
393
+ end
394
+
395
+ it 'appends the string to the byte buffer' do
396
+ expect(modified.to_s).to eq("#{(string.bytesize + 1).to_bson.to_s}#{string}#{BSON::NULL_BYTE}")
397
+ end
398
+
399
+ it 'increments the write position by length + 5' do
400
+ expect(modified.write_position).to eq(string.bytesize + 5)
401
+ end
402
+ end
403
+
404
+ context 'when bytes exist in the buffer' do
405
+
406
+ let!(:modified) do
407
+ buffer.put_int32(4).put_string(string)
408
+ end
409
+
410
+ it 'appends the string to the byte buffer' do
411
+ expect(modified.to_s).to eq(
412
+ "#{[ 4 ].pack(BSON::Int32::PACK)}#{(string.bytesize + 1).to_bson.to_s}#{string}#{BSON::NULL_BYTE}"
413
+ )
414
+ end
415
+
416
+ it 'increments the write position by length + 5' do
417
+ expect(modified.write_position).to eq(string.bytesize + 9)
418
+ end
419
+ end
420
+ end
421
+ end
422
+
423
+ describe '#replace_int32' do
424
+
425
+ let(:buffer) do
426
+ described_class.new
427
+ end
428
+
429
+ let(:exp_first) do
430
+ [ 5 ].pack(BSON::Int32::PACK)
431
+ end
432
+
433
+ let(:exp_second) do
434
+ [ 4 ].pack(BSON::Int32::PACK)
435
+ end
436
+
437
+ let(:modified) do
438
+ buffer.put_int32(0).put_int32(4).replace_int32(0, 5)
439
+ end
440
+
441
+ it 'replaces the int32 at the location' do
442
+ expect(modified.to_s).to eq("#{exp_first}#{exp_second}")
443
+ end
444
+ end
445
+ end