bson 4.3.0 → 4.4.1

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 (81) hide show
  1. checksums.yaml +5 -5
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/Rakefile +16 -9
  5. data/ext/bson/bson_native.c +102 -28
  6. data/lib/bson.rb +1 -1
  7. data/lib/bson/active_support.rb +17 -0
  8. data/lib/bson/array.rb +1 -1
  9. data/lib/bson/binary.rb +1 -1
  10. data/lib/bson/boolean.rb +1 -1
  11. data/lib/bson/code.rb +1 -1
  12. data/lib/bson/code_with_scope.rb +1 -1
  13. data/lib/bson/config.rb +1 -1
  14. data/lib/bson/date.rb +1 -1
  15. data/lib/bson/date_time.rb +1 -1
  16. data/lib/bson/decimal128.rb +1 -1
  17. data/lib/bson/decimal128/builder.rb +1 -1
  18. data/lib/bson/document.rb +42 -4
  19. data/lib/bson/environment.rb +1 -1
  20. data/lib/bson/false_class.rb +1 -1
  21. data/lib/bson/float.rb +1 -1
  22. data/lib/bson/hash.rb +1 -1
  23. data/lib/bson/int32.rb +17 -4
  24. data/lib/bson/int64.rb +17 -4
  25. data/lib/bson/integer.rb +2 -2
  26. data/lib/bson/json.rb +1 -1
  27. data/lib/bson/max_key.rb +1 -1
  28. data/lib/bson/min_key.rb +1 -1
  29. data/lib/bson/nil_class.rb +1 -1
  30. data/lib/bson/object.rb +1 -1
  31. data/lib/bson/object_id.rb +1 -1
  32. data/lib/bson/open_struct.rb +1 -1
  33. data/lib/bson/regexp.rb +1 -1
  34. data/lib/bson/registry.rb +1 -1
  35. data/lib/bson/specialized.rb +1 -1
  36. data/lib/bson/string.rb +1 -1
  37. data/lib/bson/symbol.rb +6 -3
  38. data/lib/bson/time.rb +1 -1
  39. data/lib/bson/time_with_zone.rb +54 -0
  40. data/lib/bson/timestamp.rb +1 -1
  41. data/lib/bson/true_class.rb +1 -1
  42. data/lib/bson/undefined.rb +1 -1
  43. data/lib/bson/version.rb +2 -2
  44. data/spec/bson/array_spec.rb +1 -1
  45. data/spec/bson/binary_spec.rb +1 -1
  46. data/spec/bson/boolean_spec.rb +1 -1
  47. data/spec/bson/byte_buffer_spec.rb +40 -0
  48. data/spec/bson/code_spec.rb +1 -1
  49. data/spec/bson/code_with_scope_spec.rb +1 -1
  50. data/spec/bson/date_spec.rb +1 -1
  51. data/spec/bson/date_time_spec.rb +1 -1
  52. data/spec/bson/decimal128_spec.rb +1 -1
  53. data/spec/bson/document_spec.rb +60 -1
  54. data/spec/bson/false_class_spec.rb +1 -1
  55. data/spec/bson/float_spec.rb +1 -1
  56. data/spec/bson/hash_spec.rb +1 -1
  57. data/spec/bson/int32_spec.rb +139 -3
  58. data/spec/bson/int64_spec.rb +139 -3
  59. data/spec/bson/integer_spec.rb +3 -3
  60. data/spec/bson/json_spec.rb +1 -1
  61. data/spec/bson/max_key_spec.rb +1 -1
  62. data/spec/bson/min_key_spec.rb +1 -1
  63. data/spec/bson/nil_class_spec.rb +1 -1
  64. data/spec/bson/object_id_spec.rb +1 -1
  65. data/spec/bson/object_spec.rb +1 -1
  66. data/spec/bson/open_struct_spec.rb +1 -1
  67. data/spec/bson/regexp_spec.rb +1 -1
  68. data/spec/bson/registry_spec.rb +1 -1
  69. data/spec/bson/string_spec.rb +1 -1
  70. data/spec/bson/symbol_spec.rb +3 -3
  71. data/spec/bson/time_spec.rb +1 -1
  72. data/spec/bson/time_with_zone_spec.rb +68 -0
  73. data/spec/bson/timestamp_spec.rb +1 -1
  74. data/spec/bson/true_class_spec.rb +1 -1
  75. data/spec/bson/undefined_spec.rb +1 -1
  76. data/spec/bson_spec.rb +1 -1
  77. data/spec/spec_helper.rb +15 -1
  78. data/spec/support/shared_examples.rb +1 -1
  79. data/spec/support/spec_config.rb +9 -0
  80. metadata +73 -68
  81. metadata.gz.sig +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: b2cdf98517b40720fa4e2cdfaae83903ac8d1907
