bson 4.1.1 → 5.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (226) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +106 -7
  3. data/Rakefile +86 -43
  4. data/ext/bson/{native-endian.h → bson-endian.h} +14 -107
  5. data/ext/bson/bson-native.h +135 -0
  6. data/ext/bson/bytebuf.c +133 -0
  7. data/ext/bson/endian.c +117 -0
  8. data/ext/bson/extconf.rb +8 -3
  9. data/ext/bson/init.c +364 -0
  10. data/ext/bson/libbson-utf8.c +230 -0
  11. data/ext/bson/read.c +470 -0
  12. data/ext/bson/util.c +250 -0
  13. data/ext/bson/write.c +675 -0
  14. data/lib/bson/active_support.rb +19 -0
  15. data/lib/bson/array.rb +97 -30
  16. data/lib/bson/big_decimal.rb +77 -0
  17. data/lib/bson/binary.rb +510 -70
  18. data/lib/bson/boolean.rb +15 -4
  19. data/lib/bson/code.rb +25 -12
  20. data/lib/bson/code_with_scope.rb +41 -15
  21. data/lib/bson/config.rb +3 -28
  22. data/lib/bson/date.rb +16 -4
  23. data/lib/bson/date_time.rb +6 -4
  24. data/lib/bson/db_pointer.rb +110 -0
  25. data/lib/bson/dbref.rb +154 -0
  26. data/lib/bson/decimal128/builder.rb +456 -0
  27. data/lib/bson/decimal128.rb +272 -0
  28. data/lib/bson/document.rb +177 -7
  29. data/lib/bson/environment.rb +17 -2
  30. data/lib/bson/error/bson_decode_error.rb +11 -0
  31. data/lib/bson/error/ext_json_parse_error.rb +11 -0
  32. data/lib/bson/error/illegal_key.rb +23 -0
  33. data/lib/bson/error/invalid_binary_type.rb +37 -0
  34. data/lib/bson/error/invalid_dbref_argument.rb +12 -0
  35. data/lib/bson/error/invalid_decimal128_argument.rb +25 -0
  36. data/lib/bson/error/invalid_decimal128_range.rb +27 -0
  37. data/lib/bson/error/invalid_decimal128_string.rb +26 -0
  38. data/lib/bson/error/invalid_key.rb +24 -0
  39. data/lib/bson/error/invalid_object_id.rb +11 -0
  40. data/lib/bson/error/invalid_regexp_pattern.rb +13 -0
  41. data/lib/bson/error/unrepresentable_precision.rb +19 -0
  42. data/lib/bson/error/unserializable_class.rb +13 -0
  43. data/lib/bson/error/unsupported_binary_subtype.rb +12 -0
  44. data/lib/bson/error/unsupported_type.rb +11 -0
  45. data/lib/bson/error.rb +22 -0
  46. data/lib/bson/ext_json.rb +389 -0
  47. data/lib/bson/false_class.rb +6 -4
  48. data/lib/bson/float.rb +43 -7
  49. data/lib/bson/hash.rb +152 -37
  50. data/lib/bson/int32.rb +104 -6
  51. data/lib/bson/int64.rb +111 -8
  52. data/lib/bson/integer.rb +43 -9
  53. data/lib/bson/json.rb +3 -1
  54. data/lib/bson/max_key.rb +21 -10
  55. data/lib/bson/min_key.rb +21 -10
  56. data/lib/bson/nil_class.rb +7 -3
  57. data/lib/bson/object.rb +25 -17
  58. data/lib/bson/object_id.rb +98 -113
  59. data/lib/bson/open_struct.rb +59 -0
  60. data/lib/bson/regexp.rb +129 -56
  61. data/lib/bson/registry.rb +7 -10
  62. data/lib/bson/specialized.rb +8 -4
  63. data/lib/bson/string.rb +12 -32
  64. data/lib/bson/symbol.rb +107 -11
  65. data/lib/bson/time.rb +68 -7
  66. data/lib/bson/time_with_zone.rb +67 -0
  67. data/lib/bson/timestamp.rb +50 -10
  68. data/lib/bson/true_class.rb +6 -4
  69. data/lib/bson/undefined.rb +28 -2
  70. data/lib/bson/vector.rb +44 -0
  71. data/lib/bson/version.rb +6 -14
  72. data/lib/bson.rb +22 -12
  73. data/spec/README.md +14 -0
  74. data/spec/bson/array_spec.rb +38 -62
  75. data/spec/bson/big_decimal_spec.rb +328 -0
  76. data/spec/bson/binary_spec.rb +199 -53
  77. data/spec/bson/binary_uuid_spec.rb +190 -0
  78. data/spec/bson/boolean_spec.rb +2 -1
  79. data/spec/bson/byte_buffer_read_spec.rb +198 -0
  80. data/spec/bson/byte_buffer_spec.rb +122 -381
  81. data/spec/bson/byte_buffer_write_spec.rb +855 -0
  82. data/spec/bson/code_spec.rb +6 -4
  83. data/spec/bson/code_with_scope_spec.rb +6 -4
  84. data/spec/bson/config_spec.rb +1 -35
  85. data/spec/bson/date_spec.rb +2 -1
  86. data/spec/bson/date_time_spec.rb +55 -1
  87. data/spec/bson/dbref_legacy_spec.rb +186 -0
  88. data/spec/bson/dbref_spec.rb +487 -0
  89. data/spec/bson/decimal128_spec.rb +1840 -0
  90. data/spec/bson/document_as_spec.rb +61 -0
  91. data/spec/bson/document_spec.rb +205 -32
  92. data/spec/bson/ext_json_parse_spec.rb +346 -0
  93. data/spec/bson/false_class_spec.rb +9 -1
  94. data/spec/bson/float_spec.rb +42 -1
  95. data/spec/bson/hash_as_spec.rb +58 -0
  96. data/spec/bson/hash_spec.rb +318 -66
  97. data/spec/bson/int32_spec.rb +248 -1
  98. data/spec/bson/int64_spec.rb +308 -1
  99. data/spec/bson/integer_spec.rb +61 -3
  100. data/spec/bson/json_spec.rb +2 -1
  101. data/spec/bson/max_key_spec.rb +6 -4
  102. data/spec/bson/min_key_spec.rb +6 -4
  103. data/spec/bson/nil_class_spec.rb +2 -1
  104. data/spec/bson/object_id_spec.rb +95 -5
  105. data/spec/bson/object_spec.rb +3 -2
  106. data/spec/bson/open_struct_spec.rb +87 -0
  107. data/spec/bson/raw_spec.rb +594 -0
  108. data/spec/bson/regexp_spec.rb +61 -8
  109. data/spec/bson/registry_spec.rb +3 -2
  110. data/spec/bson/string_spec.rb +26 -33
  111. data/spec/bson/symbol_raw_spec.rb +70 -0
  112. data/spec/bson/symbol_spec.rb +77 -20
  113. data/spec/bson/time_spec.rb +206 -2
  114. data/spec/bson/time_with_zone_spec.rb +69 -0
  115. data/spec/bson/timestamp_spec.rb +58 -2
  116. data/spec/bson/true_class_spec.rb +9 -1
  117. data/spec/bson/undefined_spec.rb +28 -1
  118. data/spec/bson/vector_spec.rb +33 -0
  119. data/spec/bson_spec.rb +2 -1
  120. data/spec/runners/binary_vector.rb +78 -0
  121. data/spec/runners/common_driver.rb +348 -0
  122. data/spec/runners/corpus.rb +191 -0
  123. data/spec/runners/corpus_legacy.rb +248 -0
  124. data/spec/shared/LICENSE +20 -0
  125. data/spec/shared/bin/get-mongodb-download-url +17 -0
  126. data/spec/shared/bin/s3-copy +45 -0
  127. data/spec/shared/bin/s3-upload +69 -0
  128. data/spec/shared/lib/mrss/child_process_helper.rb +80 -0
  129. data/spec/shared/lib/mrss/cluster_config.rb +231 -0
  130. data/spec/shared/lib/mrss/constraints.rb +378 -0
  131. data/spec/shared/lib/mrss/docker_runner.rb +298 -0
  132. data/spec/shared/lib/mrss/eg_config_utils.rb +51 -0
  133. data/spec/shared/lib/mrss/event_subscriber.rb +210 -0
  134. data/spec/shared/lib/mrss/lite_constraints.rb +238 -0
  135. data/spec/shared/lib/mrss/release/candidate.rb +281 -0
  136. data/spec/shared/lib/mrss/release/product_data.rb +144 -0
  137. data/spec/shared/lib/mrss/server_version_registry.rb +113 -0
  138. data/spec/shared/lib/mrss/session_registry.rb +69 -0
  139. data/spec/shared/lib/mrss/session_registry_legacy.rb +60 -0
  140. data/spec/shared/lib/mrss/spec_organizer.rb +179 -0
  141. data/spec/shared/lib/mrss/utils.rb +37 -0
  142. data/spec/shared/lib/tasks/candidate.rake +64 -0
  143. data/spec/shared/share/Dockerfile.erb +251 -0
  144. data/spec/shared/share/haproxy-1.conf +16 -0
  145. data/spec/shared/share/haproxy-2.conf +17 -0
  146. data/spec/shared/shlib/config.sh +27 -0
  147. data/spec/shared/shlib/distro.sh +84 -0
  148. data/spec/shared/shlib/server.sh +423 -0
  149. data/spec/shared/shlib/set_env.sh +110 -0
  150. data/spec/spec_helper.rb +61 -1
  151. data/spec/spec_tests/binary_vector_spec.rb +82 -0
  152. data/spec/spec_tests/common_driver_spec.rb +84 -0
  153. data/spec/spec_tests/corpus_legacy_spec.rb +72 -0
  154. data/spec/spec_tests/corpus_spec.rb +134 -0
  155. data/spec/spec_tests/data/binary_vector/README.md +61 -0
  156. data/spec/spec_tests/data/binary_vector/float32.json +65 -0
  157. data/spec/spec_tests/data/binary_vector/int8.json +57 -0
  158. data/spec/spec_tests/data/binary_vector/packed_bit.json +83 -0
  159. data/spec/spec_tests/data/corpus/README.md +15 -0
  160. data/spec/spec_tests/data/corpus/array.json +49 -0
  161. data/spec/spec_tests/data/corpus/binary.json +153 -0
  162. data/spec/spec_tests/data/corpus/boolean.json +27 -0
  163. data/spec/spec_tests/data/corpus/code.json +67 -0
  164. data/spec/spec_tests/data/corpus/code_w_scope.json +78 -0
  165. data/spec/spec_tests/data/corpus/datetime.json +42 -0
  166. data/spec/spec_tests/data/corpus/dbpointer.json +56 -0
  167. data/spec/spec_tests/data/corpus/dbref.json +51 -0
  168. data/spec/spec_tests/data/corpus/decimal128-1.json +317 -0
  169. data/spec/spec_tests/data/corpus/decimal128-2.json +793 -0
  170. data/spec/spec_tests/data/corpus/decimal128-3.json +1771 -0
  171. data/spec/spec_tests/data/corpus/decimal128-4.json +165 -0
  172. data/spec/spec_tests/data/corpus/decimal128-5.json +402 -0
  173. data/spec/spec_tests/data/corpus/decimal128-6.json +131 -0
  174. data/spec/spec_tests/data/corpus/decimal128-7.json +327 -0
  175. data/spec/spec_tests/data/corpus/document.json +60 -0
  176. data/spec/spec_tests/data/corpus/double.json +87 -0
  177. data/spec/spec_tests/data/corpus/int32.json +43 -0
  178. data/spec/spec_tests/data/corpus/int64.json +43 -0
  179. data/spec/spec_tests/data/corpus/maxkey.json +12 -0
  180. data/spec/spec_tests/data/corpus/minkey.json +12 -0
  181. data/spec/spec_tests/data/corpus/multi-type-deprecated.json +15 -0
  182. data/spec/spec_tests/data/corpus/multi-type.json +11 -0
  183. data/spec/spec_tests/data/corpus/null.json +12 -0
  184. data/spec/spec_tests/data/corpus/oid.json +28 -0
  185. data/spec/spec_tests/data/corpus/regex.json +65 -0
  186. data/spec/spec_tests/data/corpus/string.json +72 -0
  187. data/spec/spec_tests/data/corpus/symbol.json +80 -0
  188. data/spec/spec_tests/data/corpus/timestamp.json +34 -0
  189. data/spec/spec_tests/data/corpus/top.json +262 -0
  190. data/spec/spec_tests/data/corpus/undefined.json +15 -0
  191. data/spec/spec_tests/data/corpus_legacy/array.json +49 -0
  192. data/spec/spec_tests/data/corpus_legacy/binary.json +69 -0
  193. data/spec/spec_tests/data/corpus_legacy/boolean.json +27 -0
  194. data/spec/spec_tests/data/corpus_legacy/code.json +67 -0
  195. data/spec/spec_tests/data/corpus_legacy/code_w_scope.json +78 -0
  196. data/spec/spec_tests/data/corpus_legacy/document.json +36 -0
  197. data/spec/spec_tests/data/corpus_legacy/double.json +69 -0
  198. data/spec/spec_tests/data/corpus_legacy/failures/datetime.json +31 -0
  199. data/spec/spec_tests/data/corpus_legacy/failures/dbpointer.json +42 -0
  200. data/spec/spec_tests/data/corpus_legacy/failures/int64.json +38 -0
  201. data/spec/spec_tests/data/corpus_legacy/failures/symbol.json +62 -0
  202. data/spec/spec_tests/data/corpus_legacy/int32.json +38 -0
  203. data/spec/spec_tests/data/corpus_legacy/maxkey.json +12 -0
  204. data/spec/spec_tests/data/corpus_legacy/minkey.json +12 -0
  205. data/spec/spec_tests/data/corpus_legacy/null.json +12 -0
  206. data/spec/spec_tests/data/corpus_legacy/oid.json +28 -0
  207. data/spec/spec_tests/data/corpus_legacy/regex.json +37 -0
  208. data/spec/spec_tests/data/corpus_legacy/string.json +67 -0
  209. data/spec/spec_tests/data/corpus_legacy/timestamp.json +18 -0
  210. data/spec/spec_tests/data/corpus_legacy/top.json +62 -0
  211. data/spec/spec_tests/data/corpus_legacy/undefined.json +13 -0
  212. data/spec/spec_tests/data/decimal128/decimal128-1.json +363 -0
  213. data/spec/spec_tests/data/decimal128/decimal128-2.json +793 -0
  214. data/spec/spec_tests/data/decimal128/decimal128-3.json +1771 -0
  215. data/spec/spec_tests/data/decimal128/decimal128-4.json +165 -0
  216. data/spec/spec_tests/data/decimal128/decimal128-5.json +402 -0
  217. data/spec/spec_tests/data/decimal128/decimal128-6.json +131 -0
  218. data/spec/spec_tests/data/decimal128/decimal128-7.json +327 -0
  219. data/spec/support/shared_examples.rb +32 -11
  220. data/spec/support/spec_config.rb +17 -0
  221. data/spec/support/utils.rb +58 -0
  222. metadata +284 -45
  223. checksums.yaml.gz.sig +0 -3
  224. data/ext/bson/native.c +0 -722
  225. data.tar.gz.sig +0 -0
  226. metadata.gz.sig +0 -0
