mongodb-mongo_ext 0.1.1 → 0.3

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.
data/Rakefile CHANGED
@@ -11,6 +11,9 @@ end
11
11
  require 'rbconfig'
12
12
  include Config
13
13
 
14
+ gem_command = "gem"
15
+ gem_command = "gem1.9" if CONFIG["MAJOR"] == "1" && CONFIG["MINOR"] == "9"
16
+
14
17
  # NOTE: some of the tests assume Mongo is running
15
18
  Rake::TestTask.new do |t|
16
19
  t.test_files = FileList['tests/test*.rb']
@@ -18,8 +21,10 @@ end
18
21
 
19
22
  desc "Generate documentation"
20
23
  task :rdoc do
24
+ version = eval(File.read("mongo-ruby-driver.gemspec")).version
25
+ out = File.join('html', version.to_s)
21
26
  FileUtils.rm_rf('html')
22
- system "rdoc --main README.rdoc --op html --inline-source --quiet README.rdoc `find lib -name '*.rb'`"
27
+ system "rdoc --main README.rdoc --op #{out} --inline-source --quiet README.rdoc `find lib -name '*.rb'`"
23
28
  end
24
29
 
25
30
  desc "Publish documentation to mongo.rubyforge.org"
@@ -33,8 +38,8 @@ namespace :gem do
33
38
  desc "Install the gem locally"
34
39
  task :install do
35
40
  sh <<EOS
36
- gem build mongo-ruby-driver.gemspec &&
37
- sudo gem install mongo-*.gem &&
41
+ #{gem_command} build mongo-ruby-driver.gemspec &&
42
+ sudo #{gem_command} install mongo-*.gem &&
38
43
  rm mongo-*.gem
39
44
  EOS
40
45
  end
@@ -42,8 +47,8 @@ EOS
42
47
  desc "Install the optional c extensions"
43
48
  task :install_extensions do
44
49
  sh <<EOS
45
- gem build mongo-extensions.gemspec &&
46
- sudo gem install mongo_ext-*.gem &&
50
+ #{gem_command} build mongo-extensions.gemspec &&
51
+ sudo #{gem_command} install mongo_ext-*.gem &&
47
52
  rm mongo_ext-*.gem
48
53
  EOS
49
54
  end
data/ext/cbson/cbson.c CHANGED
@@ -24,6 +24,7 @@
24
24
  #include "st.h"
25
25
  #include "regex.h"
26
26
  #include <assert.h>
27
+ #include <math.h>
27
28
 
28
29
  #define INITIAL_BUFFER_SIZE 256
29
30
 
@@ -36,6 +37,23 @@ static VALUE Code;
36
37
  static VALUE RegexpOfHolding;
37
38
  static VALUE OrderedHash;
38
39
 
40
+ // this sucks. but for some reason these moved around between 1.8 and 1.9
41
+ #ifdef ONIGURUMA_H
42
+ #define IGNORECASE ONIG_OPTION_IGNORECASE
43
+ #define MULTILINE ONIG_OPTION_MULTILINE
44
+ #define EXTENDED ONIG_OPTION_EXTEND
45
+ #else
46
+ #define IGNORECASE RE_OPTION_IGNORECASE
47
+ #define MULTILINE RE_OPTION_MULTILINE
48
+ #define EXTENDED RE_OPTION_EXTENDED
49
+ #endif
50
+
51
+ // this sucks too.
52
+ #ifndef RREGEXP_SRC_PTR
53
+ #define RREGEXP_SRC_PTR(r) RREGEXP(r)->str
54
+ #define RREGEXP_SRC_LEN(r) RREGEXP(r)->len
55
+ #endif
56
+
39
57
  typedef struct {
40
58
  char* buffer;
41
59
  int size;
@@ -49,7 +67,7 @@ static int cmp_char(const void* a, const void* b) {
49
67
  return *(char*)a - *(char*)b;
50
68
  }
51
69
 
52
- static void write_doc(bson_buffer* buffer, VALUE hash);
70
+ static void write_doc(bson_buffer* buffer, VALUE hash, VALUE check_keys);
53
71
  static int write_element(VALUE key, VALUE value, VALUE extra);
54
72
  static VALUE elements_to_hash(const char* buffer, int max);
55
73
 
@@ -109,14 +127,19 @@ static void buffer_write_bytes(bson_buffer* buffer, const char* bytes, int size)
109
127
  buffer->position += size;
110
128
  }
111
129
 