4
- data.tar.gz: 821e69506dcde2eca70b737a97a8d0f3f4cce3f3
2
+ SHA256:
3
+ metadata.gz: 84427d100a7c6e64e513b120537d2347cae31bcb08f2d9270d46946f0cecab6f
4
+ data.tar.gz: 9bfb6408d1c44c3ff4cc25de3beaeb37cbd5ff18d271c44af989b37f050760f6
5
5
  SHA512:
6
- metadata.gz: 285a6ba405445c535fc2157c81bee4ce48825716d2048acd3060221371b1cecd6081c5e1c487f67e373292ed97841d6e45b78abdb98cf3f81bf854d10c5f4473
7
- data.tar.gz: 194eed21affeaf868a337ba758034f11496c077f02945a403c923a29de0c1f1e11f8da2a9318ecc5aefd3964b56b4aafd3ea167ee24edde962e580ac08f4f3ce
6
+ metadata.gz: fb891b58d7763ad8a26858941a8067fa601db56cdef379f5a56fb59de1c25851d98cbf4653fb592bba985717d1e06f85681138979e9a061ab91cb1ea186dd4c2
7
+ data.tar.gz: b33f84f1c0b06b0c5c1095bf6fa047d066ba3be9ca2f1cb7860bfab3c8a36066b84be74a61cc539500f0eeb30bba441ec4ba213e24fb004379f47b918d133a14
Binary file
data.tar.gz.sig CHANGED
Binary file
data/Rakefile CHANGED
@@ -20,6 +20,7 @@ $LOAD_PATH.unshift(File.expand_path("../lib", __FILE__))
20
20
  require "rake"
21
21
  require "rake/extensiontask"
22
22
  require "rspec/core/rake_task"
23
+ require 'fileutils'
23
24
 
24
25
  def jruby?
25
26
  defined?(JRUBY_VERSION)
@@ -62,15 +63,9 @@ else
62
63
  end
63
64
 
64
65
  task :clean_all => :clean do
65
- begin
66
- Dir.chdir(Pathname(__FILE__).dirname + "lib") do
67
- `rm bson_native.#{extension}`
68
- `rm bson_native.o`
69
- `rm bson-ruby.jar`
70
- end
71
- rescue Exception => e
72
- puts e.message
73
- end
66
+ FileUtils.rm_f(File.join(File.dirname(__FILE__), 'lib', "bson_native.#{extension}"))
67
+ FileUtils.rm_f(File.join(File.dirname(__FILE__), 'lib', "bson_native.o"))
68
+ FileUtils.rm_f(File.join(File.dirname(__FILE__), 'lib', "bson-ruby.jar"))
74
69
  end
75
70
 
76
71
  task :spec => :compile do
@@ -126,3 +121,15 @@ namespace :benchmark do
126
121
  end
127
122
 
128
123
  task :default => [ :clean_all, :spec ]
124
+
125
+ desc "Generate all documentation"
126
+ task :docs => 'docs:yard'
127
+
128
+ namespace :docs do
129
+ desc "Generate yard documention"
130
+ task :yard do
131
+ out = File.join('yard-docs', BSON::VERSION)
132
+ FileUtils.rm_rf(out)
133
+ system "yardoc -o #{out} --title bson-#{BSON::VERSION}"
134
+ end
135
+ end
@@ -73,12 +73,15 @@ static VALUE rb_bson_byte_buffer_get_hash(VALUE self);
73
73
  static VALUE rb_bson_byte_buffer_get_array(VALUE self);
74
74
  static VALUE rb_bson_byte_buffer_put_byte(VALUE self, VALUE byte);
75
75
  static VALUE rb_bson_byte_buffer_put_bytes(VALUE self, VALUE bytes);