data/lib/bson/regexp.rb CHANGED
@@ -1,4 +1,6 @@
1
- # Copyright (C) 2009-2015 MongoDB Inc.
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (C) 2009-2020 MongoDB Inc.
2
4
  #
3
5
  # Licensed under the Apache License, Version 2.0 (the "License");
4
6
  # you may not use this file except in compliance with the License.
@@ -12,8 +14,8 @@
12
14
  # See the License for the specific language governing permissions and
13
15
  # limitations under the License.
14
16
 
17
+ # The top-level BSON module.
15
18
  module BSON
16
-
17
19
  # Injects behaviour for encoding and decoding regular expression values to
18
20
  # and from raw bytes as specified by the BSON spec.
19
21
  #
@@ -26,32 +28,34 @@ module BSON
26
28
  # A regular expression is type 0x0B in the BSON spec.
27
29
  #
28
30
  # @since 2.0.0
29
- BSON_TYPE = 11.chr.force_encoding(BINARY).freeze
31
+ BSON_TYPE = ::String.new(11.chr, encoding: BINARY).freeze
30
32
 
31
33
  # Extended value constant.
32
34
  #
33
35
  # @since 3.2.6
34
- EXTENDED_VALUE = 'x'.freeze
36
+ EXTENDED_VALUE = 'x'
35
37
 
