mongodb-mongo_ext 0.1.1 → 0.3

Sign up to get free protection for your applications and to get access to all the features.
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