bson 1.12.5-java → 2.0.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.

Files changed (89) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/CHANGELOG.md +80 -0
  5. data/CONTRIBUTING.md +42 -0
  6. data/NOTICE +2 -0
  7. data/README.md +190 -0
  8. data/Rakefile +109 -0
  9. data/lib/bson-ruby.jar +0 -0
  10. data/lib/bson.rb +60 -87
  11. data/lib/bson/array.rb +104 -0
  12. data/lib/bson/binary.rb +193 -0
  13. data/lib/bson/boolean.rb +48 -0
  14. data/lib/bson/code.rb +109 -0
  15. data/lib/bson/code_with_scope.rb +120 -0
  16. data/lib/bson/document.rb +549 -0
  17. data/lib/bson/encodable.rb +86 -0
  18. data/lib/bson/environment.rb +98 -0
  19. data/lib/bson/false_class.rb +61 -0
  20. data/lib/bson/float.rb +82 -0
  21. data/lib/bson/hash.rb +84 -0
  22. data/lib/bson/int32.rb +59 -0
  23. data/lib/bson/int64.rb +59 -0
  24. data/lib/bson/integer.rb +185 -0
  25. data/lib/bson/json.rb +37 -0
  26. data/lib/bson/max_key.rb +70 -0
  27. data/lib/bson/min_key.rb +70 -0
  28. data/lib/bson/nil_class.rb +70 -0
  29. data/lib/bson/object_id.rb +395 -0
  30. data/lib/bson/regexp.rb +124 -0
  31. data/lib/bson/registry.rb +70 -0
  32. data/lib/bson/specialized.rb +74 -0
  33. data/lib/bson/string.rb +203 -0
  34. data/lib/bson/symbol.rb +87 -0
  35. data/lib/bson/time.rb +72 -0
  36. data/lib/bson/timestamp.rb +113 -0
  37. data/lib/bson/true_class.rb +61 -0
  38. data/lib/bson/undefined.rb +74 -0
  39. data/lib/bson/version.rb +17 -0
  40. data/spec/bson/array_spec.rb +58 -0
  41. data/spec/bson/binary_spec.rb +115 -0
  42. data/spec/bson/boolean_spec.rb +48 -0
  43. data/spec/bson/code_spec.rb +42 -0
  44. data/spec/bson/code_with_scope_spec.rb +74 -0
  45. data/spec/bson/document_spec.rb +778 -0
  46. data/spec/bson/false_class_spec.rb +28 -0
  47. data/spec/bson/float_spec.rb +29 -0
  48. data/spec/bson/hash_spec.rb +56 -0
  49. data/spec/bson/int32_spec.rb +28 -0
  50. data/spec/bson/int64_spec.rb +28 -0
  51. data/spec/bson/integer_spec.rb +76 -0
  52. data/spec/bson/json_spec.rb +53 -0
  53. data/spec/bson/max_key_spec.rb +75 -0
  54. data/spec/bson/min_key_spec.rb +75 -0
  55. data/spec/bson/nil_class_spec.rb +29 -0
  56. data/spec/bson/object_id_spec.rb +527 -0
  57. data/spec/bson/regexp_spec.rb +89 -0
  58. data/spec/bson/registry_spec.rb +55 -0
  59. data/spec/bson/string_spec.rb +298 -0
  60. data/spec/bson/symbol_spec.rb +55 -0
  61. data/spec/bson/time_spec.rb +43 -0
  62. data/spec/bson/timestamp_spec.rb +74 -0
  63. data/spec/bson/true_class_spec.rb +28 -0
  64. data/spec/bson/undefined_spec.rb +29 -0
  65. data/{lib/bson/types/dbref.rb → spec/bson_spec.rb} +22 -16
  66. data/spec/spec_helper.rb +32 -0
  67. data/spec/support/shared_examples.rb +95 -0
  68. metadata +116 -48
  69. metadata.gz.sig +1 -1
  70. data/VERSION +0 -1
  71. data/bin/b2json +0 -63
  72. data/bin/j2bson +0 -64
  73. data/bson.gemspec +0 -34
  74. data/ext/jbson/lib/java-bson.jar +0 -0
  75. data/ext/jbson/target/jbson.jar +0 -0
  76. data/lib/bson/bson_c.rb +0 -37
  77. data/lib/bson/bson_java.rb +0 -49
  78. data/lib/bson/bson_ruby.rb +0 -645
  79. data/lib/bson/byte_buffer.rb +0 -241
  80. data/lib/bson/exceptions.rb +0 -37
  81. data/lib/bson/grow.rb +0 -173
  82. data/lib/bson/ordered_hash.rb +0 -197
  83. data/lib/bson/support/hash_with_indifferent_access.rb +0 -174
  84. data/lib/bson/types/binary.rb +0 -52
  85. data/lib/bson/types/code.rb +0 -55
  86. data/lib/bson/types/min_max_keys.rb +0 -56
  87. data/lib/bson/types/object_id.rb +0 -226
  88. data/lib/bson/types/regex.rb +0 -116
  89. data/lib/bson/types/timestamp.rb +0 -72