36
38
  # Ignore case constant.
37
39
  #
38
40
  # @since 3.2.6
39
- IGNORECASE_VALUE = 'i'.freeze
41
+ IGNORECASE_VALUE = 'i'
40
42
 
41
43
  # Multiline constant.
42
44
  #
43
45
  # @since 3.2.6
44
- MULTILINE_VALUE = 'm'.freeze
46
+ MULTILINE_VALUE = 'm'
45
47
 
46
48
  # Newline constant.
47
49
  #
48
50
  # @since 3.2.6
49
- NEWLINE_VALUE = 's'.freeze
51
+ NEWLINE_VALUE = 's'
50
52
 
51
53
  # Ruby multiline constant.
52
54
  #
53
55
  # @since 3.2.6
54
- RUBY_MULTILINE_VALUE = 'ms'.freeze
56
+ #
57
+ # @deprecated Will be removed in 5.0
58
+ RUBY_MULTILINE_VALUE = 'ms'
55
59
 
56
60
  # Get the regexp as JSON hash data.
57
61
  #
@@ -59,10 +63,8 @@ module BSON
59
63
  # regexp.as_json
60
64
  #
61
65
  # @return [ Hash ] The regexp as a JSON hash.
62
- #
63
- # @since 2.0.0
64
- def as_json(*args)
65
- { "$regex" => source, "$options" => bson_options }
66
+ def as_json(*)
67
+ { '$regex' => source, '$options' => bson_options }
66
68
  end