130
+ static VALUE pack_extra(bson_buffer* buffer, VALUE check_keys) {
131
+ return rb_ary_new3(2, INT2NUM((int)buffer), check_keys);
132
+ }
133
+
112
134
  static void write_name_and_type(bson_buffer* buffer, VALUE name, char type) {
113
135
  buffer_write_bytes(buffer, &type, 1);
114
- buffer_write_bytes(buffer, RSTRING(name)->ptr, RSTRING(name)->len);
136
+ buffer_write_bytes(buffer, RSTRING_PTR(name), RSTRING_LEN(name));
115
137
  buffer_write_bytes(buffer, &zero, 1);
116
138
  }
117
139
 
118
140
  static int write_element_allow_id(VALUE key, VALUE value, VALUE extra, int allow_id) {
119
- bson_buffer* buffer = (bson_buffer*)extra;
141
+ bson_buffer* buffer = (bson_buffer*)NUM2INT(rb_ary_entry(extra, 0));
142
+ VALUE check_keys = rb_ary_entry(extra, 1);
120
143
 
121
144
  if (TYPE(key) == T_SYMBOL) {
122
145
  // TODO better way to do this... ?
@@ -127,13 +150,29 @@ static int write_element_allow_id(VALUE key, VALUE value, VALUE extra, int allow
127
150
  rb_raise(rb_eTypeError, "keys must be strings or symbols");
128
151
  }
129
152
 
130
- if (!allow_id && strcmp("_id", RSTRING(key)->ptr) == 0) {
153
+ if (!allow_id && strcmp("_id", RSTRING_PTR(key)) == 0) {
131
154
  return ST_CONTINUE;
132
155
  }
133
156
 
157
+ if (check_keys == Qtrue) {
158
+ if (RSTRING_LEN(key) > 0 && RSTRING_PTR(key)[0] == '$') {
159
+ rb_raise(rb_eRuntimeError, "key must not start with '$'");
160
+ }
161
+ int i;
162
+ for (i = 0; i < RSTRING_LEN(key); i++) {
163
+ if (RSTRING_PTR(key)[i] == '.') {
164
+ rb_raise(rb_eRuntimeError, "key must not contain '.'");
165
+ }
166
+ }
167
+ }
168
+
134
169
  switch(TYPE(value)) {
135
170
  case T_BIGNUM:
136
171
  {
172
+ if (rb_funcall(value, rb_intern(">"), 1, INT2NUM(2147483647)) == Qtrue ||
173
+ rb_funcall(value, rb_intern("<"), 1, INT2NUM(-2147483648)) == Qtrue) {
174
+ rb_raise(rb_eRangeError, "MongoDB can only handle 4-byte ints - try converting to a double before saving");
175
+ }
137
176
  write_name_and_type(buffer, key, 0x10);
138
177
  VALUE as_f = rb_funcall(value, rb_intern("to_f"), 0);
139
178
  int int_value = NUM2LL(as_f);
@@ -174,7 +213,7 @@ static int write_element_allow_id(VALUE key, VALUE value, VALUE extra, int allow
174
213
  case T_HASH:
175
214
  {
176
215
  write_name_and_type(buffer, key, 0x03);
177
- write_doc(buffer, value);
216
+ write_doc(buffer, value, check_keys);
178
217
  break;
179
218
  }
180
219
  case T_ARRAY:
@@ -192,7 +231,7 @@ static int write_element_allow_id(VALUE key, VALUE value, VALUE extra, int allow
192
231
  char* name;
193
232
  asprintf(&name, "%d", i);
194
233
  VALUE key = rb_str_new2(name);
195
- write_element(key, values[i], (VALUE)buffer);
234
+ write_element(key, values[i], pack_extra(buffer, check_keys));
196
235
  free(name);
197
236
  }
198
237
 
@@ -211,11 +250,11 @@ static int write_element_allow_id(VALUE key, VALUE value, VALUE extra, int allow
211
250
  int start_position = buffer->position;
212
251
  int length_location = buffer_save_bytes(buffer, 4);
213
252
 
214
- int length = RSTRING(value)->len + 1;
253
+ int length = RSTRING_LEN(value) + 1;
215
254
  buffer_write_bytes(buffer, (char*)&length, 4);
216
- buffer_write_bytes(buffer, RSTRING(value)->ptr, length - 1);
255
+ buffer_write_bytes(buffer, RSTRING_PTR(value), length - 1);
217
256
  buffer_write_bytes(buffer, &zero, 1);
218
- write_doc(buffer, rb_funcall(value, rb_intern("scope"), 0));
257
+ write_doc(buffer, rb_funcall(value, rb_intern("scope"), 0), Qfalse);
219
258
 
220
259
  int total_length = buffer->position - start_position;
221
260
  memcpy(buffer->buffer + length_location, &total_length, 4);
@@ -223,9 +262,9 @@ static int write_element_allow_id(VALUE key, VALUE value, VALUE extra, int allow
223
262
  break;
224
263
  } else {
225
264
  write_name_and_type(buffer, key, 0x02);
226
- int length = RSTRING(value)->len + 1;
265
+ int length = RSTRING_LEN(value) + 1;
227
266
  buffer_write_bytes(buffer, (char*)&length, 4);
228
- buffer_write_bytes(buffer, RSTRING(value)->ptr, length - 1);
267
+ buffer_write_bytes(buffer, RSTRING_PTR(value), length - 1);
229
268
  buffer_write_bytes(buffer, &zero, 1);
230
269
  break;
231
270
  }
@@ -249,7 +288,7 @@ static int write_element_allow_id(VALUE key, VALUE value, VALUE extra, int allow
249
288
  const char subtype = strcmp(cls, "ByteBuffer") ?
250
289
  (const char)FIX2INT(rb_funcall(value, rb_intern("subtype"), 0)) : 2;
251
290
  VALUE string_data = rb_funcall(value, rb_intern("to_s"), 0);
252
- int length = RSTRING(string_data)->len;
291
+ int length = RSTRING_LEN(string_data);
253
292
  if (subtype == 2) {
254
293
  const int other_length = length + 4;
255
294
  buffer_write_bytes(buffer, (const char*)&other_length, 4);
@@ -259,7 +298,7 @@ static int write_element_allow_id(VALUE key, VALUE value, VALUE extra, int allow
259
298
  if (subtype != 2) {
260
299
  buffer_write_bytes(buffer, &subtype, 1);
261
300
  }
262
- buffer_write_bytes(buffer, RSTRING(string_data)->ptr, length);
301
+ buffer_write_bytes(buffer, RSTRING_PTR(string_data), length);
263
302
  break;
264
303
  }
265
304
  if (strcmp(cls, "XGen::Mongo::Driver::ObjectID") == 0) {
@@ -267,7 +306,7 @@ static int write_element_allow_id(VALUE key, VALUE value, VALUE extra, int allow
267
306
  VALUE as_array = rb_funcall(value, rb_intern("to_a"), 0);
268
307
  int i;
269
308
  for (i = 0; i < 12; i++) {
270
- char byte = (char)FIX2INT(RARRAY(as_array)->ptr[i]);
309
+ char byte = (char)FIX2INT(RARRAY_PTR(as_array)[i]);
271
310
  buffer_write_bytes(buffer, &byte, 1);
272
311
  }
273
312
  break;
@@ -281,9 +320,9 @@ static int write_element_allow_id(VALUE key, VALUE value, VALUE extra, int allow
281
320
  int length_location = buffer_save_bytes(buffer, 4);
282
321
 
283
322
  VALUE ns = rb_funcall(value, rb_intern("namespace"), 0);
284
- write_element(rb_str_new2("$ref"), ns, (VALUE)buffer);
323
+ write_element(rb_str_new2("$ref"), ns, pack_extra(buffer, Qfalse));
285
324
  VALUE oid = rb_funcall(value, rb_intern("object_id"), 0);
286
- write_element(rb_str_new2("$id"), oid, (VALUE)buffer);
325
+ write_element(rb_str_new2("$id"), oid, pack_extra(buffer, Qfalse));
287
326
 
288
327
  // write null byte and fill in length
289
328
  buffer_write_bytes(buffer, &zero, 1);
@@ -303,7 +342,7 @@ static int write_element_allow_id(VALUE key, VALUE value, VALUE extra, int allow
303
342
  if (strcmp(cls, "Time") == 0) {
304
343
  write_name_and_type(buffer, key, 0x09);
305
344
  double t = NUM2DBL(rb_funcall(value, rb_intern("to_f"), 0));
306
- long long time_since_epoch = (long long)(t * 1000);
345
+ long long time_since_epoch = (long long)round(t * 1000);
307
346
  buffer_write_bytes(buffer, (const char*)&time_since_epoch, 8);
308
347
  break;
309
348
  }
@@ -312,21 +351,21 @@ static int write_element_allow_id(VALUE key, VALUE value, VALUE extra, int allow
312
351
  {
313
352
  write_name_and_type(buffer, key, 0x0B);
314
353
 
315
- int length = RREGEXP(value)->len;
316
- char* pattern = RREGEXP(value)->str;
354
+ int length = RREGEXP_SRC_LEN(value);
355
+ char* pattern = (char*)RREGEXP_SRC_PTR(value);
317
356
  buffer_write_bytes(buffer, pattern, length);
318
357
  buffer_write_bytes(buffer, &zero, 1);
319
358
 
320
359
  long flags = RREGEXP(value)->ptr->options;
321
- if (flags & RE_OPTION_IGNORECASE) {
360
+ if (flags & IGNORECASE) {
322
361
  char ignorecase = 'i';
323
362
  buffer_write_bytes(buffer, &ignorecase, 1);
324
363
  }
325
- if (flags & RE_OPTION_MULTILINE) {
364
+ if (flags & MULTILINE) {
326
365
  char multiline = 'm';
327
366
  buffer_write_bytes(buffer, &multiline, 1);
328
367
  }
329
- if (flags & RE_OPTION_EXTENDED) {
368
+ if (flags & EXTENDED) {
330
369
  char extended = 'x';
331
370
  buffer_write_bytes(buffer, &extended, 1);
332
371
  }
@@ -335,8 +374,8 @@ static int write_element_allow_id(VALUE key, VALUE value, VALUE extra, int allow
335
374
  if (TYPE(has_extra) == T_TRUE) {
336
375
  VALUE extra = rb_funcall(value, rb_intern("extra_options_str"), 0);
337
376
  int old_position = buffer->position;
338
- buffer_write_bytes(buffer, RSTRING(extra)->ptr, RSTRING(extra)->len);
339
- qsort(buffer->buffer + old_position, RSTRING(extra)->len, sizeof(char), cmp_char);
377
+ buffer_write_bytes(buffer, RSTRING_PTR(extra), RSTRING_LEN(extra));
378
+ qsort(buffer->buffer + old_position, RSTRING_LEN(extra), sizeof(char), cmp_char);
340
379
  }
341
380
  buffer_write_bytes(buffer, &zero, 1);
342
381
 
@@ -355,33 +394,33 @@ static int write_element(VALUE key, VALUE value, VALUE extra) {
355
394
  return write_element_allow_id(key, value, extra, 0);
356
395
  }
357
396
 
358
- static void write_doc(bson_buffer* buffer, VALUE hash) {
397
+ static void write_doc(bson_buffer* buffer, VALUE hash, VALUE check_keys) {
359
398
  int start_position = buffer->position;
360
399
  int length_location = buffer_save_bytes(buffer, 4);
361
400
 
362
401
  VALUE key = rb_str_new2("_id");
363
- VALUE id = rb_hash_aref(hash, key);
364
- if (TYPE(id) != T_NIL) {
365
- write_element_allow_id(key, id, (VALUE)buffer, 1);
402
+ if (rb_funcall(hash, rb_intern("has_key?"), 1, key) == Qtrue) {
403
+ VALUE id = rb_hash_aref(hash, key);
404
+ write_element_allow_id(key, id, pack_extra(buffer, check_keys), 1);
366
405
  }
367
406
  key = ID2SYM(rb_intern("_id"));
368
- id = rb_hash_aref(hash, key);
369
- if (TYPE(id) != T_NIL) {
370
- write_element_allow_id(key, id, (VALUE)buffer, 1);
407
+ if (rb_funcall(hash, rb_intern("has_key?"), 1, key) == Qtrue) {
408
+ VALUE id = rb_hash_aref(hash, key);
409
+ write_element_allow_id(key, id, pack_extra(buffer, check_keys), 1);
371
410
  }
372
411
 
373
-
374
412
  // we have to check for an OrderedHash and handle that specially
375
413
  if (strcmp(rb_class2name(RBASIC(hash)->klass), "OrderedHash") == 0) {
376
414
  VALUE keys = rb_funcall(hash, rb_intern("keys"), 0);
377
415
  int i;
378
- for(i = 0; i < RARRAY(keys)->len; i++) {
379
- VALUE key = RARRAY(keys)->ptr[i];
416
+ for(i = 0; i < RARRAY_LEN(keys); i++) {
417
+ VALUE key = RARRAY_PTR(keys)[i];
380
418
  VALUE value = rb_hash_aref(hash, key);
381
- write_element(key, value, (VALUE)buffer);
419
+
420
+ write_element(key, value, pack_extra(buffer, check_keys));
382
421
  }
383
422
  } else {
384
- rb_hash_foreach(hash, write_element, (VALUE)buffer);
423
+ rb_hash_foreach(hash, write_element, pack_extra(buffer, check_keys));
385
424
  }
386
425
 
387
426
  // write null byte and fill in length
@@ -390,11 +429,11 @@ static void write_doc(bson_buffer* buffer, VALUE hash) {
390
429
  memcpy(buffer->buffer + length_location, &length, 4);
391
430
  }
392
431
 
393
- static VALUE method_serialize(VALUE self, VALUE doc) {
432
+ static VALUE method_serialize(VALUE self, VALUE doc, VALUE check_keys) {
394
433
  bson_buffer* buffer = buffer_new();
395
434
  assert(buffer);
396
435
 
397
- write_doc(buffer, doc);
436
+ write_doc(buffer, doc, check_keys);
398
437
 
399
438
  VALUE result = rb_str_new(buffer->buffer, buffer->position);
400
439
  buffer_free(buffer);
@@ -525,13 +564,13 @@ static VALUE get_value(const char* buffer, int* position, int type) {
525
564
  for (i = 0; i < flags_length; i++) {
526
565
  char flag = buffer[*position + i];
527
566
  if (flag == 'i') {
528
- flags |= RE_OPTION_IGNORECASE;
567
+ flags |= IGNORECASE;
529
568
  }
530
569
  else if (flag == 'm') {
531
- flags |= RE_OPTION_MULTILINE;
570
+ flags |= MULTILINE;
532
571
  }
533
572
  else if (flag == 'x') {
534
- flags |= RE_OPTION_EXTENDED;
573
+ flags |= EXTENDED;
535
574
  }
536
575
  else if (strlen(extra) < 9) {
537
576
  strncat(extra, &flag, 1);
@@ -594,6 +633,16 @@ static VALUE get_value(const char* buffer, int* position, int type) {
594
633
  *position += 4;
595
634
  break;
596
635
  }
636
+ case 17:
637
+ {
638
+ int i;
639
+ int j;
640
+ memcpy(&i, buffer + *position, 4);
641
+ memcpy(&j, buffer + *position + 4, 4);
642
+ value = rb_ary_new3(2, LL2NUM(i), LL2NUM(j));
643
+ *position += 8;
644
+ break;
645
+ }
597
646
  default:
598
647
  {
599
648
  rb_raise(rb_eTypeError, "no c decoder for this type yet (%d)", type);
@@ -618,8 +667,8 @@ static VALUE elements_to_hash(const char* buffer, int max) {
618
667
  }
619
668
 
620
669
  static VALUE method_deserialize(VALUE self, VALUE bson) {
621
- const char* buffer = RSTRING(bson)->ptr;
622
- int remaining = RSTRING(bson)->len;
670
+ const char* buffer = RSTRING_PTR(bson);
671
+ int remaining = RSTRING_LEN(bson);
623
672
 
624
673
  // NOTE we just swallow the size and end byte here
625
674
  buffer += 4;
@@ -651,6 +700,6 @@ void Init_cbson() {
651
700
  OrderedHash = rb_const_get(rb_cObject, rb_intern("OrderedHash"));
652
701
 
653
702
  VALUE CBson = rb_define_module("CBson");
654
- rb_define_module_function(CBson, "serialize", method_serialize, 1);
703
+ rb_define_module_function(CBson, "serialize", method_serialize, 2);
655
704
  rb_define_module_function(CBson, "deserialize", method_deserialize, 1);
656
705
  }
data/ext/cbson/extconf.rb CHANGED
@@ -1,4 +1,6 @@
1
1
  require 'mkmf'
2
2
 
3
+ find_header("st.h")
4
+ find_header("regex.h")
3
5
  dir_config('cbson')
4
6
  create_makefile('mongo_ext/cbson')
@@ -7,7 +7,7 @@ TEST_FILES = []
7
7
 
8
8
  Gem::Specification.new do |s|
9
9
  s.name = 'mongo_ext'
10
- s.version = '0.1.1'
10
+ s.version = '0.3'
11
11
  s.platform = Gem::Platform::RUBY
12
12
  s.summary = 'C extensions for the MongoDB Ruby driver'
13
13
  s.description = 'C extensions to accelerate the MondoDB Ruby driver. For more information about Mongo, see http://www.mongodb.org.'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mongodb-mongo_ext
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: "0.3"
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Dirolf
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-02-25 00:00:00 -08:00
12
+ date: 2009-05-16 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies: []
15
15