bson 1.7.0-java

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.

@@ -0,0 +1,30 @@
1
+ include Java
2
+ module BSON
3
+ class BSON_JAVA
4
+
5
+ # TODO: Pool or cache instances of RubyBSONEncoder so that
6
+ # we don't create a new one on each call to #serialize.
7
+ def self.serialize(obj, check_keys=false, move_id=false, max_bson_size=BSON::DEFAULT_MAX_BSON_SIZE)
8
+ raise InvalidDocument, "BSON_JAVA.serialize takes a Hash" unless obj.is_a?(Hash)
9
+ enc = Java::OrgJbson::RubyBSONEncoder.new(JRuby.runtime, check_keys, move_id, max_bson_size)
10
+ ByteBuffer.new(enc.encode(obj))
11
+ end
12
+
13
+ def self.deserialize(buf)
14
+ dec = Java::OrgJbson::RubyBSONDecoder.new
15
+ callback = Java::OrgJbson::RubyBSONCallback.new(JRuby.runtime)
16
+ dec.decode(buf.to_s.to_java_bytes, callback)
17
+ callback.get
18
+ end
19
+
20
+ def self.max_bson_size
21
+ warn "BSON::BSON_CODER.max_bson_size is deprecated and will be removed in v2.0."
22
+ Java::OrgJbson::RubyBSONEncoder.max_bson_size(self)
23
+ end
24
+
25
+ def self.update_max_bson_size(connection)
26
+ warn "BSON::BSON_CODER.update_max_bson_size is deprecated and now a no-op. It will be removed in v2.0."
27
+ Java::OrgJbson::RubyBSONEncoder.update_max_bson_size(self, connection)
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,641 @@
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
+ # A BSON seralizer/deserializer in pure Ruby.
21
+ class BSON_RUBY
22
+
23
+ DEFAULT_MAX_BSON_SIZE = 4 * 1024 * 1024
24
+
25
+ @@max_bson_size = DEFAULT_MAX_BSON_SIZE
26
+
27
+ MINKEY = -1
28
+ EOO = 0
29
+ NUMBER = 1
30
+ STRING = 2
31
+ OBJECT = 3
32
+ ARRAY = 4
33
+ BINARY = 5
34
+ UNDEFINED = 6
35
+ OID = 7
36
+ BOOLEAN = 8
37
+ DATE = 9
38
+ NULL = 10
39
+ REGEX = 11
40
+ REF = 12
41
+ CODE = 13
42
+ SYMBOL = 14
43
+ CODE_W_SCOPE = 15
44
+ NUMBER_INT = 16
45
+ TIMESTAMP = 17
46
+ NUMBER_LONG = 18
47
+ MAXKEY = 127
48
+
49
+ def initialize(max_bson_size=BSON::DEFAULT_MAX_BSON_SIZE)
50
+ @buf = ByteBuffer.new('', max_bson_size)
51
+ @encoder = BSON_RUBY
52
+ end
53
+
54
+ if RUBY_VERSION >= '1.9'
55
+ NULL_BYTE = "\0".force_encoding('binary').freeze
56
+ UTF8_ENCODING = Encoding.find('utf-8')
57
+ BINARY_ENCODING = Encoding.find('binary')
58
+
59
+ def self.to_utf8_binary(str)
60
+ begin
61
+ str.unpack("U*")
62
+ rescue
63
+ raise InvalidStringEncoding, "String not valid utf-8: #{str.inspect}"
64
+ end
65
+ str.dup.force_encoding(BINARY_ENCODING)
66
+ end
67
+ else
68
+ NULL_BYTE = "\0"
69
+
70
+ def self.to_utf8_binary(str)
71
+ begin
72
+ str.unpack("U*")
73
+ rescue
74
+ raise InvalidStringEncoding, "String not valid utf-8: #{str.inspect}"
75
+ end
76
+ str
77
+ end
78
+ end
79
+
80
+ def self.update_max_bson_size(connection)
81
+ warn "BSON::BSON_CODER.update_max_bson_size is deprecated and now a no-op. It will be removed in v2.0."
82
+ @@max_bson_size = connection.max_bson_size
83
+ end
84
+
85
+ def self.max_bson_size
86
+ warn "BSON::BSON_CODER.max_bson_size is deprecated and will be removed in v2.0."
87
+ @@max_bson_size
88
+ end
89
+
90
+ def self.serialize_cstr(buf, val)
91
+ buf.put_binary(to_utf8_binary(val.to_s))
92
+ buf.put_binary(NULL_BYTE)
93
+ end
94
+
95
+ def self.serialize_key(buf, key)
96
+ raise InvalidDocument, "Key names / regex patterns must not contain the NULL byte" if key.include? "\x00"
97
+ self.serialize_cstr(buf, key)
98
+ end
99
+
100
+ def to_a
101
+ @buf.to_a
102
+ end
103
+
104
+ def to_s
105
+ @buf.to_s
106
+ end
107
+
108
+ # Serializes an object.
109
+ # Implemented to ensure an API compatible with BSON extension.
110
+ def self.serialize(obj, check_keys=false, move_id=false, max_bson_size=BSON::DEFAULT_MAX_BSON_SIZE)
111
+ new(max_bson_size).serialize(obj, check_keys, move_id)
112
+ end
113
+
114
+ def self.deserialize(buf=nil)
115
+ new.deserialize(buf)
116
+ end
117
+
118
+ def serialize(obj, check_keys=false, move_id=false)
119
+ raise(InvalidDocument, "BSON.serialize takes a Hash but got a #{obj.class}") unless obj.is_a?(Hash)
120
+ raise "Document is null" unless obj
121
+
122
+ @buf.rewind
123
+ # put in a placeholder for the total size
124
+ @buf.put_int(0)
125
+
126
+ # Write key/value pairs. Always write _id first if it exists.
127
+ if move_id
128
+ if obj.has_key? '_id'
129
+ serialize_key_value('_id', obj['_id'], false)
130
+ elsif obj.has_key? :_id
131
+ serialize_key_value('_id', obj[:_id], false)
132
+ end
133
+ obj.each {|k, v| serialize_key_value(k, v, check_keys) unless k == '_id' || k == :_id }
134
+ else
135
+ if obj.has_key?('_id') && obj.has_key?(:_id)
136
+ obj['_id'] = obj.delete(:_id)
137
+ end
138
+ obj.each {|k, v| serialize_key_value(k, v, check_keys) }
139
+ end
140
+
141
+ serialize_eoo_element(@buf)
142
+ if @buf.size > @buf.max_size
143
+ raise InvalidDocument, "Document is too large (#{@buf.size}). " +
144
+ "This BSON documents is limited to #{@buf.max_size} bytes."
145
+ end
146
+ @buf.put_int(@buf.size, 0)
147
+ @buf
148
+ end
149
+
150
+ # Returns the array stored in the buffer.
151
+ # Implemented to ensure an API compatible with BSON extension.
152
+ def unpack(arg)
153
+ @buf.to_a
154
+ end
155
+
156
+ def serialize_key_value(k, v, check_keys)
157
+ k = k.to_s
158
+ if check_keys
159
+ if k[0] == ?$
160
+ raise InvalidKeyName.new("key #{k} must not start with '$'")
161
+ end
162
+ if k.include? ?.
163
+ raise InvalidKeyName.new("key #{k} must not contain '.'")
164
+ end
165
+ end
166
+ type = bson_type(v)
167
+ case type
168
+ when STRING, SYMBOL
169
+ serialize_string_element(@buf, k, v, type)
170
+ when NUMBER, NUMBER_INT
171
+ serialize_number_element(@buf, k, v, type)
172
+ when OBJECT
173
+ serialize_object_element(@buf, k, v, check_keys)
174
+ when OID
175
+ serialize_oid_element(@buf, k, v)
176
+ when ARRAY
177
+ serialize_array_element(@buf, k, v, check_keys)
178
+ when REGEX
179
+ serialize_regex_element(@buf, k, v)
180
+ when BOOLEAN
181
+ serialize_boolean_element(@buf, k, v)
182
+ when DATE
183
+ serialize_date_element(@buf, k, v)
184
+ when NULL
185
+ serialize_null_element(@buf, k)
186
+ when REF
187
+ serialize_dbref_element(@buf, k, v)
188
+ when BINARY
189
+ serialize_binary_element(@buf, k, v)
190
+ when UNDEFINED
191
+ serialize_null_element(@buf, k)
192
+ when CODE_W_SCOPE
193
+ serialize_code_w_scope(@buf, k, v)
194
+ when MAXKEY
195
+ serialize_max_key_element(@buf, k)
196
+ when MINKEY
197
+ serialize_min_key_element(@buf, k)
198
+ when TIMESTAMP
199
+ serialize_timestamp_element(@buf, k, v)
200
+ else
201
+ raise "unhandled type #{type}"
202
+ end
203
+ end
204
+
205
+ def deserialize(buf=nil)
206
+ # If buf is nil, use @buf, assumed to contain already-serialized BSON.
207
+ # This is only true during testing.
208
+ if buf.is_a? String
209
+ @buf = ByteBuffer.new(buf.unpack("C*")) if buf
210
+ else
211
+ @buf = ByteBuffer.new(buf.to_a) if buf
212
+ end
213
+ @buf.rewind
214
+ @buf.get_int # eat message size
215
+ doc = BSON::OrderedHash.new
216
+ while @buf.more?
217
+ type = @buf.get
218
+ case type
219
+ when STRING, CODE
220
+ key = deserialize_cstr(@buf)
221
+ doc[key] = deserialize_string_data(@buf)
222
+ when SYMBOL
223
+ key = deserialize_cstr(@buf)
224
+ doc[key] = deserialize_string_data(@buf).intern
225
+ when NUMBER
226
+ key = deserialize_cstr(@buf)
227
+ doc[key] = deserialize_number_data(@buf)
228
+ when NUMBER_INT
229
+ key = deserialize_cstr(@buf)
230
+ doc[key] = deserialize_number_int_data(@buf)
231
+ when NUMBER_LONG
232
+ key = deserialize_cstr(@buf)
233
+ doc[key] = deserialize_number_long_data(@buf)
234
+ when OID
235
+ key = deserialize_cstr(@buf)
236
+ doc[key] = deserialize_oid_data(@buf)
237
+ when ARRAY
238
+ key = deserialize_cstr(@buf)
239
+ doc[key] = deserialize_array_data(@buf)
240
+ when REGEX
241
+ key = deserialize_cstr(@buf)
242
+ doc[key] = deserialize_regex_data(@buf)
243
+ when OBJECT
244
+ key = deserialize_cstr(@buf)
245
+ doc[key] = deserialize_object_data(@buf)
246
+ when BOOLEAN
247
+ key = deserialize_cstr(@buf)
248
+ doc[key] = deserialize_boolean_data(@buf)
249
+ when DATE
250
+ key = deserialize_cstr(@buf)
251
+ doc[key] = deserialize_date_data(@buf)
252
+ when NULL
253
+ key = deserialize_cstr(@buf)
254
+ doc[key] = nil
255
+ when UNDEFINED
256
+ key = deserialize_cstr(@buf)
257
+ doc[key] = nil
258
+ when REF
259
+ key = deserialize_cstr(@buf)
260
+ doc[key] = deserialize_dbref_data(@buf)
261
+ when BINARY
262
+ key = deserialize_cstr(@buf)
263
+ doc[key] = deserialize_binary_data(@buf)
264
+ when CODE_W_SCOPE
265
+ key = deserialize_cstr(@buf)
266
+ doc[key] = deserialize_code_w_scope_data(@buf)
267
+ when TIMESTAMP
268
+ key = deserialize_cstr(@buf)
269
+ doc[key] = deserialize_timestamp_data(@buf)
270
+ when MAXKEY
271
+ key = deserialize_cstr(@buf)
272
+ doc[key] = MaxKey.new
273
+ when MINKEY, 255 # This is currently easier than unpack the type byte as an unsigned char.
274
+ key = deserialize_cstr(@buf)
275
+ doc[key] = MinKey.new
276
+ when EOO
277
+ break
278
+ else
279
+ raise "Unknown type #{type}, key = #{key}"
280
+ end
281
+ end
282
+ @buf.rewind
283
+ doc
284
+ end
285
+
286
+ # For debugging.
287
+ def hex_dump
288
+ str = ''
289
+ @buf.to_a.each_with_index { |b,i|
290
+ if (i % 8) == 0
291
+ str << "\n" if i > 0
292
+ str << '%4d: ' % i
293
+ else
294
+ str << ' '
295
+ end
296
+ str << '%02X' % b
297
+ }
298
+ str
299
+ end
300
+
301
+ def deserialize_date_data(buf)
302
+ unsigned = buf.get_long()
303
+ milliseconds = unsigned >= 2 ** 64 / 2 ? unsigned - 2**64 : unsigned
304
+ Time.at(milliseconds.to_f / 1000.0).utc # at() takes fractional seconds
305
+ end
306
+
307
+ def deserialize_boolean_data(buf)
308
+ buf.get == 1
309
+ end
310
+
311
+ def deserialize_number_data(buf)
312
+ buf.get_double
313
+ end
314
+
315
+ def deserialize_number_int_data(buf)
316
+ unsigned = buf.get_int
317
+ unsigned >= 2**32 / 2 ? unsigned - 2**32 : unsigned
318
+ end
319
+
320
+ def deserialize_number_long_data(buf)
321
+ unsigned = buf.get_long
322
+ unsigned >= 2 ** 64 / 2 ? unsigned - 2**64 : unsigned
323
+ end
324
+
325
+ def deserialize_object_data(buf)
326
+ size = buf.get_int
327
+ buf.position -= 4
328
+ object = @encoder.new().deserialize(buf.get(size))
329
+ if object.has_key? "$ref"
330
+ DBRef.new(object["$ref"], object["$id"])
331
+ else
332
+ object
333
+ end
334
+ end
335
+
336
+ def deserialize_array_data(buf)
337
+ h = deserialize_object_data(buf)
338
+ a = []
339
+ h.each { |k, v| a[k.to_i] = v }
340
+ a
341
+ end
342
+
343
+ def deserialize_regex_data(buf)
344
+ str = deserialize_cstr(buf)
345
+ options_str = deserialize_cstr(buf)
346
+ opts = 0
347
+ opts |= Regexp::IGNORECASE if options_str.include?('i')
348
+ opts |= Regexp::MULTILINE if options_str.include?('m')
349
+ opts |= Regexp::MULTILINE if options_str.include?('s')
350
+ opts |= Regexp::EXTENDED if options_str.include?('x')
351
+ Regexp.new(str, opts)
352
+ end
353
+
354
+ def deserialize_timestamp_data(buf)
355
+ increment = buf.get_int
356
+ seconds = buf.get_int
357
+ Timestamp.new(seconds, increment)
358
+ end
359
+
360
+ def encoded_str(str)
361
+ if RUBY_VERSION >= '1.9'
362
+ str.force_encoding("utf-8")
363
+ if Encoding.default_internal
364
+ str.encode!(Encoding.default_internal)
365
+ end
366
+ end
367
+ str
368
+ end
369
+
370
+ def deserialize_string_data(buf)
371
+ len = buf.get_int
372
+ bytes = buf.get(len)
373
+ str = bytes[0..-2]
374
+ if str.respond_to? "pack"
375
+ str = str.pack("C*")
376
+ end
377
+ encoded_str(str)
378
+ end
379
+
380
+ def deserialize_code_w_scope_data(buf)
381
+ buf.get_int
382
+ len = buf.get_int
383
+ code = buf.get(len)[0..-2]
384
+ if code.respond_to? "pack"
385
+ code = code.pack("C*")
386
+ end
387
+
388
+ scope_size = buf.get_int
389
+ buf.position -= 4
390
+ scope = @encoder.new().deserialize(buf.get(scope_size))
391
+
392
+ Code.new(encoded_str(code), scope)
393
+ end
394
+
395
+ def deserialize_oid_data(buf)
396
+ ObjectId.new(buf.get(12))
397
+ end
398
+
399
+ def deserialize_dbref_data(buf)
400
+ ns = deserialize_string_data(buf)
401
+ oid = deserialize_oid_data(buf)
402
+ DBRef.new(ns, oid)
403
+ end
404
+
405
+ def deserialize_binary_data(buf)
406
+ len = buf.get_int
407
+ type = buf.get
408
+ len = buf.get_int if type == Binary::SUBTYPE_BYTES
409
+ Binary.new(buf.get(len), type)
410
+ end
411
+
412
+ def serialize_eoo_element(buf)
413
+ buf.put(EOO)
414
+ end
415
+
416
+ def serialize_null_element(buf, key)
417
+ buf.put(NULL)
418
+ self.class.serialize_key(buf, key)
419
+ end
420
+
421
+ def serialize_dbref_element(buf, key, val)
422
+ oh = BSON::OrderedHash.new
423
+ oh['$ref'] = val.namespace
424
+ oh['$id'] = val.object_id
425
+ serialize_object_element(buf, key, oh, false)
426
+ end
427
+
428
+ def serialize_binary_element(buf, key, val)
429
+ buf.put(BINARY)
430
+ self.class.serialize_key(buf, key)
431
+
432
+ bytes = val.to_a
433
+ num_bytes = bytes.length
434
+ subtype = val.respond_to?(:subtype) ? val.subtype : Binary::SUBTYPE_BYTES
435
+ if subtype == Binary::SUBTYPE_BYTES
436
+ buf.put_int(num_bytes + 4)
437
+ buf.put(subtype)
438
+ buf.put_int(num_bytes)
439
+ buf.put_array(bytes)
440
+ else
441
+ buf.put_int(num_bytes)
442
+ buf.put(subtype)
443
+ buf.put_array(bytes)
444
+ end
445
+ end
446
+
447
+ def serialize_boolean_element(buf, key, val)
448
+ buf.put(BOOLEAN)
449
+ self.class.serialize_key(buf, key)
450
+ buf.put(val ? 1 : 0)
451
+ end
452
+
453
+ def serialize_date_element(buf, key, val)
454
+ buf.put(DATE)
455
+ self.class.serialize_key(buf, key)
456
+ millisecs = (val.to_f * 1000).to_i
457
+ buf.put_long(millisecs)
458
+ end
459
+
460
+ def serialize_number_element(buf, key, val, type)
461
+ if type == NUMBER
462
+ buf.put(type)
463
+ self.class.serialize_key(buf, key)
464
+ buf.put_double(val)
465
+ else
466
+ if val > 2**64 / 2 - 1 or val < -2**64 / 2
467
+ raise RangeError.new("MongoDB can only handle 8-byte ints")
468
+ end
469
+ if val > 2**32 / 2 - 1 or val < -2**32 / 2
470
+ buf.put(NUMBER_LONG)
471
+ self.class.serialize_key(buf, key)
472
+ buf.put_long(val)
473
+ else
474
+ buf.put(type)
475
+ self.class.serialize_key(buf, key)
476
+ buf.put_int(val)
477
+ end
478
+ end
479
+ end
480
+
481
+ def serialize_object_element(buf, key, val, check_keys, opcode=OBJECT)
482
+ buf.put(opcode)
483
+ self.class.serialize_key(buf, key)
484
+ buf.put_array(@encoder.new.serialize(val, check_keys).to_a)
485
+ end
486
+
487
+ def serialize_array_element(buf, key, val, check_keys)
488
+ # Turn array into hash with integer indices as keys
489
+ h = BSON::OrderedHash.new
490
+ i = 0
491
+ val.each { |v| h[i] = v; i += 1 }
492
+ serialize_object_element(buf, key, h, check_keys, ARRAY)
493
+ end
494
+
495
+ def serialize_regex_element(buf, key, val)
496
+ buf.put(REGEX)
497
+ self.class.serialize_key(buf, key)
498
+
499
+ str = val.source
500
+ # We use serialize_key here since regex patterns aren't prefixed with
501
+ # length (can't contain the NULL byte).
502
+ self.class.serialize_key(buf, str)
503
+
504
+ options = val.options
505
+ options_str = ''
506
+ options_str << 'i' if ((options & Regexp::IGNORECASE) != 0)
507
+ if ((options & Regexp::MULTILINE) != 0)
508
+ options_str << 'm'
509
+ options_str << 's'
510
+ end
511
+ options_str << 'x' if ((options & Regexp::EXTENDED) != 0)
512
+ options_str << val.extra_options_str if val.respond_to?(:extra_options_str)
513
+ # Must store option chars in alphabetical order
514
+ self.class.serialize_cstr(buf, options_str.split(//).sort.uniq.join)
515
+ end
516
+
517
+ def serialize_max_key_element(buf, key)
518
+ buf.put(MAXKEY)
519
+ self.class.serialize_key(buf, key)
520
+ end
521
+
522
+ def serialize_min_key_element(buf, key)
523
+ buf.put(MINKEY)
524
+ self.class.serialize_key(buf, key)
525
+ end
526
+
527
+ def serialize_timestamp_element(buf, key, val)
528
+ buf.put(TIMESTAMP)
529
+ self.class.serialize_key(buf, key)
530
+
531
+ buf.put_int(val.increment)
532
+ buf.put_int(val.seconds)
533
+ end
534
+
535
+ def serialize_oid_element(buf, key, val)
536
+ buf.put(OID)
537
+ self.class.serialize_key(buf, key)
538
+
539
+ buf.put_array(val.to_a)
540
+ end
541
+
542
+ def serialize_string_element(buf, key, val, type)
543
+ buf.put(type)
544
+ self.class.serialize_key(buf, key)
545
+
546
+ # Make a hole for the length
547
+ len_pos = buf.position
548
+ buf.put_int(0)
549
+
550
+ # Save the string
551
+ start_pos = buf.position
552
+ self.class.serialize_cstr(buf, val)
553
+ end_pos = buf.position
554
+
555
+ # Put the string size in front
556
+ buf.put_int(end_pos - start_pos, len_pos)
557
+
558
+ # Go back to where we were
559
+ buf.position = end_pos
560
+ end
561
+
562
+ def serialize_code_w_scope(buf, key, val)
563
+ buf.put(CODE_W_SCOPE)
564
+ self.class.serialize_key(buf, key)
565
+
566
+ # Make a hole for the length
567
+ len_pos = buf.position
568
+ buf.put_int(0)
569
+
570
+ buf.put_int(val.code.length + 1)
571
+ self.class.serialize_cstr(buf, val.code)
572
+ buf.put_array(@encoder.new.serialize(val.scope).to_a)
573
+
574
+ end_pos = buf.position
575
+ buf.put_int(end_pos - len_pos, len_pos)
576
+ buf.position = end_pos
577
+ end
578
+
579
+ def deserialize_cstr(buf)
580
+ chars = ""
581
+ while true
582
+ b = buf.get
583
+ break if b == 0
584
+ chars << b.chr
585
+ end
586
+ encoded_str(chars)
587
+ end
588
+
589
+ def bson_type(o)
590
+ case o
591
+ when nil
592
+ NULL
593
+ when Integer
594
+ NUMBER_INT
595
+ when Float
596
+ NUMBER
597
+ when ByteBuffer
598
+ BINARY
599
+ when Code
600
+ CODE_W_SCOPE
601
+ when String
602
+ STRING
603
+ when Array
604
+ ARRAY
605
+ when Regexp
606
+ REGEX
607
+ when ObjectId
608
+ OID
609
+ when DBRef
610
+ REF
611
+ when true, false
612
+ BOOLEAN
613
+ when Time
614
+ DATE
615
+ when Hash
616
+ OBJECT
617
+ when Symbol
618
+ SYMBOL
619
+ when MaxKey
620
+ MAXKEY
621
+ when MinKey
622
+ MINKEY
623
+ when Timestamp
624
+ TIMESTAMP
625
+ when Numeric
626
+ raise InvalidDocument, "Cannot serialize the Numeric type #{o.class} as BSON; only Fixum, Bignum, and Float are supported."
627
+ when Date, DateTime
628
+ raise InvalidDocument, "#{o.class} is not currently supported; " +
629
+ "use a UTC Time instance instead."
630
+ else
631
+ if defined?(ActiveSupport::TimeWithZone) && o.is_a?(ActiveSupport::TimeWithZone)
632
+ raise InvalidDocument, "ActiveSupport::TimeWithZone is not currently supported; " +
633
+ "use a UTC Time instance instead."
634
+ else
635
+ raise InvalidDocument, "Cannot serialize #{o.class} as a BSON type; it either isn't supported or won't translate to BSON."
636
+ end
637
+ end
638
+ end
639
+
640
+ end
641
+ end