67
69
 
68
70
  # Get the regular expression as encoded BSON.
@@ -79,12 +81,12 @@ module BSON
79
81
  # 's' for dotall mode ('.' matches everything),
80
82
  # and 'u' to make \w, \W, etc. match unicode.
81
83
  #
82
- # @return [ String ] The encoded string.
84
+ # @param [ BSON::ByteBuffer ] buffer The byte buffer to append to.
83
85
  #
84
- # @see http://bsonspec.org/#/specification
86
+ # @return [ BSON::ByteBuffer ] The buffer with the encoded object.
85
87
  #
86
- # @since 2.0.0
87
- def to_bson(buffer = ByteBuffer.new, validating_keys = Config.validating_keys?)
88
+ # @see http://bsonspec.org/#/specification
89
+ def to_bson(buffer = ByteBuffer.new)
88
90
  buffer.put_cstring(source)
89
91
  buffer.put_cstring(bson_options)
90
92
  end
@@ -92,32 +94,33 @@ module BSON
92
94
  private
93
95
 
94
96
  def bson_options
95
- bson_ignorecase + bson_multiline + bson_extended
97
+ # Ruby's Regexp always has BSON's equivalent of 'm' on, so always add it
98
+ bson_ignorecase + MULTILINE_VALUE + bson_dotall + bson_extended
96
99
  end
97
100
 
98
101
  def bson_extended
99
- (options & ::Regexp::EXTENDED != 0) ? EXTENDED_VALUE : NO_VALUE
102
+ options.nobits?(::Regexp::EXTENDED) ? NO_VALUE : EXTENDED_VALUE
100
103
  end
101
104
 
102
105
  def bson_ignorecase
103
- (options & ::Regexp::IGNORECASE != 0) ? IGNORECASE_VALUE : NO_VALUE
106
+ options.nobits?(::Regexp::IGNORECASE) ? NO_VALUE : IGNORECASE_VALUE
104
107
  end
105
108
 
106
- def bson_multiline
107
- (options & ::Regexp::MULTILINE != 0) ? RUBY_MULTILINE_VALUE : NO_VALUE
109
+ def bson_dotall
110
+ # Ruby Regexp's MULTILINE is equivalent to BSON's dotall value
111
+ options.nobits?(::Regexp::MULTILINE) ? NO_VALUE : NEWLINE_VALUE
108
112
  end
109
113
 
110
114
  # Represents the raw values for the regular expression.
111
115
  #
112
116
  # @see https://jira.mongodb.org/browse/RUBY-698
113
- #
114
- # @since 3.0.0
115
117
  class Raw
118
+ include JSON
116
119
 
117
120
  # @return [ String ] pattern The regex pattern.
118
121
  attr_reader :pattern
119
122
 
120
- # @return [ Integer ] options The options.
123
+ # @return [ String ] options The options.
121
124
  attr_reader :options
122
125
 
123
126
  # Compile the Regular expression into the native type.
@@ -126,10 +129,8 @@ module BSON
126
129
  # raw.compile
127
130
  #
128
131
  # @return [ ::Regexp ] The compiled regular expression.
129
- #
130
- # @since 3.0.0
131
132
  def compile
132
- @compiled ||= ::Regexp.new(pattern, options)
133
+ @compile ||= ::Regexp.new(pattern, options_to_int)
133
134
  end
134
135
 
135
136
  # Initialize the new raw regular expression.