metadata.gz.sig CHANGED
@@ -1 +1 @@
1
- di4U���xm43��rX�=� �!agc,�>��O���݌e���l5h���Ï�еlj��^� �*�,�Tl��KRТmer3 ɹ���<<������}��1DPJM���&��3���x�
1
+ ���T����jI�:`�kQ5���Ӟ6`�<Z���0r�|�V�|95Ɣ��/x.�._{^�G��� q̺�@q��{I���Ip��k��C#2YP+�:�
data/VERSION DELETED
@@ -1 +0,0 @@
1
- 1.12.5
data/bin/b2json DELETED
@@ -1,63 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # encoding: UTF-8
3
-
4
- # Copyright (C) 2009-2013 MongoDB, 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
- require 'rubygems'
19
- require 'bson'
20
-
21
- # Note that this will not properly round-trip in all cases
22
- # from the output generated by j2bson.
23
- begin
24
- require 'yajl'
25
- rescue LoadError
26
- puts "This script requires yajl. Please install as follows:"
27
- puts " gem install yajl-ruby"
28
- Process.exit
29
- end
30
-
31
- # Convert all documents in an IO into JSON.
32
- def print_b2json(io)
33
- while not io.eof? do
34
- bsonobj = BSON.read_bson_document(io)
35
- Yajl::Encoder.encode(bsonobj, STDOUT)
36
- STDOUT << "\n"
37
- end
38
- end
39
-
40
- # print usage
41
- def usage()
42
- STDERR << <<END_OF_USAGE
43
- usage: b2json [-h] [file1 [file2]]
44
-
45
- Converts a BSON file to JSON on STDOUT.
46
- You can pass multiple filenames.
47
- If no filenames are passed, then STDIN is consumed.
48
-
49
- END_OF_USAGE
50
- exit
51
- end
52
-
53
- # no arg, use STDIN
54
- # -h, print usage and exit
55
- # otherwise loop of filenames
56
- if ARGV.empty? then
57
- print_b2json(STDIN)
58
- exit
59
- elsif ARGV[0] == "-h" then
60
- usage()
61
- else
62
- ARGV.each { |fname| print_b2json(File.new(fname)) }
63
- end
data/bin/j2bson DELETED
@@ -1,64 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # encoding: UTF-8
3
-
4
- # Copyright (C) 2009-2013 MongoDB, 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
- require 'rubygems'
19
- require 'bson'
20
-
21
- # Note that, at the moment, this will not properly round-trip
22
- # in all cases from the output generated by b2json.
23
- begin
24
- require 'json/pure' # broken with 'json/ext'
25
- rescue LoadError
26
- puts "This script requires json/pure. Please install one of the following:"
27
- puts " gem install json_pure"
28
- puts " gem install json"
29
- Process.exit
30
- end
31
-
32
- # Convert all JSON objects in an IO into BSON.
33
- def print_j2bson(io)
34
- io.each_line do |line|
35
- jsonobj = JSON.parse(line, { :object_class => BSON::OrderedHash } )
36
- bsonobj = BSON.serialize(jsonobj)
37
- STDOUT << bsonobj.to_s
38
- end
39
- end
40
-
41
- # print usage
42
- def usage()
43
- STDERR << <<END_OF_USAGE
44
- usage: j2bson [-h] [file1 [file2]]
45
-
46
- Converts a JSON file to BSON on STDOUT.
47
- You can pass multiple filenames.
48
- If no filenames are passed, then STDIN is consumed.
49
-
50
- END_OF_USAGE
51
- exit
52
- end
53
-
54
- # no arg, use STDIN
55
- # -h, print usage and exit
56
- # otherwise loop of filenames
57
- if ARGV.empty? then
58
- print_j2bson(STDIN)
59
- exit
60
- elsif ARGV[0] == "-h" then
61
- usage()
62
- else
63
- ARGV.each { |fname| print_j2bson(File.new(fname)) }
64
- end
@@ -1,34 +0,0 @@
1
- Gem::Specification.new do |s|
2
- s.name = 'bson'
3
-
4
- s.version = File.read(File.join(File.dirname(__FILE__), 'VERSION'))
5
- s.authors = ['Emily Stolfo', 'Durran Jordan', 'Gary Murakami', 'Tyler Brock', 'Brandon Black']
6
- s.email = 'mongodb-dev@googlegroups.com'
7
- s.homepage = 'http://www.mongodb.org'
8
- s.summary = 'Ruby implementation of BSON'
9
- s.description = 'A Ruby BSON implementation for MongoDB. For more information about Mongo, see http://www.mongodb.org. For more information on BSON, see http://www.bsonspec.org.'
10
- s.rubyforge_project = 'bson'
11
- s.license = 'Apache License Version 2.0'
12
-
13
- if File.exists?('gem-private_key.pem')
14
- s.signing_key = 'gem-private_key.pem'
15
- s.cert_chain = ['gem-public_cert.pem']
16
- else
17
- warn 'Warning: No private key present, creating unsigned gem.'
18
- end
19
-
20
- s.files = ['bson.gemspec', 'LICENSE', 'VERSION']
21
- s.files += ['bin/b2json', 'bin/j2bson', 'lib/bson.rb']
22
- s.files += Dir['lib/bson/**/*.rb']
23
-
24
- if RUBY_PLATFORM =~ /java/
25
- s.platform = 'java'
26
- s.files += ['ext/jbson/target/jbson.jar', 'ext/jbson/lib/java-bson.jar']
27
- else
28
- s.platform = Gem::Platform::RUBY
29
- end
30
-
31
- s.executables = ['b2json', 'j2bson']
32
- s.require_paths = ['lib']
33
- s.has_rdoc = 'yard'
34
- end
Binary file
Binary file
@@ -1,37 +0,0 @@
1
- # Copyright (C) 2009-2013 MongoDB, Inc.
2
- #
3
- # Licensed under the Apache License, Version 2.0 (the "License");
4
- # you may not use this file except in compliance with the License.
5
- # You may obtain a copy of the License at
6
- #
7
- # http://www.apache.org/licenses/LICENSE-2.0
8
- #
9
- # Unless required by applicable law or agreed to in writing, software
10
- # distributed under the License is distributed on an "AS IS" BASIS,
11
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- # See the License for the specific language governing permissions and
13
- # limitations under the License.
14
-
15
- # A thin wrapper for the BSON C-Extension
16
- module BSON
17
- class BSON_C
18
-
19
- def self.serialize(obj, check_keys=false, move_id=false, max_bson_size=DEFAULT_MAX_BSON_SIZE)
20
- ByteBuffer.new(CBson.serialize(obj, check_keys, move_id, max_bson_size))
21
- end
22
-
23
- def self.deserialize(buf=nil, opts={})
24
- CBson.deserialize(ByteBuffer.new(buf).to_s, opts)
25
- end
26
-
27
- def self.max_bson_size
28
- warn "BSON::BSON_CODER.max_bson_size is deprecated and will be removed in v2.0."
29
- CBson.max_bson_size
30
- end
31
-
32
- def self.update_max_bson_size(connection)
33
- warn "BSON::BSON_CODER.update_max_bson_size is deprecated and now a no-op. It will be removed in v2.0."
34
- CBson.update_max_bson_size(connection)
35
- end
36
- end
37
- end
@@ -1,49 +0,0 @@
1
- # Copyright (C) 2009-2013 MongoDB, Inc.
2
- #
3
- # Licensed under the Apache License, Version 2.0 (the "License");
4
- # you may not use this file except in compliance with the License.
5
- # You may obtain a copy of the License at
6
- #
7
- # http://www.apache.org/licenses/LICENSE-2.0
8
- #
9
- # Unless required by applicable law or agreed to in writing, software
10
- # distributed under the License is distributed on an "AS IS" BASIS,
11
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- # See the License for the specific language governing permissions and
13
- # limitations under the License.
14
-
15
- require 'jruby'
16
-
17
- include Java
18
-
19
- jar_dir = File.expand_path(File.join(File.dirname(__FILE__), '../../ext/jbson'))
20
- require File.join(jar_dir, 'lib/java-bson.jar')
21
- require File.join(jar_dir, 'target/jbson.jar')
22
-
23
- module BSON
24
- class BSON_JAVA
25
- def self.serialize(obj, check_keys=false, move_id=false, max_bson_size=DEFAULT_MAX_BSON_SIZE)
26
- raise InvalidDocument, "BSON_JAVA.serialize takes a Hash" unless obj.is_a?(Hash)
27
- enc = Java::OrgJbson::RubyBSONEncoder.new(JRuby.runtime, check_keys, move_id, max_bson_size)
28
- ByteBuffer.new(enc.encode(obj))
29
- end
30
-
31
- def self.deserialize(buf, opts={})
32
- dec = Java::OrgJbson::RubyBSONDecoder.new
33
- callback = Java::OrgJbson::RubyBSONCallback.new(JRuby.runtime)
34
- callback.set_opts(opts);
35
- dec.decode(buf.to_s.to_java_bytes, callback)
36
- callback.get
37
- end
38
-
39
- def self.max_bson_size
40
- warn "BSON::BSON_CODER.max_bson_size is deprecated and will be removed in v2.0."
41
- Java::OrgJbson::RubyBSONEncoder.max_bson_size(self)
42
- end
43
-
44
- def self.update_max_bson_size(connection)
45
- warn "BSON::BSON_CODER.update_max_bson_size is deprecated and now a no-op. It will be removed in v2.0."
46
- Java::OrgJbson::RubyBSONEncoder.update_max_bson_size(self, connection)
47
- end
48
- end
49
- end
@@ -1,645 +0,0 @@
1
- # Copyright (C) 2009-2013 MongoDB, Inc.
2
- #
3
- # Licensed under the Apache License, Version 2.0 (the "License");
4
- # you may not use this file except in compliance with the License.
5
- # You may obtain a copy of the License at
6
- #
7
- # http://www.apache.org/licenses/LICENSE-2.0
8
- #
9
- # Unless required by applicable law or agreed to in writing, software
10
- # distributed under the License is distributed on an "AS IS" BASIS,
11
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- # See the License for the specific language governing permissions and
13
- # limitations under the License.
14
-
15
- module BSON
16
- NULL_BYTE = "\x00"
17
-
18
- # A BSON seralizer/deserializer in pure Ruby.
19
- class BSON_RUBY
20
- @@max_bson_size = DEFAULT_MAX_BSON_SIZE
21
-
22
- MINKEY = -1
23
- EOO = 0
24
- NUMBER = 1
25
- STRING = 2
26
- OBJECT = 3
27
- ARRAY = 4
28
- BINARY = 5
29
- UNDEFINED = 6
30
- OID = 7
31
- BOOLEAN = 8
32
- DATE = 9
33
- NULL = 10
34
- REGEX = 11
35
- REF = 12
36
- CODE = 13
37
- SYMBOL = 14
38
- CODE_W_SCOPE = 15
39
- NUMBER_INT = 16
40
- TIMESTAMP = 17
41
- NUMBER_LONG = 18
42
- MAXKEY = 127
43
-
44
- INT32_MIN = -(1 << 31) + 1
45
- INT32_MAX = (1 << 31) - 1
46
- INT64_MIN = -2**64 / 2
47
- INT64_MAX = 2**64 / 2 - 1
48
-
49
- def initialize(max_bson_size=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
- UTF8_ENCODING = Encoding.find('utf-8')
56
- BINARY_ENCODING = Encoding.find('binary')
57
-
58
- def self.to_utf8_binary(str)
59
- begin
60
- str.unpack("U*")
61
- rescue
62
- raise InvalidStringEncoding, "String not valid utf-8: #{str.inspect}"
63
- end
64
- str.dup.force_encoding(BINARY_ENCODING)
65
- end
66
- else
67
- def self.to_utf8_binary(str)
68
- begin
69
- str.unpack("U*")
70
- rescue
71
- raise InvalidStringEncoding, "String not valid utf-8: #{str.inspect}"
72
- end
73
- str
74
- end
75
- end
76
-
77
- def self.update_max_bson_size(connection)
78
- warn "BSON::BSON_CODER.update_max_bson_size is deprecated and now a no-op. It will be removed in v2.0."
79
- @@max_bson_size = connection.max_bson_size
80
- end
81
-
82
- def self.max_bson_size
83
- warn "BSON::BSON_CODER.max_bson_size is deprecated and will be removed in v2.0."
84
- @@max_bson_size
85
- end
86
-
87
- def self.serialize_cstr(buf, val)
88
- buf.put_binary(to_utf8_binary(val.to_s))
89
- buf.put_binary(NULL_BYTE)
90
- end
91
-
92
- def self.serialize_key(buf, key)
93
- raise InvalidDocument, "Key names / regex patterns must not contain the NULL byte" if key.include? "\x00"
94
- self.serialize_cstr(buf, key)
95
- end
96
-
97
- def to_a
98
- @buf.to_a
99
- end
100
-
101
- def to_s
102
- @buf.to_s
103
- end
104
-
105
- # Serializes an object.
106
- # Implemented to ensure an API compatible with BSON extension.
107
- def self.serialize(obj, check_keys=false, move_id=false, max_bson_size=DEFAULT_MAX_BSON_SIZE)
108
- new(max_bson_size).serialize(obj, check_keys, move_id)
109
- end
110
-
111
- def self.deserialize(buf=nil, opts={})
112
- new.deserialize(buf, opts)
113
- end
114
-
115
- def serialize(obj, check_keys=false, move_id=false)
116
- raise(InvalidDocument, "BSON.serialize takes a Hash but got a #{obj.class}") unless obj.is_a?(Hash)
117
- raise "Document is null" unless obj
118
-
119
- @buf.rewind
120
- # put in a placeholder for the total size
121
- @buf.put_int(0)
122
-
123
- # Write key/value pairs. Always write _id first if it exists.
124
- if move_id
125
- if obj.has_key? '_id'
126
- serialize_key_value('_id', obj['_id'], false)
127
- elsif obj.has_key? :_id
128
- serialize_key_value('_id', obj[:_id], false)
129
- end
130
- obj.each {|k, v| serialize_key_value(k, v, check_keys) unless k == '_id' || k == :_id }
131
- else
132
- if obj.has_key?('_id') && obj.has_key?(:_id)
133
- obj['_id'] = obj.delete(:_id)
134
- end
135
- obj.each {|k, v| serialize_key_value(k, v, check_keys) }
136
- end
137
-
138
- serialize_eoo_element(@buf)
139
- if @buf.size > @buf.max_size
140
- raise InvalidDocument, "Document is too large (#{@buf.size}). " +
141
- "This BSON document is limited to #{@buf.max_size} bytes."
142
- end
143
- @buf.put_int(@buf.size, 0)
144
- @buf
145
- end
146
-
147
- # Returns the array stored in the buffer.
148
- # Implemented to ensure an API compatible with BSON extension.
149
- def unpack
150
- @buf.to_a
151
- end
152
-
153
- def serialize_key_value(k, v, check_keys)
154
- k = k.to_s
155
- if check_keys
156
- if k[0] == ?$
157
- raise InvalidKeyName.new("key #{k} must not start with '$'")
158
- end
159
- if k.include? ?.
160
- raise InvalidKeyName.new("key #{k} must not contain '.'")
161
- end
162
- end
163
- type = bson_type(v)
164
- case type
165
- when STRING, SYMBOL
166
- serialize_string_element(@buf, k, v, type)
167
- when NUMBER, NUMBER_INT
168
- serialize_number_element(@buf, k, v, type)
169
- when OBJECT
170
- serialize_object_element(@buf, k, v, check_keys)
171
- when OID
172
- serialize_oid_element(@buf, k, v)
173
- when ARRAY
174
- serialize_array_element(@buf, k, v, check_keys)
175
- when REGEX
176
- serialize_regex_element(@buf, k, v)
177
- when BOOLEAN
178
- serialize_boolean_element(@buf, k, v)
179
- when DATE
180
- serialize_date_element(@buf, k, v)
181
- when NULL
182
- serialize_null_element(@buf, k)
183
- when REF
184
- serialize_dbref_element(@buf, k, v)
185
- when BINARY
186
- serialize_binary_element(@buf, k, v)
187
- when UNDEFINED
188
- serialize_null_element(@buf, k)
189
- when CODE_W_SCOPE
190
- serialize_code_w_scope(@buf, k, v)
191
- when MAXKEY
192
- serialize_max_key_element(@buf, k)
193
- when MINKEY
194
- serialize_min_key_element(@buf, k)
195
- when TIMESTAMP
196
- serialize_timestamp_element(@buf, k, v)
197
- else
198
- raise "unhandled type #{type}"
199
- end
200
- end
201
-
202
- def deserialize(buf=nil, opts={})
203
- # If buf is nil, use @buf, assumed to contain already-serialized BSON.
204
- # This is only true during testing.
205
- if buf.is_a? String
206
- @buf = ByteBuffer.new(buf.unpack("C*")) if buf
207
- else
208
- @buf = ByteBuffer.new(buf.to_a) if buf
209
- end
210
- @buf.rewind
211
- @buf.get_int # eat message size
212
- doc = BSON::OrderedHash.new
213
- while @buf.more?
214
- type = @buf.get
215
- case type
216
- when STRING, CODE
217
- key = deserialize_cstr(@buf)
218
- doc[key] = deserialize_string_data(@buf)
219
- when SYMBOL
220
- key = deserialize_cstr(@buf)
221
- doc[key] = deserialize_string_data(@buf).intern
222
- when NUMBER
223
- key = deserialize_cstr(@buf)
224
- doc[key] = deserialize_number_data(@buf)
225
- when NUMBER_INT
226
- key = deserialize_cstr(@buf)
227
- doc[key] = deserialize_number_int_data(@buf)
228
- when NUMBER_LONG
229
- key = deserialize_cstr(@buf)
230
- doc[key] = deserialize_number_long_data(@buf)
231
- when OID
232
- key = deserialize_cstr(@buf)
233
- doc[key] = deserialize_oid_data(@buf)
234
- when ARRAY
235
- key = deserialize_cstr(@buf)
236
- doc[key] = deserialize_array_data(@buf, opts)
237
- when REGEX
238
- key = deserialize_cstr(@buf)
239
- doc[key] = deserialize_regex_data(@buf, opts)
240
- when OBJECT
241
- key = deserialize_cstr(@buf)
242
- doc[key] = deserialize_object_data(@buf, opts)
243
- when BOOLEAN
244
- key = deserialize_cstr(@buf)
245
- doc[key] = deserialize_boolean_data(@buf)
246
- when DATE
247
- key = deserialize_cstr(@buf)
248
- doc[key] = deserialize_date_data(@buf)
249
- when NULL
250
- key = deserialize_cstr(@buf)
251
- doc[key] = nil
252
- when UNDEFINED
253
- key = deserialize_cstr(@buf)
254
- doc[key] = nil
255
- when REF
256
- key = deserialize_cstr(@buf)
257
- doc[key] = deserialize_dbref_data(@buf)
258
- when BINARY
259
- key = deserialize_cstr(@buf)
260
- doc[key] = deserialize_binary_data(@buf)
261
- when CODE_W_SCOPE
262
- key = deserialize_cstr(@buf)
263
- doc[key] = deserialize_code_w_scope_data(@buf)
264
- when TIMESTAMP
265
- key = deserialize_cstr(@buf)
266
- doc[key] = deserialize_timestamp_data(@buf)
267
- when MAXKEY
268
- key = deserialize_cstr(@buf)
269
- doc[key] = MaxKey.new
270
- when MINKEY, 255 # This is currently easier than unpack the type byte as an unsigned char.
271
- key = deserialize_cstr(@buf)
272
- doc[key] = MinKey.new
273
- when EOO
274
- break
275
- else
276
- raise "Unknown type #{type}, key = #{key}"
277
- end
278
- end
279
- @buf.rewind
280
- doc
281
- end
282
-
283
- # For debugging.
284
- def hex_dump
285
- str = ''
286
- @buf.to_a.each_with_index { |b,i|
287
- if (i % 8) == 0
288
- str << "\n" if i > 0
289
- str << '%4d: ' % i
290
- else
291
- str << ' '
292
- end
293
- str << '%02X' % b
294
- }
295
- str
296
- end
297
-
298
- def deserialize_date_data(buf)
299
- milliseconds = buf.get_long
300
- Time.at(milliseconds.to_f / 1000.0).utc # at() takes fractional seconds
301
- end
302
-
303
- def deserialize_boolean_data(buf)
304
- buf.get == 1
305
- end
306
-
307
- def deserialize_number_data(buf)
308
- buf.get_double
309
- end
310
-
311
- def deserialize_number_int_data(buf)
312
- buf.get_int
313
- end
314
-
315
- def deserialize_number_long_data(buf)
316
- buf.get_long
317
- end
318
-
319
- def deserialize_object_data(buf, opts={})
320
- size = buf.get_int
321
- buf.position -= 4
322
- object = @encoder.new.deserialize(buf.get(size), opts)
323
- if object.has_key? "$ref"
324
- DBRef.new(object["$ref"], object["$id"])
325
- else
326
- object
327
- end
328
- end
329
-
330
- def deserialize_array_data(buf, opts={})
331
- h = deserialize_object_data(buf, opts)
332
- a = []
333
- h.each { |k, v| a[k.to_i] = v }
334
- a
335
- end
336
-
337
- def deserialize_regex_data(buf, opts={})
338
- compile = opts.key?(:compile_regex) ? opts[:compile_regex] : true
339
- compile = true if compile.nil?
340
- str = deserialize_cstr(buf)
341
- options_str = deserialize_cstr(buf)
342
- bson_regex = BSON::Regex.new(str, options_str)
343
- compile ? bson_regex.try_compile : bson_regex
344
- end
345
-
346
- def deserialize_timestamp_data(buf)
347
- increment = buf.get_int
348
- seconds = buf.get_int
349
- Timestamp.new(seconds, increment)
350
- end
351
-
352
- def encoded_str(str)
353
- if RUBY_VERSION >= '1.9'
354
- str.force_encoding("utf-8")
355
- if Encoding.default_internal
356
- str.encode!(Encoding.default_internal)
357
- end
358
- end
359
- str
360
- end
361
-
362
- def deserialize_string_data(buf)
363
- len = buf.get_int
364
- bytes = buf.get(len)
365
- str = bytes[0..-2]
366
- if str.respond_to? "pack"
367
- str = str.pack("C*")
368
- end
369
- encoded_str(str)
370
- end
371
-
372
- def deserialize_code_w_scope_data(buf, opts={})
373
- buf.get_int
374
- len = buf.get_int
375
- code = buf.get(len)[0..-2]
376
- if code.respond_to? "pack"
377
- code = code.pack("C*")
378
- end
379
-
380
- scope_size = buf.get_int
381
- buf.position -= 4
382
- scope = @encoder.new.deserialize(buf.get(scope_size), opts)
383
-
384
- Code.new(encoded_str(code), scope)
385
- end
386
-
387
- def deserialize_oid_data(buf)
388
- ObjectId.new(buf.get(12))
389
- end
390
-
391
- def deserialize_dbref_data(buf)
392
- ns = deserialize_string_data(buf)
393
- oid = deserialize_oid_data(buf)
394
- DBRef.new(ns, oid)
395
- end
396
-
397
- def deserialize_binary_data(buf)
398
- len = buf.get_int
399
- type = buf.get
400
- len = buf.get_int if type == Binary::SUBTYPE_BYTES
401
- Binary.new(buf.get(len), type)
402
- end
403
-
404
- def serialize_eoo_element(buf)
405
- buf.put(EOO)
406
- end
407
-
408
- def serialize_null_element(buf, key)
409
- buf.put(NULL)
410
- self.class.serialize_key(buf, key)
411
- end
412
-
413
- def serialize_dbref_element(buf, key, val) # this does NOT use the BSON "\x0C" DBPointer type
414
- oh = BSON::OrderedHash.new
415
- oh['$ref'] = val.namespace
416
- oh['$id'] = val.object_id
417
- serialize_object_element(buf, key, oh, false)
418
- end
419
-
420
- def serialize_binary_element(buf, key, val)
421
- buf.put(BINARY)
422
- self.class.serialize_key(buf, key)
423
-
424
- bytes = val.to_a
425
- num_bytes = bytes.length
426
- subtype = val.respond_to?(:subtype) ? val.subtype : Binary::SUBTYPE_BYTES
427
- if subtype == Binary::SUBTYPE_BYTES
428
- buf.put_int(num_bytes + 4)
429
- buf.put(subtype)
430
- buf.put_int(num_bytes)
431
- buf.put_array(bytes)
432
- else
433
- buf.put_int(num_bytes)
434
- buf.put(subtype)
435
- buf.put_array(bytes)
436
- end
437
- end
438
-
439
- def serialize_boolean_element(buf, key, val)
440
- buf.put(BOOLEAN)
441
- self.class.serialize_key(buf, key)
442
- buf.put(val ? 1 : 0)
443
- end
444
-
445
- def serialize_date_element(buf, key, val)
446
- buf.put(DATE)
447
- self.class.serialize_key(buf, key)
448
- millisecs = (val.to_f * 1000).to_i
449
- buf.put_long(millisecs)
450
- end
451
-
452
- def serialize_number_element(buf, key, val, type)
453
- if type == NUMBER
454
- buf.put(type)
455
- self.class.serialize_key(buf, key)
456
- buf.put_double(val)
457
- else
458
- if val > INT64_MAX or val < INT64_MIN
459
- raise RangeError.new("MongoDB can only handle 8-byte ints")
460
- end
461
- if val > INT32_MAX or val < INT32_MIN
462
- buf.put(NUMBER_LONG)
463
- self.class.serialize_key(buf, key)
464
- buf.put_long(val)
465
- else
466
- buf.put(type)
467
- self.class.serialize_key(buf, key)
468
- buf.put_int(val)
469
- end
470
- end
471
- end
472
-
473
- def serialize_object_element(buf, key, val, check_keys, opcode=OBJECT)
474
- buf.put(opcode)
475
- self.class.serialize_key(buf, key)
476
- buf.put_array(@encoder.new.serialize(val, check_keys).to_a)
477
- end
478
-
479
- def serialize_array_element(buf, key, val, check_keys)
480
- # Turn array into hash with integer indices as keys
481
- h = BSON::OrderedHash.new
482
- i = 0
483
- val.each { |v| h[i] = v; i += 1 }
484
- serialize_object_element(buf, key, h, check_keys, ARRAY)
485
- end
486
-
487
- def serialize_regex_element(buf, key, val)
488
- buf.put(REGEX)
489
- self.class.serialize_key(buf, key)
490
-
491
- str = val.source
492
- # We use serialize_key here since regex patterns aren't prefixed with
493
- # length (can't contain the NULL byte).
494
- self.class.serialize_key(buf, str)
495
-
496
- options = val.options
497
- options_str = ''
498
-
499
- if val.is_a?(BSON::Regex)
500
- options_str << 'i' if ((options & BSON::Regex::IGNORECASE) != 0)
501
- options_str << 'l' if ((options & BSON::Regex::LOCALE_DEPENDENT) != 0)
502
- options_str << 'm' if ((options & BSON::Regex::MULTILINE) != 0)
503
- options_str << 's' if ((options & BSON::Regex::DOTALL) != 0)
504
- options_str << 'u' if ((options & BSON::Regex::UNICODE) != 0)
505
- options_str << 'x' if ((options & BSON::Regex::EXTENDED) != 0)
506
- else
507
- options_str << 'm' # Ruby regular expressions always use multiline mode
508
- options_str << 'i' if ((options & Regexp::IGNORECASE) != 0)
509
- # dotall on the server is multiline in Ruby
510
- options_str << 's' if ((options & Regexp::MULTILINE) != 0)
511
- options_str << 'x' if ((options & Regexp::EXTENDED) != 0)
512
- end
513
-
514
- options_str << val.extra_options_str if val.respond_to?(:extra_options_str)
515
- # Must store option chars in alphabetical order
516
- self.class.serialize_cstr(buf, options_str.split(//).sort.uniq.join)
517
- end
518
-
519
- def serialize_max_key_element(buf, key)
520
- buf.put(MAXKEY)
521
- self.class.serialize_key(buf, key)
522
- end
523
-
524
- def serialize_min_key_element(buf, key)
525
- buf.put(MINKEY)
526
- self.class.serialize_key(buf, key)
527
- end
528
-
529
- def serialize_timestamp_element(buf, key, val)
530
- buf.put(TIMESTAMP)
531
- self.class.serialize_key(buf, key)
532
-
533
- buf.put_int(val.increment)
534
- buf.put_int(val.seconds)
535
- end
536
-
537
- def serialize_oid_element(buf, key, val)
538
- buf.put(OID)
539
- self.class.serialize_key(buf, key)
540
-
541
- buf.put_array(val.to_a)
542
- end
543
-
544
- def serialize_string_element(buf, key, val, type)
545
- buf.put(type)
546
- self.class.serialize_key(buf, key)
547
-
548
- # Make a hole for the length
549
- len_pos = buf.position
550
- buf.put_int(0)
551
-
552
- # Save the string
553
- start_pos = buf.position
554
- self.class.serialize_cstr(buf, val)
555
- end_pos = buf.position
556
-
557
- # Put the string size in front
558
- buf.put_int(end_pos - start_pos, len_pos)
559
-
560
- # Go back to where we were
561
- buf.position = end_pos
562
- end
563
-
564
- def serialize_code_w_scope(buf, key, val)
565
- buf.put(CODE_W_SCOPE)
566
- self.class.serialize_key(buf, key)
567
-
568
- # Make a hole for the length
569
- len_pos = buf.position
570
- buf.put_int(0)
571
-
572
- buf.put_int(val.code.length + 1)
573
- self.class.serialize_cstr(buf, val.code)
574
- buf.put_array(@encoder.new.serialize(val.scope).to_a)
575
-
576
- end_pos = buf.position
577
- buf.put_int(end_pos - len_pos, len_pos)
578
- buf.position = end_pos
579
- end
580
-
581
- def deserialize_cstr(buf)
582
- chars = ""
583
- while true
584
- b = buf.get
585
- break if b == 0
586
- chars << b.chr
587
- end
588
- encoded_str(chars)
589
- end
590
-
591
- def bson_type(o)
592
- case o
593
- when nil
594
- NULL
595
- when Integer
596
- NUMBER_INT
597
- when Float
598
- NUMBER
599
- when ByteBuffer
600
- BINARY
601
- when Code
602
- CODE_W_SCOPE
603
- when String
604
- STRING
605
- when Array
606
- ARRAY
607
- when Regexp, BSON::Regex
608
- REGEX
609
- when ObjectId
610
- OID
611
- when DBRef
612
- REF
613
- when true, false
614
- BOOLEAN
615
- when Time
616
- DATE
617
- when Hash
618
- OBJECT
619
- when Symbol
620
- SYMBOL
621
- when MaxKey
622
- MAXKEY
623
- when MinKey
624
- MINKEY
625
- when Timestamp
626
- TIMESTAMP
627
- when Numeric
628
- raise InvalidDocument, "Cannot serialize the Numeric type #{o.class} as BSON; only Fixum, Bignum, and Float are supported."
629
- when Date, DateTime
630
- raise InvalidDocument, "#{o.class} is not currently supported; " +
631
- "use a UTC Time instance instead."
632
- else
633
- if defined?(ActiveSupport::Multibyte::Chars) && o.is_a?(ActiveSupport::Multibyte::Chars)
634
- STRING
635
- elsif defined?(ActiveSupport::TimeWithZone) && o.is_a?(ActiveSupport::TimeWithZone)
636
- raise InvalidDocument, "ActiveSupport::TimeWithZone is not currently supported; " +
637
- "use a UTC Time instance instead."
638
- else
639
- raise InvalidDocument, "Cannot serialize #{o.class} as a BSON type; it either isn't supported or won't translate to BSON."
640
- end
641
- end
642
- end
643
-
644
- end
645
- end