76
+ static VALUE rb_bson_byte_buffer_put_bson_partial_string(VALUE self, const char *str, int32_t length);
76
77
  static VALUE rb_bson_byte_buffer_put_cstring(VALUE self, VALUE string);
77
78
  static VALUE rb_bson_byte_buffer_put_decimal128(VALUE self, VALUE low, VALUE high);
78
79
  static VALUE rb_bson_byte_buffer_put_double(VALUE self, VALUE f);
79
80
  static VALUE rb_bson_byte_buffer_put_int32(VALUE self, VALUE i);
80
81
  static VALUE rb_bson_byte_buffer_put_int64(VALUE self, VALUE i);
82
+ static VALUE rb_bson_byte_buffer_put_bson_string(VALUE self, const char *str, int32_t length);
81
83
  static VALUE rb_bson_byte_buffer_put_string(VALUE self, VALUE string);
84
+ static VALUE rb_bson_byte_buffer_put_symbol(VALUE self, VALUE symbol);
82
85
  static VALUE rb_bson_byte_buffer_put_hash(VALUE self, VALUE hash, VALUE validating_keys);
83
86
  static VALUE rb_bson_byte_buffer_put_array(VALUE self, VALUE array, VALUE validating_keys);
84
87
  static VALUE rb_bson_byte_buffer_read_position(VALUE self);
@@ -118,7 +121,7 @@ static void pvt_put_byte(byte_buffer_t *b, const char byte);
118
121
  static void pvt_put_int32(byte_buffer_t *b, const int32_t i32);
119
122
  static void pvt_put_int64(byte_buffer_t *b, const int64_t i);
120
123
  static void pvt_put_double(byte_buffer_t *b, double f);
121
- static void pvt_put_cstring(byte_buffer_t *b, VALUE string);
124
+ static void pvt_put_cstring(byte_buffer_t *b, const char *str, int32_t length);
122
125
  static void pvt_put_bson_key(byte_buffer_t *b, VALUE string, VALUE validating_keys);
123
126
 
124
127
  /**
@@ -173,6 +176,7 @@ void Init_bson_native()
173
176
  rb_define_method(rb_byte_buffer_class, "put_int32", rb_bson_byte_buffer_put_int32, 1);
174
177
  rb_define_method(rb_byte_buffer_class, "put_int64", rb_bson_byte_buffer_put_int64, 1);
175
178
  rb_define_method(rb_byte_buffer_class, "put_string", rb_bson_byte_buffer_put_string, 1);
179
+ rb_define_method(rb_byte_buffer_class, "put_symbol", rb_bson_byte_buffer_put_symbol, 1);
176
180
  rb_define_method(rb_byte_buffer_class, "read_position", rb_bson_byte_buffer_read_position, 0);
177
181
  rb_define_method(rb_byte_buffer_class, "replace_int32", rb_bson_byte_buffer_replace_int32, 2);
178
182
  rb_define_method(rb_byte_buffer_class, "rewind!", rb_bson_byte_buffer_rewind, 0);
@@ -461,6 +465,7 @@ void pvt_put_array_index(byte_buffer_t *b, int32_t index)
461
465
  {
462
466
  char buffer[16];
463
467
  const char *c_str = NULL;
468
+ size_t length;
464
469
 
465
470
  if (index < 1000) {
466
471
  c_str = index_strings[index];
@@ -468,7 +473,7 @@ void pvt_put_array_index(byte_buffer_t *b, int32_t index)
468
473
  c_str = buffer;
469
474
  snprintf(buffer, sizeof(buffer), "%d", index);
470
475
  }
471
- size_t length = strlen(c_str) + 1;
476
+ length = strlen(c_str) + 1;
472
477
  ENSURE_BSON_WRITE(b, length);
473
478
  memcpy(WRITE_PTR(b), c_str, length);
474
479
  b->write_position += length;
@@ -533,8 +538,9 @@ VALUE rb_bson_byte_buffer_get_byte(VALUE self)
533
538
  }
534
539
 
535
540
  uint8_t pvt_get_type_byte(byte_buffer_t *b){
541
+ int8_t byte;
536
542
  ENSURE_BSON_READ(b, 1);
537
- int8_t byte = *READ_PTR(b);
543
+ byte = *READ_PTR(b);
538
544
  b->read_position += 1;
539
545
  return (uint8_t)byte;
540
546
  }
@@ -759,7 +765,12 @@ VALUE pvt_read_field(byte_buffer_t *b, VALUE rb_buffer, uint8_t type){
759
765
  VALUE rb_bson_byte_buffer_put_byte(VALUE self, VALUE byte)
760
766
  {
761
767
  byte_buffer_t *b;
762
- const char *str = RSTRING_PTR(byte);
768
+ const char *str;
769
+
770
+ if (!RB_TYPE_P(byte, T_STRING))
771
+ rb_raise(rb_eArgError, "Invalid input");
772
+
773
+ str = RSTRING_PTR(byte);
763
774
 
764
775
  TypedData_Get_Struct(self, byte_buffer_t, &rb_byte_buffer_data_type, b);
765
776
  ENSURE_BSON_WRITE(b, 1);
@@ -782,8 +793,14 @@ void pvt_put_byte( byte_buffer_t *b, const char byte)
782
793
  VALUE rb_bson_byte_buffer_put_bytes(VALUE self, VALUE bytes)
783
794
  {
784
795
  byte_buffer_t *b;
785
- const char *str = RSTRING_PTR(bytes);
786
- const size_t length = RSTRING_LEN(bytes);
796
+ const char *str;
797
+ size_t length;
798
+
799
+ if (!RB_TYPE_P(bytes, T_STRING) && !RB_TYPE_P(bytes, RUBY_T_DATA))
800
+ rb_raise(rb_eArgError, "Invalid input");
801
+
802
+ str = RSTRING_PTR(bytes);
803
+ length = RSTRING_LEN(bytes);
787
804
 
788
805
  TypedData_Get_Struct(self, byte_buffer_t, &rb_byte_buffer_data_type, b);
789
806
  ENSURE_BSON_WRITE(b, length);
@@ -793,42 +810,74 @@ VALUE rb_bson_byte_buffer_put_bytes(VALUE self, VALUE bytes)
793
810
  }
794
811
 
795
812
  /**
796
- * Writes a cstring to the byte buffer.
813
+ * Writes a string (which may form part of a BSON object) to the byte buffer.
814
+ * length does not include the null terminator.
797
815
  */