@@ -138,69 +139,141 @@ module BSON
138
139
  # Raw.new(pattern, options)
139
140
  #
140
141
  # @param [ String ] pattern The regular expression pattern.
141
- # @param [ Integer ] options The options.
142
- #
143
- # @since 3.0.0
144
- def initialize(pattern, options)
142
+ # @param [ String | Symbol ] options The options.
143
+ def initialize(pattern, options = '')
144
+ if pattern.include?(NULL_BYTE)
145
+ raise Error::InvalidRegexpPattern, "Regexp pattern cannot contain a null byte: #{pattern}"
146
+ elsif options.is_a?(String) || options.is_a?(Symbol)
147
+ if options.to_s.include?(NULL_BYTE)
148
+ raise Error::InvalidRegexpPattern, "Regexp options cannot contain a null byte: #{options}"
149
+ end
150
+ else
151
+ raise ArgumentError, 'Regexp options must be a String or Symbol'
152
+ end
153
+
145
154
  @pattern = pattern
146
- @options = options
155
+ @options = options.to_s
147
156
  end
148
157
 
149
158
  # Allow automatic delegation of methods to the Regexp object
150
159
  # returned by +compile+.
151
160
  #
152
161
  # @param [ String] method The name of a method.
162
+ def respond_to_missing?(method, include_private = false)
163
+ # YAML calls #respond_to? during deserialization, before the object
164
+ # is initialized.
165
+ defined?(@pattern) && compile.respond_to?(method, include_private)
166
+ end
167
+
168
+ # Encode the Raw Regexp object to BSON.
169
+ #
170
+ # @example Get the raw regular expression as encoded BSON.
171
+ # raw_regexp.to_bson
172
+ #
173
+ # @note From the BSON spec: The first cstring is the regex pattern,
174
+ # the second is the regex options string. Options are identified
175
+ # by characters, which must be stored in alphabetical order.
176
+ # Valid options are 'i' for case insensitive matching,
177
+ # 'm' for multiline matching, 'x' for verbose mode,
178
+ # 'l' to make \w, \W, etc. locale dependent,
179
+ # 's' for dotall mode ('.' matches everything),
180
+ # and 'u' to make \w, \W, etc. match unicode.
181
+ #
182
+ # @param [ BSON::ByteBuffer ] buffer The byte buffer to append to.
183
+ #
184
+ # @return [ BSON::ByteBuffer ] The buffer with the encoded object.
185
+ #
186
+ # @see http://bsonspec.org/#/specification
187
+ def to_bson(buffer = ByteBuffer.new)
188
+ buffer.put_cstring(source)
189
+ buffer.put_cstring(options.chars.sort.join)
190
+ end
191
+
192
+ # Get the raw BSON regexp as JSON hash data.
193
+ #
194
+ # @example Get the raw regexp as a JSON hash.
195
+ # raw_regexp.as_json
153
196
  #
154
- # @since 3.1.0
155
- def respond_to?(method, include_private = false)
156
- compile.respond_to?(method, include_private = false) || super
197
+ # @return [ Hash ] The raw regexp as a JSON hash.
198
+ def as_json(*)
199
+ as_extended_json(mode: :legacy)
157
200
  end
158
201
 
202
+ # Converts this object to a representation directly serializable to
203
+ # Extended JSON (https://github.com/mongodb/specifications/blob/master/source/extended-json/extended-json.md).
204
+ #
205
+ # @option opts [ nil | :relaxed | :legacy ] :mode Serialization mode
206
+ # (default is canonical extended JSON)
207
+ #
208
+ # @return [ Hash ] The extended json representation.
209
+ def as_extended_json(**opts)
210
+ if opts[:mode] == :legacy
211
+ { '$regex' => source, '$options' => options }
212
+ else
213
+ { '$regularExpression' => { 'pattern' => source, 'options' => options } }
214
+ end
215
+ end
216
+
217
+ # Check equality of the raw bson regexp against another.
218
+ #
219
+ # @example Check if the raw bson regexp is equal to the other.
220
+ # raw_regexp == other
221
+ #
222
+ # @param [ Object ] other The object to check against.
223
+ #
224
+ # @return [ true, false ] If the objects are equal.
225
+ def ==(other)
226
+ return false unless other.is_a?(::Regexp::Raw)
227
+
228
+ pattern == other.pattern && options == other.options
229
+ end
230
+ alias eql? ==
231
+
159
232
  private
160
233
 
161
234
  def method_missing(method, *arguments)
162
235
  return super unless respond_to?(method)
236
+
163
237
  compile.send(method, *arguments)
164
238
  end
239
+
240
+ def options_to_int
241
+ opts = 0
242
+ opts |= ::Regexp::IGNORECASE if options.include?(IGNORECASE_VALUE)
243
+ opts |= ::Regexp::MULTILINE if options.include?(NEWLINE_VALUE)
244
+ opts |= ::Regexp::EXTENDED if options.include?(EXTENDED_VALUE)
245
+ opts
246
+ end
165
247
  end
166
248
 
249
+ # Class-level methods to be added to the Regexp class.
167
250
  module ClassMethods
168
-
169
251
  # Deserialize the regular expression from BSON.
170
252
  #
253
+ # @note If the argument cannot be parsed, an exception will be raised
254
+ # and the argument will be left in an undefined state. The caller
255
+ # must explicitly call `rewind` on the buffer before trying to parse
256
+ # it again.
257
+ #
171
258
  # @param [ ByteBuffer ] buffer The byte buffer.
