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
@@ -0,0 +1,120 @@
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
+
17
+ # Represents a code with scope, which is a wrapper around javascript code
18
+ # with variable scope provided.
19
+ #
20
+ # @see http://bsonspec.org/#/specification
21
+ #
22
+ # @since 2.0.0
23
+ class CodeWithScope
24
+ include Encodable
25
+ include JSON
26
+
27
+ # A code with scope is type 0x0F in the BSON spec.
28
+ #
29
+ # @since 2.0.0
30
+ BSON_TYPE = 15.chr.force_encoding(BINARY).freeze
31
+
32
+ # @!attribute javascript
33
+ # @return [ String ] The javascript code.
34
+ # @since 2.0.0
35
+ # @!attribute scope
36
+ # @return [ Hash ] The variable scope.
37
+ # @since 2.0.0
38
+ attr_reader :javascript, :scope
39
+
40
+ # Determine if this code with scope object is equal to another object.
41
+ #
42
+ # @example Check the code with scope equality.
43
+ # code_with_scope == other
44
+ #
45
+ # @param [ Object ] other The object to compare against.
46
+ #
47
+ # @return [ true, false ] If the objects are equal.
48
+ #
49
+ # @since 2.0.0
50
+ def ==(other)
51
+ return false unless other.is_a?(CodeWithScope)
52
+ javascript == other.javascript && scope == other.scope
53
+ end
54
+
55
+ # Get the code with scope as JSON hash data.
56
+ #
57
+ # @example Get the code with scope as a JSON hash.
58
+ # code_with_scope.as_json
59
+ #
60
+ # @return [ Hash ] The code with scope as a JSON hash.
61
+ #
62
+ # @since 2.0.0
63
+ def as_json(*args)
64
+ { "$code" => javascript, "$scope" => scope }
65
+ end
66
+
67
+ # Instantiate the new code with scope.
68
+ #
69
+ # @example Instantiate the code with scope.
70
+ # BSON::CodeWithScope.new("this.value = name", name: "sid")
71
+ #
72
+ # @param [ String ] javascript The javascript code.
73
+ # @param [ Hash ] scope The variable scope.
74
+ #
75
+ # @since 2.0.0
76
+ def initialize(javascript = "", scope = {})
77
+ @javascript = javascript
78
+ @scope = scope
79
+ end
80
+
81
+ # Encode the javascript code with scope.
82
+ #
83
+ # @example Encode the code with scope.
84
+ # code_with_scope.to_bson
85
+ #
86
+ # @return [ String ] The encoded string.
87
+ #
88
+ # @see http://bsonspec.org/#/specification
89
+ #
90
+ # @since 2.0.0
91
+ def to_bson(encoded = ''.force_encoding(BINARY))
92
+ # -1 because we are removing an extra byte
93
+ out = encode_with_placeholder_and_null(BSON_ADJUST - 1, encoded) do |encoded|
94
+ javascript.to_bson(encoded)
95
+ scope.to_bson(encoded)
96
+ end
97
+ # an extra null byte has been added; we must remove it
98
+ out.chop!
99
+ end
100
+
101
+ # Deserialize a code with scope from BSON.
102
+ #
103
+ # @param [ BSON ] bson The encoded code with scope.
104
+ #
105
+ # @return [ TrueClass, FalseClass ] The decoded code with scope.
106
+ #
107
+ # @see http://bsonspec.org/#/specification
108
+ #
109
+ # @since 2.0.0
110
+ def self.from_bson(bson)
111
+ bson.read(4) # Throw away the total length.
112
+ new(bson.read(Int32.from_bson(bson)).from_bson_string.chop!, ::Hash.from_bson(bson))
113
+ end
114
+
115
+ # Register this type when the module is loaded.
116
+ #
117
+ # @since 2.0.0
118
+ Registry.register(BSON_TYPE, self)
119
+ end
120
+ end
@@ -0,0 +1,549 @@
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 "yaml"
16
+
17
+ # Since we have a custom bsondoc type for yaml serialization, we need
18
+ # to ensure that it's properly deserialized when parsed.
19
+ #
20
+ # @since 2.0.0
21
+ YAML.add_builtin_type("bsondoc") do |type, value|
22
+ BSON::Document[value.map{ |val| val.to_a.first }]
23
+ end
24
+
25
+ module BSON
26
+
27
+ # This module provides behaviour for serializing and deserializing entire
28
+ # BSON documents, according to the BSON specification.
29
+ #
30
+ # @note The specification is: document ::= int32 e_list "\x00"
31
+ #
32
+ # @see http://bsonspec.org/#/specification
33
+ #
34
+ # @since 2.0.0
35
+ class Document < ::Hash
36
+
37
+ # Get a value from the document for the provided key. Can use string or
38
+ # symbol access, but the fastest will be to always provide a key that is of
39
+ # the same type as the stored keys.
40
+ #
41
+ # @example Get an element for the key.
42
+ # document["field"]
43
+ #
44
+ # @example Get an element for the key by symbol.
45
+ # document[:field]
46
+ #
47
+ # @param [ String, Symbol ] key The key to lookup.
48
+ #
49
+ # @return [ Object ] The found value, or nil if none found.
50
+ #
51
+ # @since 2.0.0
52
+ def [](key)
53
+ super(key) || super(key.to_s)
54
+ end
55
+
56
+ # If we have ordered hashes, the a BSON::Document is simply a hash. If we do
57
+ # not, then we need to import our custom BSON::Document implementation.
58
+ #
59
+ # @since 2.0.0
60
+ unless Environment.retaining_hash_order?
61
+
62
+ # Message for argument error when providing bad arguments to [].
63
+ #
64
+ # @since 2.0.0
65
+ ARG_ERROR = "An even number of arguments must be passed to BSON::Document[]."
66
+
67
+ # Sets a value for the provided key.
68
+ #
69
+ # @example Set the value in the document.
70
+ # document[:name] = "Sid"
71
+ #
72
+ # @param [ Object ] key The name of the key.
73
+ # @param [ Object ] value The value for the key.
74
+ #
75
+ # @return [ Object ] The passed in value.
76
+ #
77
+ # @since 2.0.0
78
+ def []=(key, value)
79
+ order.push(key) unless has_key?(key)
80
+ super
81
+ end
82
+
83
+ # Clear out all elements in the document.
84
+ #
85
+ # @example Clear out all elements.
86
+ # document.clear
87
+ #
88
+ # @return [ BSON::Document ] The empty document.
89
+ #
90
+ # @since 2.0.0
91
+ def clear
92
+ super
93
+ order.clear
94
+ self
95
+ end
96
+
97
+ # Delete a value from the document for the provided key.
98
+ #
99
+ # @example Delete a value from the document.
100
+ # document.delete(:name)
101
+ #
102
+ # @param [ Object ] key The key to delete for.
103
+ #
104
+ # @return [ Object ] The deleted value.
105
+ #
106
+ # @since 2.0.0
107
+ def delete(key)
108
+ if has_key?(key)
109
+ order.delete_at(order.index(key))
110
+ end
111
+ super
112
+ end
113
+
114
+ # Delete each key/value pair in the document for which the provided block
115
+ # returns true.
116
+ #
117
+ # @example Delete each for when the block is true.
118
+ # document.delete_if do |key, value|
119
+ # value == 1
120
+ # end
121
+ #
122
+ # @return [ BSON::Document ] The document.
123
+ #
124
+ # @since 2.0.0
125
+ def delete_if
126
+ super
127
+ synchronize!
128
+ self
129
+ end
130
+ alias :reject! :delete_if
131
+
132
+ # Iterate over each element of the document in insertion order and yield
133
+ # the key and value.
134
+ #
135
+ # @example Iterate over the document.
136
+ # document.each do |key, value|
137
+ # #...
138
+ # end
139
+ #
140
+ # @return [ BSON::Document ] The document if a block was given, otherwise
141
+ # an enumerator.
142
+ #
143
+ # @since 2.0.0
144
+ def each
145
+ if block_given?
146
+ order.each{ |key| yield([ key, self[key]]) }
147
+ self
148
+ else
149
+ to_enum(:each)
150
+ end
151
+ end
152
+
153
+ # Iterate over each key in the document in insertion order and yield the
154
+ # key.
155
+ #
156
+ # @example Iterate over the keys.
157
+ # document.each_key do |key|
158
+ # #...
159
+ # end
160
+ #
161
+ # @return [ BSON::Document ] The document if a block was given, otherwise
162
+ # an enumerator.
163
+ #
164
+ # @since 2.0.0
165
+ def each_key
166
+ if block_given?
167
+ order.each{ |key| yield(key) }
168
+ self
169
+ else
170
+ to_enum(:each_key)
171
+ end
172
+ end
173
+
174
+ # Iterate over each value in the document in insertion order and yield the
175
+ # value.
176
+ #
177
+ # @example Iterate over the values.
178
+ # document.each_value do |value|
179
+ # #...
180
+ # end
181
+ #
182
+ # @return [ BSON::Document ] The document if a block was given, otherwise
183
+ # an enumerator.
184
+ #
185
+ # @since 2.0.0
186
+ def each_value
187
+ if block_given?
188
+ order.each{ |key| yield(self[key]) }
189
+ self
190
+ else
191
+ to_enum(:each_value)
192
+ end
193
+ end
194
+
195
+ # Iterate over each element of the document in insertion order and yield
196
+ # the key and value.
197
+ #
198
+ # @example Iterate over the document.
199
+ # document.each_pair do |key, value|
200
+ # #...
201
+ # end
202
+ #
203
+ # @return [ BSON::Document ] The document if a block was given, otherwise
204
+ # an enumerator.
205
+ #
206
+ # @since 2.0.0
207
+ def each_pair
208
+ if block_given?
209
+ order.each{ |key| yield([ key, self[key]]) }
210
+ self
211
+ else
212
+ to_enum(:each_pair)
213
+ end
214
+ end
215
+
216
+ # Encode the document with the provided coder.
217
+ #
218
+ # @example Encode the document with the coder.
219
+ # document.encode_with(coder)
220
+ #
221
+ # @param [ Object ] coder The coder.
222
+ #
223
+ # @return [ String ] The encoded document.
224
+ #
225
+ # @since 2.0.0
226
+ def encode_with(coder)
227
+ coder.represent_seq("!bsondoc", map{ |key, value| { key => value }})
228
+ end
229
+
230
+ # Get all the keys in the document, in order.
231
+ #
232
+ # @example Get all the keys in the document.
233
+ # document.keys
234
+ #
235
+ # @return [ Array<Object> ] The ordered keys.
236
+ #
237
+ # @since 2.0.0
238
+ def keys
239
+ order.dup
240
+ end
241
+
242
+ # Instantiate a new Document.
243
+ #
244
+ # @example Instantiate an empty new document.
245
+ # BSON::Document.new
246
+ #
247
+ # @since 2.0.0
248
+ def initialize(*args, &block)
249
+ super
250
+ @order = []
251
+ end
252
+
253
+ # Inspect the contents of the document.
254
+ #
255
+ # @example Inspect the document.
256
+ # document.inspect
257
+ #
258
+ # @return [ String ] The inspection string.
259
+ #
260
+ # @since 2.0.0
261
+ def inspect
262
+ "#<BSON::Document #{super}>"
263
+ end
264
+
265
+ # Invert the document - reverses the order of all key/value pairs and
266
+ # returns a new document.
267
+ #
268
+ # @example Invert the document.
269
+ # document.invert
270
+ #
271
+ # @return [ BSON::Document ] The inverted document.
272
+ #
273
+ # @since 2.0.0
274
+ def invert
275
+ Document[to_a.map!{ |pair| pair.reverse }]
276
+ end
277
+
278
+ # Merge a document into this document. Will overwrite any existing keys and
279
+ # add potential new ones. This returns a new document instead of merging in
280
+ # place.
281
+ #
282
+ # @example Merge the document into this document.
283
+ # document.merge(other_document)
284
+ #
285
+ # @param [ BSON::Document ] other The document to merge in.
286
+ #
287
+ # @return [ BSON::Document ] A newly merged document.
288
+ #
289
+ # @since 2.0.0
290
+ def merge(other, &block)
291
+ dup.merge!(other, &block)
292
+ end
293
+
294
+ # Merge a document into this document. Will overwrite any existing keys and
295
+ # add potential new ones.
296
+ #
297
+ # @example Merge the document into this document.
298
+ # document.merge!(other_document)
299
+ #
300
+ # @param [ BSON::Document ] other The document to merge in.
301
+ #
302
+ # @return [ BSON::Document ] The document.
303
+ #
304
+ # @since 2.0.0
305
+ def merge!(other)
306
+ if block_given?
307
+ other.each do |key, value|
308
+ self[key] = key?(key) ? yield(key, self[key], value) : value
309
+ end
310
+ else
311
+ other.each{ |key, value| self[key] = value }
312
+ end
313
+ self
314
+ end
315
+ alias :update :merge!
316
+
317
+ # Delete each key/value pair in the document for which the provided block
318
+ # returns true. This returns a new document instead of modifying in place.
319
+ #
320
+ # @example Delete each for when the block is true.
321
+ # document.reject do |key, value|
322
+ # value == 1
323
+ # end
324
+ #
325
+ # @return [ BSON::Document ] The new document.
326
+ #
327
+ # @since 2.0.0
328
+ def reject(&block)
329
+ dup.reject!(&block)
330
+ end
331
+
332
+ # Replace this document with the other document.
333
+ #
334
+ # @example Replace the contents of this document with the other.
335
+ # document.replace(other_document)
336
+ #
337
+ # @param [ BSON::Document ] other The other document.
338
+ #
339
+ # @return [ BSON::Document ] The document replaced.
340
+ #
341
+ # @since 2.0.0
342
+ def replace(other)
343
+ super
344
+ @order = other.keys
345
+ self
346
+ end
347
+
348
+ # Shift the document by popping off the first key/value pair in the
349
+ # document.
350
+ #
351
+ # @example Shift the document.
352
+ # document.shift
353
+ #
354
+ # @return [ Array<Object, Object> ] The first key/value pair.
355
+ #
356
+ # @since 2.0.0
357
+ def shift
358
+ key = order.first
359
+ value = delete(key)
360
+ [ key, value ]
361
+ end
362
+
363
+ alias :select :find_all
364
+
365
+ # Get the document as an array. This returns a multi-dimensional array
366
+ # where each element is a [ key, value ] pair in the insertion order.
367
+ #
368
+ # @example Get the document as an array.
369
+ # document.to_a
370
+ #
371
+ # @return [ Array<Array<Object, Object>> ] The pairs in insertion order.
372
+ #
373
+ # @since 2.0.0
374
+ def to_a
375
+ order.map{ |key| [ key, self[key] ]}
376
+ end
377
+
378
+ # Convert this document to a hash. Since a document is simply an ordered
379
+ # hash we return self.
380
+ #
381
+ # @example Get the document as a hash.
382
+ # document.to_hash
383
+ #
384
+ # @return [ BSON::Document ] The document.
385
+ #
386
+ # @since 2.0.0
387
+ def to_hash
388
+ self
389
+ end
390
+
391
+ # Convert the document to yaml.
392
+ #
393
+ # @example Convert the document to yaml.
394
+ # document.to_yaml
395
+ #
396
+ # @param [ Hash ] options The yaml options.
397
+ #
398
+ # @return [ String ] The document as yaml.
399
+ #
400
+ # @since 2.0.0
401
+ def to_yaml(options = {})
402
+ if YAML.const_defined?(:ENGINE) && !YAML::ENGINE.syck?
403
+ return super
404
+ end
405
+ YAML.quick_emit(self, options) do |out|
406
+ out.seq(taguri) do |seq|
407
+ each{ |key, value| seq.add(key => value) }
408
+ end
409
+ end
410
+ end
411
+
412
+ # Get the custom yaml type for the document.
413
+ #
414
+ # @example Get the yaml type.
415
+ # document.to_yaml_type
416
+ #
417
+ # @return [ String ] "!bsondoc".
418
+ #
419
+ # @since 2.0.0
420
+ def to_yaml_type
421
+ "!bsondoc"
422
+ end
423
+
424
+ # Get all the values in the document, by order of insertion.
425
+ #
426
+ # @example Get all the values in the document.
427
+ # document.values
428
+ #
429
+ # @return [ Array<Object> ] The ordered values.
430
+ #
431
+ # @since 2.0.0
432
+ def values
433
+ order.map{ |key| self[key] }
434
+ end
435
+
436
+ class << self
437
+
438
+ # Create a new document given the provided arguments. The args can either
439
+ # be empty in order to instantiate an empty document, or an array of
440
+ # key/value pairs in the order that they should remain in.
441
+ #
442
+ # @example Create a new empty document.
443
+ # BSON::Document[]
444
+ #
445
+ # @example Create a new document with the provided elements.
446
+ # BSON::Document[1, 2, 3, 4]
447
+ #
448
+ # @example Create a new document with key/value array pairs.
449
+ # BSON::Document[[ 1, 2 ], [ 3, 4 ]]
450
+ #
451
+ # @param [ Array<Object> ] args The key/value pairs.
452
+ #
453
+ # @return [ BSON::Document ] The new document.
454
+ #
455
+ # @since 2.0.0
456
+ def [](*args)
457
+ if (args.length == 1 && args.first.is_a?(Array))
458
+ return document_from_pairs(args)
459
+ end
460
+ raise ArgumentError.new(ARG_ERROR) unless (args.size % 2 == 0)
461
+ document_from_args(args)
462
+ end
463
+
464
+ private
465
+
466
+ # Returns a document that will be generated from an array of [ key, value ]
467
+ # array pairs.
468
+ #
469
+ # @api private
470
+ #
471
+ # @example Initialize a document from array pairs.
472
+ # BSON::Document[[ 1, 2 ], [ 3, 4 ]]
473
+ #
474
+ # @param [ Array ] pairs The key/value pairs.
475
+ #
476
+ # @since 2.0.0
477
+ #
478
+ # @return [ BSON::Document ] The document.
479
+ def document_from_pairs(pairs)
480
+ document = new
481
+ pairs.first.each do |pair|
482
+ next unless (pair.is_a?(Array))
483
+ document[pair[0]] = pair[1]
484
+ end
485
+ return document
486
+ end
487
+
488
+ # Returns a document that will be generated from an even number of
489
+ # individual arguments.
490
+ #
491
+ # @api private
492
+ #
493
+ # @example Initialize a document from args.
494
+ # BSON::Document[1, 2, 3, 4]
495
+ #
496
+ # @param [ Array ] args The arguments.
497
+ #
498
+ # @return [ BSON::Document ] The document.
499
+ #
500
+ # @since 2.0.0
501
+ def document_from_args(args)
502
+ document = new
503
+ args.each_with_index do |val, ind|
504
+ next if (ind % 2 != 0)
505
+ document[val] = args[ind + 1]
506
+ end
507
+ document
508
+ end
509
+ end
510
+
511
+ private
512
+
513
+ # @!attribute order
514
+ # @api private
515
+ # @return [ Array<String> ] The document keys in order.
516
+ # @since 2.0.0
517
+ attr_reader :order
518
+
519
+ # Initialize a copy of the document for use with clone or dup.
520
+ #
521
+ # @api private
522
+ #
523
+ # @example Clone the document.
524
+ # document.clone
525
+ #
526
+ # @param [ Object ] other The original copy.
527
+ #
528
+ # @since 2.0.0
529
+ def initialize_copy(other)
530
+ super
531
+ @order = other.keys
532
+ end
533
+
534
+ # Ensure that the ordered keys are the same entries as the internal keys.
535
+ #
536
+ # @api private
537
+ #
538
+ # @example Synchronize the keys.
539
+ # document.synchronize!
540
+ #
541
+ # @return [ Array<Object> ] The keys.
542
+ #
543
+ # @since 2.0.0
544
+ def synchronize!
545
+ order.reject!{ |key| !has_key?(key) }
546
+ end
547
+ end
548
+ end
549
+ end