798
- VALUE rb_bson_byte_buffer_put_cstring(VALUE self, VALUE string)
816
+ VALUE rb_bson_byte_buffer_put_bson_partial_string(VALUE self, const char *str, int32_t length)
799
817
  {
800
818
  byte_buffer_t *b;
801
819
  TypedData_Get_Struct(self, byte_buffer_t, &rb_byte_buffer_data_type, b);
802
- pvt_put_cstring(b, string);
820
+ pvt_put_cstring(b, str, length);
803
821
  return self;
804
822
  }
805
823
 
806
- void pvt_put_cstring(byte_buffer_t *b, VALUE string)
824
+ /**
825
+ * length does not include the null terminator.
826
+ */
827
+ void pvt_put_cstring(byte_buffer_t *b, const char *str, int32_t length)
807
828
  {
808
- char *c_str = RSTRING_PTR(string);
809
- size_t length = RSTRING_LEN(string) + 1;
810
-
811
- if (!rb_bson_utf8_validate(c_str, length - 1, false)) {
812
- rb_raise(rb_eArgError, "String %s is not a valid UTF-8 CString.", c_str);
829
+ int bytes_to_write;
830
+ if (!rb_bson_utf8_validate(str, length, false)) {
831
+ rb_raise(rb_eArgError, "String %s is not a valid UTF-8 CString.", str);
813
832
  }
814
- ENSURE_BSON_WRITE(b, length);
815
- memcpy(WRITE_PTR(b), c_str, length);
816
- b->write_position += length;
833
+ bytes_to_write = length + 1;
834
+ ENSURE_BSON_WRITE(b, bytes_to_write);
835
+ memcpy(WRITE_PTR(b), str, bytes_to_write);
836
+ b->write_position += bytes_to_write;
817
837
  }
818
838
 
819
839
  /**
820
840
  * Write a hash key to the byte buffer, validating it if requested
821
841
  */
822
842
  void pvt_put_bson_key(byte_buffer_t *b, VALUE string, VALUE validating_keys){
823
- if(RTEST(validating_keys)){
824
- char *c_str = RSTRING_PTR(string);
825
- size_t length = RSTRING_LEN(string);
826
- if(length > 0 && (c_str[0] == '$' || memchr(c_str, '.', length))){
827
- rb_exc_raise(rb_funcall(rb_bson_illegal_key, rb_intern("new"),1, string));
843
+ char *c_str = RSTRING_PTR(string);
844
+ size_t length = RSTRING_LEN(string);
845
+
846
+ if (RTEST(validating_keys)) {
847
+ if (length > 0 && (c_str[0] == '$' || memchr(c_str, '.', length))) {
848
+ rb_exc_raise(rb_funcall(rb_bson_illegal_key, rb_intern("new"), 1, string));
828
849
  }
829
850
  }
830
851
 
831
- pvt_put_cstring(b, string);
852
+ pvt_put_cstring(b, c_str, length);
853
+ }
854
+
855
+ /**
856
+ * Writes a cstring to the byte buffer.
857
+ * This magically supports both Ruby symbols and strings.
858
+ */
859
+ VALUE rb_bson_byte_buffer_put_cstring(VALUE self, VALUE string)
860
+ {
861
+ int32_t length;
862
+
863
+ if (TYPE(string) == T_SYMBOL) {
864
+ const char *sym = rb_id2name(SYM2ID(string));
865
+ length = strlen(sym);
866
+
867
+ return rb_bson_byte_buffer_put_bson_partial_string(self, sym, length);
868
+ } else if (TYPE(string) == T_STRING) {
869
+ const char *str = RSTRING_PTR(string);
870
+ length = RSTRING_LEN(string);
871
+
872
+ return rb_bson_byte_buffer_put_bson_partial_string(self, str, length);
873
+ } else if (TYPE(string) == T_FIXNUM) {
874
+ const char *str = RSTRING_PTR(rb_fix2str(string, 10));
875
+ length = strlen(str);
876
+
877
+ return rb_bson_byte_buffer_put_bson_partial_string(self, str, length);
878
+ } else {
879
+ rb_raise(rb_eTypeError, "Invalid type for string");
880
+ }
832
881
  }
833
882
 
834
883
  /**
@@ -945,15 +994,18 @@ void pvt_validate_length(byte_buffer_t *b)
945
994
  }
946
995
 
947
996
  /**
948
- * Writes a string to the byte buffer.
997
+ * Write BSON string to byte buffer given a C string.
998
+ * length is inclusive of the NULL terminator in the C string.
949
999
  */
950
- VALUE rb_bson_byte_buffer_put_string(VALUE self, VALUE string)
1000
+ static VALUE rb_bson_byte_buffer_put_bson_string(VALUE self, const char *str, int32_t length)
951
1001
  {
952
1002
  byte_buffer_t *b;
953
1003
  int32_t length_le;
954
1004
 
955
- char *str = RSTRING_PTR(string);
956
- const int32_t length = RSTRING_LEN(string) + 1;
1005
+ if (length <= 0) {
1006
+ rb_raise(rb_eArgError, "The length must include the NULL terminator, and thus be at least 1");
1007
+ }
1008
+
957
1009
  length_le = BSON_UINT32_TO_LE(length);
958
1010
 
959
1011
  if (!rb_bson_utf8_validate(str, length - 1, true)) {
@@ -970,6 +1022,28 @@ VALUE rb_bson_byte_buffer_put_string(VALUE self, VALUE string)
970
1022
  return self;
971
1023
  }
972
1024
 
1025
+ /**
1026
+ * Writes a string to the byte buffer.
1027
+ */
1028
+ VALUE rb_bson_byte_buffer_put_string(VALUE self, VALUE string)
1029
+ {
1030
+ const char *str = RSTRING_PTR(string);
1031
+ const int32_t length = RSTRING_LEN(string) + 1;
1032
+
1033
+ return rb_bson_byte_buffer_put_bson_string(self, str, length);
1034
+ }
1035
+
1036
+ /**
1037
+ * Writes a symbol to the byte buffer.
1038
+ */
1039
+ VALUE rb_bson_byte_buffer_put_symbol(VALUE self, VALUE symbol)
1040
+ {
1041
+ const char *sym = rb_id2name(SYM2ID(symbol));
1042
+ const int32_t length = strlen(sym) + 1;
1043
+
1044
+ return rb_bson_byte_buffer_put_bson_string(self, sym, length);
1045
+ }
1046
+
973
1047
  /**
974
1048
  * Get the read position.
975
1049
  */
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2009-2014 MongoDB Inc.
1
+ # Copyright (C) 2009-2019 MongoDB Inc.
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -0,0 +1,17 @@
1
+ # Copyright (C) 2018-2019 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 this file if using BSON with ActiveSupport.
16
+
17
+ require "bson/time_with_zone"
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2009-2014 MongoDB Inc.
1
+ # Copyright (C) 2009-2019 MongoDB Inc.
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2009-2014 MongoDB Inc.
1
+ # Copyright (C) 2009-2019 MongoDB Inc.
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2009-2014 MongoDB Inc.
1
+ # Copyright (C) 2009-2019 MongoDB Inc.
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2009-2014 MongoDB Inc.
1
+ # Copyright (C) 2009-2019 MongoDB Inc.
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2009-2014 MongoDB Inc.
1
+ # Copyright (C) 2009-2019 MongoDB Inc.
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2016 MongoDB Inc.
1
+ # Copyright (C) 2016-2019 MongoDB Inc.
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2009-2014 MongoDB Inc.
1
+ # Copyright (C) 2009-2019 MongoDB Inc.
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2009-2014 MongoDB Inc.
1
+ # Copyright (C) 2009-2019 MongoDB Inc.
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2016 MongoDB Inc.
1
+ # Copyright (C) 2016-2019 MongoDB Inc.
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2016 MongoDB Inc.
1
+ # Copyright (C) 2016-2019 MongoDB Inc.
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2009-2014 MongoDB Inc.
1
+ # Copyright (C) 2009-2019 MongoDB Inc.
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -35,8 +35,25 @@ module BSON
35
35
  class Document < ::Hash
36
36
 
37
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.
38
+ # symbol access, with string access being the faster of the two.
39
+ #
40
+ # @example Get an element for the key.
41
+ # document.fetch("field")
42
+ #
43
+ # @example Get an element for the key by symbol.
44
+ # document.fetch(:field)
45
+ #
46
+ # @param [ String, Symbol ] key The key to look up.
47
+ #
48
+ # @return [ Object ] The found value. Raises KeyError if none found.
49
+ #
50
+ # @since 4.4.0
51
+ def fetch(key)
52
+ super(convert_key(key))
53
+ end
54
+
55
+ # Get a value from the document for the provided key. Can use string or
56
+ # symbol access, with string access being the faster of the two.
40
57
  #
41
58
  # @example Get an element for the key.
42
59
  # document["field"]
@@ -44,7 +61,7 @@ module BSON
44
61
  # @example Get an element for the key by symbol.
45
62
  # document[:field]
46
63
  #
47
- # @param [ String, Symbol ] key The key to lookup.
64
+ # @param [ String, Symbol ] key The key to look up.
48
65
  #
49
66
  # @return [ Object ] The found value, or nil if none found.
50
67
  #
@@ -192,6 +209,27 @@ module BSON
192
209
  end
193
210
  end
194
211
 
212
+ if instance_methods.include?(:slice)
213
+ # Slices a document to include only the given keys.
214
+ # Will normalize symbol keys into strings.
215
+ # (this method is backported from ActiveSupport::Hash)
216
+ #
217
+ # @example Get a document/hash with only the `name` and `age` fields present
218
+ # document # => { _id: <ObjectId>, :name => 'John', :age => 30, :location => 'Earth' }
219
+ # document.slice(:name, 'age') # => { name: 'John', age: 30 }
220
+ # document.slice('name') # => { name: 'John' }
221
+ # document.slice(:foo) # => nil
222
+ #
223
+ # @param [ Array<String, Symbol> ] *keys Keys, that will be kept in the resulting document
224
+ #
225
+ # @return [ BSON::Document ] The document with only the selected keys
226
+ #
227
+ # @since 4.3.1
228
+ def slice(*keys)
229
+ super(*keys.map{|key| convert_key(key)})
230
+ end
231
+ end
232
+
195
233
  private
196
234
 
197
235
  def convert_key(key)