172
259
  #
260
+ # @option opts [ nil | :bson ] :mode Decoding mode to use.
261
+ #
173
262
  # @return [ Regexp ] The decoded regular expression.
174
263
  #
175
264
  # @see http://bsonspec.org/#/specification
176
- #
177
- # @since 2.0.0
178
- def from_bson(buffer)
265
+ def from_bson(buffer, **_)
179
266
  pattern = buffer.get_cstring
180
- options = 0
181
- while (option = buffer.get_byte) != NULL_BYTE
182
- case option
183
- when IGNORECASE_VALUE
184
- options |= ::Regexp::IGNORECASE
185
- when MULTILINE_VALUE, NEWLINE_VALUE
186
- options |= ::Regexp::MULTILINE
187
- when EXTENDED_VALUE
188
- options |= ::Regexp::EXTENDED
189
- end
190
- end
267
+ options = buffer.get_cstring
191
268
  Raw.new(pattern, options)
192
269
  end
193
270
  end
194
271
 
195
272
  # Register this type when the module is loaded.
196
- #
197
- # @since 2.0.0
198
273
  Registry.register(BSON_TYPE, ::Regexp)
199
274
  end
200
275
 
201
276
  # Enrich the core Regexp class with this module.
202
- #
203
- # @since 2.0.0
204
- ::Regexp.send(:include, Regexp)
205
- ::Regexp.send(:extend, Regexp::ClassMethods)
277
+ ::Regexp.include Regexp
278
+ ::Regexp.extend Regexp::ClassMethods
206
279
  end
data/lib/bson/registry.rb CHANGED
@@ -1,4 +1,6 @@
1
- # Copyright (C) 2009-2014 MongoDB Inc.
1
+ # frozen_string_literal: true
2
+ # rubocop:todo all
3
+ # Copyright (C) 2009-2020 MongoDB Inc.
2
4
  #
3
5
  # Licensed under the Apache License, Version 2.0 (the "License");
4
6
  # you may not use this file except in compliance with the License.
@@ -40,7 +42,7 @@ module BSON
40
42
  #
41
43
  # @since 2.0.0
42
44
  def get(byte, field = nil)
43
- if type = MAPPINGS[byte]
45
+ if type = MAPPINGS[byte] || (byte.is_a?(String) && type = MAPPINGS[byte.ord])
44
46
  type
45
47
  else
46
48
  handle_unsupported_type!(byte, field)
@@ -53,21 +55,16 @@ module BSON
53
55
  # BSON::Registry.register("\x01", Float)
54
56
  #
55
57
  # @param [ String ] byte The single byte.
56
- # @param [ Class ] The class the byte maps to.
58
+ # @param [ Class ] type The class the byte maps to.
57
59
  #
58
60
  # @return [ Class ] The class.
59
61
  #
60
62
  # @since 2.0.0
61
63
  def register(byte, type)
62
- MAPPINGS.store(byte, type)
64
+ MAPPINGS[byte.ord] = type
63
65
  define_type_reader(type)
64
66
  end
65
67
 
66
- # Raised when trying to get a type from the registry that doesn't exist.
67
- #
68
- # @since 4.1.0
69
- class UnsupportedType < RuntimeError; end
70
-
71
68
  private
72
69
 
73
70
  def define_type_reader(type)
@@ -80,7 +77,7 @@ module BSON
80
77
  message = "Detected unknown BSON type #{byte.inspect} "
81
78
  message += (field ? "for fieldname \"#{field}\". " : "in array. ")
82
79
  message +="Are you using the latest BSON version?"
83
- raise UnsupportedType.new(message)
80
+ raise Error::UnsupportedType.new(message)
84
81
  end
85
82
  end
86
83
  end
@@ -1,4 +1,6 @@
1
- # Copyright (C) 2009-2014 MongoDB Inc.
1
+ # frozen_string_literal: true
2
+ # rubocop:todo all
3
+ # Copyright (C) 2009-2020 MongoDB Inc.
2
4
  #
3
5
  # Licensed under the Apache License, Version 2.0 (the "License");
4
6
  # you may not use this file except in compliance with the License.
@@ -42,10 +44,10 @@ module BSON
42
44
  # @example Encode the min key value.
43
45
  # min_key.to_bson
44
46
  #
45
- # @return [ String ] An empty string.
47
+ # @return [ BSON::ByteBuffer ] The buffer with the encoded object.
46
48
  #
47
49
  # @since 2.0.0
48
- def to_bson(buffer = ByteBuffer.new, validating_keys = Config.validating_keys?)
50
+ def to_bson(buffer = ByteBuffer.new)
49
51
  buffer
50
52
  end
51
53
 
@@ -61,12 +63,14 @@ module BSON
61
63
  #
62
64
  # @param [ ByteBuffer ] buffer The byte buffer.
63
65
  #
66
+ # @option options [ nil | :bson ] :mode Decoding mode to use.
67
+ #
64
68
  # @return [ Specialized ] The decoded specialized class.
65
69
  #
66
70
  # @see http://bsonspec.org/#/specification
67
71
  #
68
72
  # @since 2.0.0
69
- def from_bson(buffer)
73
+ def from_bson(buffer, **options)
70
74
  new
71
75
  end
72
76
  end
data/lib/bson/string.rb CHANGED
@@ -1,5 +1,7 @@
1
+ # rubocop:todo all
1
2
  # -*- coding: utf-8 -*-
2
- # Copyright (C) 2009-2014 MongoDB Inc.
3
+ # frozen_string_literal: true
4
+ # Copyright (C) 2009-2020 MongoDB Inc.
3
5
  #
4
6
  # Licensed under the Apache License, Version 2.0 (the "License");
5
7
  # you may not use this file except in compliance with the License.
@@ -26,12 +28,12 @@ module BSON
26
28
  # A string is type 0x02 in the BSON spec.
27
29
  #
28
30
  # @since 2.0.0
29
- BSON_TYPE = 2.chr.force_encoding(BINARY).freeze
31
+ BSON_TYPE = ::String.new(2.chr, encoding: BINARY).freeze
30
32
 
31
33
  # Regex for matching illegal BSON keys.
32
34
  #
33
35
  # @since 4.1.0
34
- ILLEGAL_KEY = /(\A[$])|(\.)/.freeze
36
+ ILLEGAL_KEY = /(\A[$])|(\.)/
35
37
 
36
38
  # Get the string as encoded BSON.
37
39
  #
@@ -40,12 +42,12 @@ module BSON
40
42
  #
41
43
  # @raise [ EncodingError ] If the string is not UTF-8.
42
44
  #
43
- # @return [ String ] The encoded string.
45
+ # @return [ BSON::ByteBuffer ] The buffer with the encoded object.
44
46
  #
45
47
  # @see http://bsonspec.org/#/specification
46
48
  #
47
49
  # @since 2.0.0
48
- def to_bson(buffer = ByteBuffer.new, validating_keys = Config.validating_keys?)
50
+ def to_bson(buffer = ByteBuffer.new)
49
51
  buffer.put_string(self)
50
52
  end
51
53
 
@@ -56,18 +58,12 @@ module BSON
56
58
  #
57
59
  # @raise [ EncodingError ] If the string is not UTF-8.
58
60
  #
59
- # @raise [ IllegalKey ] If validating keys and it contains a '.' or starts
60
- # with '$'.
61
- #
62
61
  # @return [ String ] The encoded string.
63
62
  #
64
63
  # @see http://bsonspec.org/#/specification
65
64
  #
66
65
  # @since 2.0.0
67
- def to_bson_key(validating_keys = Config.validating_keys?)
68
- if validating_keys
69
- raise IllegalKey.new(self) if ILLEGAL_KEY =~ self
70
- end
66
+ def to_bson_key
71
67
  self
72
68
  end
73
69
 
@@ -79,7 +75,7 @@ module BSON
79
75
  #
80
76
  # @note This is used for repairing legacy bson data.
81
77
  #
82
- # @raise [ InvalidObjectId ] If the string is not 12 elements.
78
+ # @raise [ BSON::Error::InvalidObjectId ] If the string is not 12 elements.
83
79
  #
84
80
  # @return [ String ] The raw object id bytes.
85
81
  #
@@ -100,36 +96,20 @@ module BSON
100
96
  unpack("H*")[0]
101
97
  end
102
98
 
103
- # Raised when validating keys and a key is illegal in MongoDB
104
- #
105
- # @since 4.1.0
106
- class IllegalKey < RuntimeError
107
-
108
- # Instantiate the exception.
109
- #
110
- # @example Instantiate the exception.
111
- # BSON::Object::IllegalKey.new(string)
112
- #
113
- # @param [ String ] string The illegal string.
114
- #
115
- # @since 4.1.0
116
- def initialize(string)
117
- super("'#{string}' is an illegal key in MongoDB. Keys may not start with '$' or contain a '.'.")
118
- end
119
- end
120
-
121
99
  module ClassMethods
122
100
 
123
101
  # Deserialize a string from BSON.
124
102
  #
125
103
  # @param [ ByteBuffer ] buffer The byte buffer.
126
104
  #
105
+ # @option options [ nil | :bson ] :mode Decoding mode to use.
106
+ #
127
107
  # @return [ Regexp ] The decoded string.
128
108
  #
129
109
  # @see http://bsonspec.org/#/specification
130
110
  #
131
111
  # @since 2.0.0
132
- def from_bson(buffer)
112
+ def from_bson(buffer, **options)
133
113
  buffer.get_string
134
114
  end
135
115
  end
data/lib/bson/symbol.rb CHANGED
@@ -1,4 +1,6 @@
1
- # Copyright (C) 2009-2014 MongoDB Inc.
1
+ # frozen_string_literal: true
2
+ # rubocop:todo all
3
+ # Copyright (C) 2009-2020 MongoDB Inc.
2
4
  #
3
5
  # Licensed under the Apache License, Version 2.0 (the "License");
4
6
  # you may not use this file except in compliance with the License.
@@ -28,7 +30,7 @@ module BSON
28
30
  # A symbol is type 0x0E in the BSON spec.
29
31
  #
30
32
  # @since 2.0.0
31
- BSON_TYPE = 14.chr.force_encoding(BINARY).freeze
33
+ BSON_TYPE = ::String.new(14.chr, encoding: BINARY).freeze
32
34
 
33
35
  # Symbols are serialized as strings as symbols are now removed from the
34
36
  # BSON specification. Therefore the bson_type when serializing must be a
@@ -51,13 +53,13 @@ module BSON
51
53
  # @example Get the symbol as encoded BSON.
52
54
  # :test.to_bson
53
55
  #
54
- # @return [ Symbol ] The encoded symbol.
56
+ # @return [ BSON::ByteBuffer ] The buffer with the encoded object.
55
57
  #
56
58
  # @see http://bsonspec.org/#/specification
57
59
  #
58
60
  # @since 2.0.0
59
- def to_bson(buffer = ByteBuffer.new, validating_keys = Config.validating_keys?)
60
- to_s.to_bson(buffer)
61
+ def to_bson(buffer = ByteBuffer.new)
62
+ buffer.put_symbol(self)
61
63
  end
62
64
 
63
65
  # Get the symbol as a BSON key name encoded C symbol.
@@ -70,8 +72,8 @@ module BSON
70
72
  # @see http://bsonspec.org/#/specification
71
73
  #
72
74
  # @since 2.0.0
73
- def to_bson_key(validating_keys = Config.validating_keys?)
74
- to_s.to_bson_key(validating_keys)
75
+ def to_bson_key
76
+ self
75
77
  end
76
78
 
77
79
  # Converts the symbol to a normalized key in a BSON document.
@@ -86,26 +88,120 @@ module BSON
86
88
  to_s
87
89
  end
88
90
 
91
+ # Converts this object to a representation directly serializable to
92
+ # Extended JSON (https://github.com/mongodb/specifications/blob/master/source/extended-json/extended-json.md).
93
+ #
94
+ # @return [ Hash ] The extended json representation.
95
+ def as_extended_json(**_options)
96
+ { "$symbol" => to_s }
97
+ end
98
+
99
+ class Raw
100
+ include JSON
101
+
102
+ # Create a BSON Symbol
103
+ #
104
+ # @param [ String | Symbol ] str_or_sym The symbol represented by this
105
+ # object. Can be specified as a Symbol or a String.
106
+ #
107
+ # @see http://bsonspec.org/#/specification
108
+ def initialize(str_or_sym)
109
+ unless str_or_sym.is_a?(String) || str_or_sym.is_a?(Symbol)
110
+ raise ArgumentError, "BSON::Symbol::Raw must be given a symbol or a string, not #{str_or_sym}"
111
+ end
112
+
113
+ @symbol = str_or_sym.to_sym
114
+ end
115
+
116
+ # Get the underlying symbol as a Ruby symbol.
117
+ #
118
+ # @return [ Symbol ] The symbol represented by this BSON object.
119
+ def to_sym
120
+ @symbol
121
+ end
122
+
123
+ # Get the underlying symbol as a Ruby string.
124
+ #
125
+ # @return [ String ] The symbol as a string.
126
+ def to_s
127
+ @symbol.to_s
128
+ end
129
+
130
+ # Check equality of the raw bson symbol against another.
131
+ #
132
+ # @param [ Object ] other The object to check against.
133
+ #
134
+ # @return [ true, false ] If the objects are equal.
135
+ def ==(other)
136
+ return false unless other.is_a?(Raw)
137
+ to_sym == other.to_sym
138
+ end
139
+ alias :eql? :==
140
+
141
+ # Get the symbol as encoded BSON.
142
+ #
143
+ # @raise [ EncodingError ] If the symbol is not UTF-8.
144
+ #
145
+ # @return [ BSON::ByteBuffer ] The buffer with the encoded object.
146
+ #
147
+ # @see http://bsonspec.org/#/specification
148
+ def to_bson(buffer = ByteBuffer.new)
149
+ buffer.put_string(to_s)
150
+ end
151
+
152
+ def bson_type
153
+ Symbol::BSON_TYPE
154
+ end
155
+
156
+ # Return a string representation of the raw symbol for use in
157
+ # application-level JSON serialization. This method is intentionally
158
+ # different from #as_extended_json.
159
+ #
160
+ # @example Get the raw symbol as a JSON-serializable object.
161
+ # raw_symbol.as_json
162
+ #
163
+ # @return [ String ] The raw symbol as a String.
164
+ def as_json(*args)
165
+ to_s
166
+ end
167
+
168
+ # Converts this object to a representation directly serializable to
169
+ # Extended JSON (https://github.com/mongodb/specifications/blob/master/source/extended-json/extended-json.md).
170
+ #
171
+ # @return [ Hash ] The extended json representation.
172
+ def as_extended_json(**_options)
173
+ { '$symbol' => to_s }
174
+ end
175
+ end
176
+
89
177
  module ClassMethods
90
178
 
91
179
  # Deserialize a symbol from BSON.
92
180
  #
93
181
  # @param [ ByteBuffer ] buffer The byte buffer.
94
182
  #
95
- # @return [ Regexp ] The decoded symbol.
183
+ # @option options [ nil | :bson ] :mode Decoding mode to use.
184
+ #
185
+ # @return [ Symbol | BSON::Symbol::Raw ] The decoded symbol.
96
186
  #
97
187
  # @see http://bsonspec.org/#/specification
98
188
  #
99
189
  # @since 2.0.0
100
- def from_bson(buffer)
101
- buffer.get_string.intern
190
+ def from_bson(buffer, **options)
191
+ sym = buffer.get_string.intern
192
+
193
+ if options[:mode] == :bson
194
+ Raw.new(sym)
195
+ else
196
+ sym
197
+ end
102
198
  end
103
199
  end
104
200
 
105
201
  # Register this type when the module is loaded.
106
202
  #
107
203
  # @since 2.0.0
108
- Registry::MAPPINGS.store(BSON_TYPE, ::Symbol)
204
+ Registry::MAPPINGS[BSON_TYPE.ord] = ::Symbol
109
205
  end
110
206
 
111
207
  # Enrich the core Symbol class with this module.