oj 1.0.6 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of oj might be problematic. Click here for more details.

@@ -75,6 +75,7 @@ static VALUE read_false(ParseInfo pi);
75
75
  static VALUE read_nil(ParseInfo pi);
76
76
  static void next_non_white(ParseInfo pi);
77
77
  static char* read_quoted_value(ParseInfo pi);
78
+ static void skip_comment(ParseInfo pi);
78
79
 
79
80
 
80
81
  /* This XML parser is a single pass, destructive, callback parser. It is a
@@ -100,6 +101,9 @@ next_non_white(ParseInfo pi) {
100
101
  case '\n':
101
102
  case '\r':
102
103
  break;
104
+ case '/':
105
+ skip_comment(pi);
106
+ break;
103
107
  default:
104
108
  return;
105
109
  }
@@ -275,6 +279,36 @@ circ_array_get(CircArray ca, unsigned long id) {
275
279
  return obj;
276
280
  }
277
281
 
282
+ static void
283
+ skip_comment(ParseInfo pi) {
284
+ pi->s++; // skip first /
285
+ if ('*' == *pi->s) {
286
+ pi->s++;
287
+ for (; '\0' != *pi->s; pi->s++) {
288
+ if ('*' == *pi->s && '/' == *(pi->s + 1)) {
289
+ pi->s++;
290
+ return;
291
+ } else if ('\0' == *pi->s) {
292
+ raise_error("comment not terminated", pi->str, pi->s);
293
+ }
294
+ }
295
+ } else if ('/' == *pi->s) {
296
+ for (; 1; pi->s++) {
297
+ switch (*pi->s) {
298
+ case '\n':
299
+ case '\r':
300
+ case '\f':
301
+ case '\0':
302
+ return;
303
+ default:
304
+ break;
305
+ }
306
+ }
307
+ } else {
308
+ raise_error("invalid comment", pi->str, pi->s);
309
+ }
310
+ }
311
+
278
312
  static VALUE
279
313
  read_next(ParseInfo pi, int hint) {
280
314
  VALUE obj;
@@ -307,7 +341,10 @@ read_next(ParseInfo pi, int hint) {
307
341
  } else {
308
342
  obj = read_num(pi);
309
343
  }
310
- break;
344
+ break;
345
+ case 'I':
346
+ obj = read_num(pi);
347
+ break;
311
348
  case 't':
312
349
  obj = read_true(pi);
313
350
  break;
@@ -641,6 +678,17 @@ read_num(ParseInfo pi) {
641
678
  } else if ('+' == *pi->s) {
642
679
  pi->s++;
643
680
  }
681
+ if ('I' == *pi->s) {
682
+ if (0 != strncmp("Infinity", pi->s, 8)) {
683
+ raise_error("number or other value", pi->str, pi->s);
684
+ }
685
+ pi->s += 8;
686
+ if (neg) {
687
+ return rb_float_new(-INFINITY);
688
+ } else {
689
+ return rb_float_new(INFINITY);
690
+ }
691
+ }
644
692
  for (; '0' <= *pi->s && *pi->s <= '9'; pi->s++) {
645
693
  n = n * 10 + (*pi->s - '0');
646
694
  if (NUM_MAX <= n) {
@@ -33,9 +33,15 @@
33
33
  #include <errno.h>
34
34
  #include <stdio.h>
35
35
  #include <string.h>
36
+ #include <sys/types.h>
37
+ #include <sys/uio.h>
38
+ #include <unistd.h>
36
39
 
37
40
  #include "oj.h"
38
41
 
42
+ // maximum to allocate on the stack, arbitrary limit
43
+ #define SMALL_XML 65536
44
+
39
45
  typedef struct _YesNoOpt {
40
46
  VALUE sym;
41
47
  char *attr;
@@ -47,6 +53,7 @@ VALUE Oj = Qnil;
47
53
 
48
54
  ID oj_as_json_id;
49
55
  ID oj_at_id;
56
+ ID oj_fileno_id;
50
57
  ID oj_instance_variables_id;
51
58
  ID oj_json_create_id;
52
59
  ID oj_read_id;
@@ -57,6 +64,7 @@ ID oj_to_sym_id;
57
64
  ID oj_tv_nsec_id;
58
65
  ID oj_tv_sec_id;
59
66
  ID oj_tv_usec_id;
67
+ ID oj_write_id;
60
68
 
61
69
  VALUE oj_bag_class;
62
70
  VALUE oj_date_class;
@@ -78,19 +86,33 @@ static VALUE object_sym;
78
86
  static VALUE strict_sym;
79
87
  static VALUE symbol_keys_sym;
80
88
 
89
+ static VALUE array_nl_sym;
90
+ static VALUE create_additions_sym;
91
+ static VALUE object_nl_sym;
92
+ static VALUE space_before_sym;
93
+ static VALUE space_sym;
94
+ static VALUE symbolize_names_sym;
95
+
96
+ static VALUE mimic = Qnil;
97
+ static VALUE keep = Qnil;
98
+
81
99
  Cache oj_class_cache = 0;
82
100
  Cache oj_attr_cache = 0;
83
101
 
84
102
  struct _Options oj_default_options = {
85
- { '\0' }, // encoding
103
+ // { '\0' }, // encoding
104
+ "UTF-8", // encoding
86
105
  0, // indent
87
106
  No, // circular
88
107
  Yes, // auto_define
89
108
  No, // sym_key
90
109
  No, // ascii_only
91
110
  ObjectMode, // mode
111
+ 0, // dump_opts
92
112
  };
93
113
 
114
+ static VALUE define_mimic_json(VALUE self);
115
+
94
116
  /* call-seq: default_options() => Hash
95
117
  *
96
118
  * Returns the default load and dump options as a Hash. The options are
@@ -257,42 +279,20 @@ parse_options(VALUE ropts, Options copts) {
257
279
  }
258
280
 
259
281
  static VALUE
260
- load(char *json, int argc, VALUE *argv, VALUE self) {
261
- VALUE obj;
262
- struct _Options options = oj_default_options;
263
-
264
- if (1 == argc) {
265
- parse_options(*argv, &options);
266
- }
267
- obj = oj_parse(json, &options);
268
- //free(json);
269
-
270
- return obj;
271
- }
272
-
273
- /* call-seq: load(json, options) => Hash, Array, String, Fixnum, Float, true, false, or nil
274
- *
275
- * Parses a JSON document String into a Hash, Array, String, Fixnum, Float,
276
- * true, false, or nil. Raises an exception if the JSON is malformed or the
277
- * classes specified are not valid.
278
- * @param [String] json JSON String
279
- * @param [Hash] options load options (same as default_options)
280
- */
281
- static VALUE
282
- load_str(int argc, VALUE *argv, VALUE self) {
282
+ load_with_opts(VALUE input, Options copts) {
283
283
  char *json;
284
284
  size_t len;
285
- VALUE input;
286
-
287
- if (1 > argc) {
288
- rb_raise(rb_eArgError, "Wrong number of arguments to load().\n");
289
- }
290
- input = *argv;
285
+ VALUE obj;
286
+
291
287
  if (rb_type(input) == T_STRING) {
292
288
  // the json string gets modified so make a copy of it
293
- len = RSTRING_LEN(*argv) + 1;
294
- json = ALLOCA_N(char, len);
295
- strcpy(json, StringValuePtr(*argv));
289
+ len = RSTRING_LEN(input) + 1;
290
+ if (SMALL_XML < len) {
291
+ json = ALLOC_N(char, len);
292
+ } else {
293
+ json = ALLOCA_N(char, len);
294
+ }
295
+ strcpy(json, StringValuePtr(input));
296
296
  } else {
297
297
  VALUE clas = rb_obj_class(input);
298
298
  VALUE s;
@@ -300,21 +300,66 @@ load_str(int argc, VALUE *argv, VALUE self) {
300
300
  if (oj_stringio_class == clas) {
301
301
  s = rb_funcall2(input, oj_string_id, 0, 0);
302
302
  len = RSTRING_LEN(s) + 1;
303
- json = ALLOCA_N(char, len);
303
+ if (SMALL_XML < len) {
304
+ json = ALLOC_N(char, len);
305
+ } else {
306
+ json = ALLOCA_N(char, len);
307
+ }
304
308
  strcpy(json, StringValuePtr(s));
305
-
306
- // TBD else responds to fileno
307
-
309
+ } else if (rb_respond_to(input, oj_fileno_id) && Qnil != (s = rb_funcall(input, oj_fileno_id, 0))) {
310
+ int fd = FIX2INT(s);
311
+ ssize_t cnt;
312
+
313
+ len = lseek(fd, 0, SEEK_END);
314
+ lseek(fd, 0, SEEK_SET);
315
+ if (SMALL_XML < len) {
316
+ json = ALLOC_N(char, len + 1);
317
+ } else {
318
+ json = ALLOCA_N(char, len + 1);
319
+ }
320
+ if (0 >= (cnt = read(fd, json, len)) || cnt != (ssize_t)len) {
321
+ rb_raise(rb_eIOError, "failed to read from IO Object.\n");
322
+ }
323
+ json[len] = '\0';
308
324
  } else if (rb_respond_to(input, oj_read_id)) {
309
325
  s = rb_funcall2(input, oj_read_id, 0, 0);
310
326
  len = RSTRING_LEN(s) + 1;
311
- json = ALLOCA_N(char, len);
327
+ if (SMALL_XML < len) {
328
+ json = ALLOC_N(char, len);
329
+ } else {
330
+ json = ALLOCA_N(char, len);
331
+ }
312
332
  strcpy(json, StringValuePtr(s));
313
333
  } else {
314
334
  rb_raise(rb_eArgError, "load() expected a String or IO Object.\n");
315
335
  }
316
336
  }
317
- return load(json, argc - 1, argv + 1, self);
337
+ obj = oj_parse(json, copts);
338
+ if (SMALL_XML < len) {
339
+ xfree(json);
340
+ }
341
+ return obj;
342
+ }
343
+
344
+ /* call-seq: load(json, options) => Hash, Array, String, Fixnum, Float, true, false, or nil
345
+ *
346
+ * Parses a JSON document String into a Hash, Array, String, Fixnum, Float,
347
+ * true, false, or nil. Raises an exception if the JSON is malformed or the
348
+ * classes specified are not valid.
349
+ * @param [String] json JSON String
350
+ * @param [Hash] options load options (same as default_options)
351
+ */
352
+ static VALUE
353
+ load(int argc, VALUE *argv, VALUE self) {
354
+ struct _Options options = oj_default_options;
355
+
356
+ if (1 > argc) {
357
+ rb_raise(rb_eArgError, "Wrong number of arguments to load().\n");
358
+ }
359
+ if (2 <= argc) {
360
+ parse_options(argv[1], &options);
361
+ }
362
+ return load_with_opts(*argv, &options);
318
363
  }
319
364
 
320
365
  static VALUE
@@ -323,7 +368,9 @@ load_file(int argc, VALUE *argv, VALUE self) {
323
368
  char *json;
324
369
  FILE *f;
325
370
  unsigned long len;
326
-
371
+ VALUE obj;
372
+ struct _Options options = oj_default_options;
373
+
327
374
  Check_Type(*argv, T_STRING);
328
375
  path = StringValuePtr(*argv);
329
376
  if (0 == (f = fopen(path, "r"))) {
@@ -331,9 +378,10 @@ load_file(int argc, VALUE *argv, VALUE self) {
331
378
  }
332
379
  fseek(f, 0, SEEK_END);
333
380
  len = ftell(f);
334
- if (0 == (json = ALLOCA_N(char, len + 1))) {
335
- fclose(f);
336
- rb_raise(rb_eNoMemError, "Could not allocate memory for %ld byte file.\n", len);
381
+ if (SMALL_XML < len) {
382
+ json = ALLOC_N(char, len + 1);
383
+ } else {
384
+ json = ALLOCA_N(char, len + 1);
337
385
  }
338
386
  fseek(f, 0, SEEK_SET);
339
387
  if (len != fread(json, 1, len, f)) {
@@ -342,8 +390,14 @@ load_file(int argc, VALUE *argv, VALUE self) {
342
390
  }
343
391
  fclose(f);
344
392
  json[len] = '\0';
345
-
346
- return load(json, argc - 1, argv + 1, self);
393
+ if (2 <= argc) {
394
+ parse_options(argv[1], &options);
395
+ }
396
+ obj = oj_parse(json, &options);
397
+ if (SMALL_XML < len) {
398
+ xfree(json);
399
+ }
400
+ return obj;
347
401
  }
348
402
 
349
403
  /* call-seq: dump(obj, options) => json-string
@@ -365,7 +419,7 @@ dump(int argc, VALUE *argv, VALUE self) {
365
419
  rb_raise(rb_eNoMemError, "Not enough memory.\n");
366
420
  }
367
421
  rstr = rb_str_new2(json);
368
- #ifdef ENCODING_INLINE_MAX
422
+ #ifdef HAVE_RUBY_ENCODING_H
369
423
  if ('\0' != *copts.encoding) {
370
424
  rb_enc_associate(rstr, rb_enc_find(copts.encoding));
371
425
  }
@@ -398,9 +452,264 @@ to_file(int argc, VALUE *argv, VALUE self) {
398
452
  return Qnil;
399
453
  }
400
454
 
401
- void Init_oj() {
402
- VALUE keep = Qnil;
455
+ // Mimic JSON section
456
+
457
+ static VALUE
458
+ mimic_dump(int argc, VALUE *argv, VALUE self) {
459
+ char *json;
460
+ struct _Options copts = oj_default_options;
461
+ VALUE rstr;
462
+
463
+ if (0 == (json = oj_write_obj_to_str(*argv, &copts))) {
464
+ rb_raise(rb_eNoMemError, "Not enough memory.\n");
465
+ }
466
+ rstr = rb_str_new2(json);
467
+ #ifdef ENCODING_INLINE_MAX
468
+ if ('\0' != *copts.encoding) {
469
+ rb_enc_associate(rstr, rb_enc_find(copts.encoding));
470
+ }
471
+ #endif
472
+ if (2 <= argc && Qnil != argv[1]) {
473
+ VALUE io = argv[1];
474
+ VALUE args[1];
475
+
476
+ *args = rstr;
477
+ rb_funcall2(io, oj_write_id, 1, args);
478
+ rstr = io;
479
+ }
480
+ xfree(json);
481
+
482
+ return rstr;
483
+ }
484
+
485
+ // This is the signature for the hash_foreach callback also.
486
+ static int
487
+ mimic_walk(VALUE key, VALUE obj, VALUE proc) {
488
+ VALUE args[1];
489
+
490
+ switch (rb_type(obj)) {
491
+ case T_HASH:
492
+ rb_hash_foreach(obj, mimic_walk, proc);
493
+ break;
494
+ case T_ARRAY:
495
+ {
496
+ VALUE *np = RARRAY_PTR(obj);
497
+ size_t cnt = RARRAY_LEN(obj);
498
+
499
+ for (; 0 < cnt; cnt--, np++) {
500
+ mimic_walk(Qnil, *np, proc);
501
+ }
502
+ break;
503
+ }
504
+ default:
505
+ break;
506
+ }
507
+ *args = obj;
508
+ if (Qnil == proc) {
509
+ rb_yield_values2(1, args);
510
+ } else {
511
+ rb_proc_call_with_block(proc, 1, args, Qnil);
512
+ }
513
+ return ST_CONTINUE;
514
+ }
515
+
516
+ static VALUE
517
+ mimic_load(int argc, VALUE *argv, VALUE self) {
518
+ VALUE obj = load(1, argv, self);
519
+
520
+ if (2 <= argc && Qnil != argv[1]) {
521
+ mimic_walk(Qnil, obj, argv[1]);
522
+ }
523
+ return obj;
524
+ }
525
+
526
+ static VALUE
527
+ mimic_dump_load(int argc, VALUE *argv, VALUE self) {
528
+ if (1 > argc) {
529
+ rb_raise(rb_eArgError, "wrong number of arguments (0 for 1)\n");
530
+ } else if (T_STRING == rb_type(*argv)) {
531
+ return mimic_load(argc, argv, self);
532
+ } else {
533
+ return mimic_dump(argc, argv, self);
534
+ }
535
+ }
403
536
 
537
+ static VALUE
538
+ mimic_generate_core(int argc, VALUE *argv, Options copts) {
539
+ char *json;
540
+ VALUE rstr;
541
+
542
+ if (2 == argc && Qnil != argv[1]) {
543
+ struct _DumpOpts dump_opts;
544
+ VALUE ropts = argv[1];
545
+ VALUE v;
546
+
547
+ memset(&dump_opts, 0, sizeof(dump_opts)); // may not be needed
548
+ if (T_HASH != rb_type(ropts)) {
549
+ rb_raise(rb_eArgError, "options must be a hash.\n");
550
+ }
551
+ if (Qnil != (v = rb_hash_lookup(ropts, indent_sym))) {
552
+ rb_check_type(v, T_STRING);
553
+ if (0 == copts->dump_opts) {
554
+ copts->dump_opts = &dump_opts;
555
+ }
556
+ copts->dump_opts->indent = StringValuePtr(v);
557
+ copts->dump_opts->indent_size = (uint8_t)strlen(copts->dump_opts->indent);
558
+ }
559
+ if (Qnil != (v = rb_hash_lookup(ropts, space_sym))) {
560
+ rb_check_type(v, T_STRING);
561
+ if (0 == copts->dump_opts) {
562
+ copts->dump_opts = &dump_opts;
563
+ }
564
+ copts->dump_opts->after_sep = StringValuePtr(v);
565
+ copts->dump_opts->after_size = (uint8_t)strlen(copts->dump_opts->after_sep);
566
+ }
567
+ if (Qnil != (v = rb_hash_lookup(ropts, space_before_sym))) {
568
+ rb_check_type(v, T_STRING);
569
+ if (0 == copts->dump_opts) {
570
+ copts->dump_opts = &dump_opts;
571
+ }
572
+ copts->dump_opts->before_sep = StringValuePtr(v);
573
+ copts->dump_opts->before_size = (uint8_t)strlen(copts->dump_opts->before_sep);
574
+ }
575
+ if (Qnil != (v = rb_hash_lookup(ropts, object_nl_sym))) {
576
+ rb_check_type(v, T_STRING);
577
+ if (0 == copts->dump_opts) {
578
+ copts->dump_opts = &dump_opts;
579
+ }
580
+ copts->dump_opts->hash_nl = StringValuePtr(v);
581
+ copts->dump_opts->hash_size = (uint8_t)strlen(copts->dump_opts->hash_nl);
582
+ }
583
+ if (Qnil != (v = rb_hash_lookup(ropts, array_nl_sym))) {
584
+ rb_check_type(v, T_STRING);
585
+ if (0 == copts->dump_opts) {
586
+ copts->dump_opts = &dump_opts;
587
+ }
588
+ copts->dump_opts->array_nl = StringValuePtr(v);
589
+ copts->dump_opts->array_size = (uint8_t)strlen(copts->dump_opts->array_nl);
590
+ }
591
+ // :allow_nan is not supported as Oj always allows_nan
592
+ // :max_nesting is always set to 100
593
+ }
594
+ if (0 == (json = oj_write_obj_to_str(*argv, copts))) {
595
+ rb_raise(rb_eNoMemError, "Not enough memory.\n");
596
+ }
597
+ rstr = rb_str_new2(json);
598
+ #ifdef ENCODING_INLINE_MAX
599
+ if ('\0' != *copts->encoding) {
600
+ rb_enc_associate(rstr, rb_enc_find(copts->encoding));
601
+ }
602
+ #endif
603
+ xfree(json);
604
+
605
+ return rstr;
606
+ }
607
+
608
+ static VALUE
609
+ mimic_generate(int argc, VALUE *argv, VALUE self) {
610
+ struct _Options copts = oj_default_options;
611
+
612
+ return mimic_generate_core(argc, argv, &copts);
613
+ }
614
+
615
+ static VALUE
616
+ mimic_pretty_generate(int argc, VALUE *argv, VALUE self) {
617
+ struct _Options copts = oj_default_options;
618
+ struct _DumpOpts dump_opts;
619
+
620
+ dump_opts.indent = " ";
621
+ dump_opts.indent_size = (uint8_t)strlen(dump_opts.indent);
622
+ dump_opts.before_sep = " ";
623
+ dump_opts.before_size = (uint8_t)strlen(dump_opts.before_sep);
624
+ dump_opts.after_sep = " ";
625
+ dump_opts.after_size = (uint8_t)strlen(dump_opts.after_sep);
626
+ dump_opts.hash_nl = "\n";
627
+ dump_opts.hash_size = (uint8_t)strlen(dump_opts.hash_nl);
628
+ dump_opts.array_nl = "\n";
629
+ dump_opts.array_size = (uint8_t)strlen(dump_opts.array_nl);
630
+ copts.dump_opts = &dump_opts;
631
+
632
+ return mimic_generate_core(argc, argv, &copts);
633
+ }
634
+
635
+ static VALUE
636
+ mimic_parse(int argc, VALUE *argv, VALUE self) {
637
+ struct _Options options = oj_default_options;
638
+
639
+ if (1 > argc) {
640
+ rb_raise(rb_eArgError, "Wrong number of arguments to load().\n");
641
+ }
642
+ if (2 <= argc && Qnil != argv[1]) {
643
+ VALUE ropts = argv[1];
644
+ VALUE v;
645
+
646
+ if (T_HASH != rb_type(ropts)) {
647
+ rb_raise(rb_eArgError, "options must be a hash.\n");
648
+ }
649
+ if (Qnil != (v = rb_hash_lookup(ropts, symbolize_names_sym))) {
650
+ options.sym_key = (Qtrue == v) ? Yes : No;
651
+ }
652
+ if (Qnil != (v = rb_hash_lookup(ropts, create_additions_sym))) {
653
+ options.mode = (Qtrue == v) ? CompatMode : StrictMode;
654
+ }
655
+ // :allow_nan is not supported as Oj always allows_nan
656
+ // :max_nesting is always set to 100
657
+ // :object_class is always Hash
658
+ // :array_class is always Array
659
+ }
660
+ return load_with_opts(*argv, &options);
661
+ }
662
+
663
+ static VALUE
664
+ mimic_recurse_proc(VALUE self, VALUE obj) {
665
+ rb_need_block();
666
+ mimic_walk(Qnil, obj, Qnil);
667
+
668
+ return Qnil;
669
+ }
670
+
671
+ static VALUE
672
+ no_op1(VALUE self, VALUE obj) {
673
+ return Qnil;
674
+ }
675
+
676
+ static VALUE
677
+ define_mimic_json(VALUE self) {
678
+ if (Qnil == mimic) {
679
+ VALUE ext;
680
+
681
+ mimic = rb_define_module("JSON");
682
+ ext = rb_define_module_under(mimic, "Ext");
683
+ rb_define_class_under(ext, "Parser", rb_cObject);
684
+ rb_define_class_under(ext, "Generator", rb_cObject);
685
+
686
+ rb_define_module_function(mimic, "parser=", no_op1, 1);
687
+ rb_define_module_function(mimic, "generator=", no_op1, 1);
688
+
689
+ rb_define_module_function(mimic, "dump", mimic_dump, -1);
690
+ rb_define_module_function(mimic, "load", mimic_load, -1);
691
+ rb_define_module_function(mimic, "restore", mimic_load, -1);
692
+ rb_define_module_function(mimic, "recurse_proc", mimic_recurse_proc, 1);
693
+ rb_define_module_function(mimic, "[]", mimic_dump_load, -1);
694
+ rb_define_module_function(mimic, "generate", mimic_generate, -1);
695
+ rb_define_module_function(mimic, "fast_generate", mimic_generate, -1);
696
+ rb_define_module_function(mimic, "pretty_generate", mimic_pretty_generate, -1);
697
+ rb_define_module_function(mimic, "parse", mimic_parse, -1);
698
+ rb_define_module_function(mimic, "parse!", mimic_parse, -1);
699
+
700
+ array_nl_sym = ID2SYM(rb_intern("array_nl")); rb_ary_push(keep, array_nl_sym);
701
+ create_additions_sym = ID2SYM(rb_intern("create_additions")); rb_ary_push(keep, create_additions_sym);
702
+ object_nl_sym = ID2SYM(rb_intern("object_nl")); rb_ary_push(keep, object_nl_sym);
703
+ space_before_sym = ID2SYM(rb_intern("space_before")); rb_ary_push(keep, space_before_sym);
704
+ space_sym = ID2SYM(rb_intern("space")); rb_ary_push(keep, space_sym);
705
+ symbolize_names_sym = ID2SYM(rb_intern("symbolize_names")); rb_ary_push(keep, symbolize_names_sym);
706
+
707
+ oj_default_options.mode = CompatMode;
708
+ }
709
+ return mimic;
710
+ }
711
+
712
+ void Init_oj() {
404
713
  Oj = rb_define_module("Oj");
405
714
  keep = rb_cv_get(Oj, "@@keep"); // needed to stop GC from deleting and reusing VALUEs
406
715
 
@@ -411,13 +720,15 @@ void Init_oj() {
411
720
  rb_define_module_function(Oj, "default_options", get_def_opts, 0);
412
721
  rb_define_module_function(Oj, "default_options=", set_def_opts, 1);
413
722
 
414
- rb_define_module_function(Oj, "load", load_str, -1);
723
+ rb_define_module_function(Oj, "mimic_JSON", define_mimic_json, 0);
724
+ rb_define_module_function(Oj, "load", load, -1);
415
725
  rb_define_module_function(Oj, "load_file", load_file, -1);
416
726
  rb_define_module_function(Oj, "dump", dump, -1);
417
727
  rb_define_module_function(Oj, "to_file", to_file, -1);
418
728
 
419
729
  oj_as_json_id = rb_intern("as_json");
420
730
  oj_at_id = rb_intern("at");
731
+ oj_fileno_id = rb_intern("fileno");
421
732
  oj_instance_variables_id = rb_intern("instance_variables");
422
733
  oj_json_create_id = rb_intern("json_create");
423
734
  oj_read_id = rb_intern("read");
@@ -428,6 +739,7 @@ void Init_oj() {
428
739
  oj_tv_nsec_id = rb_intern("tv_nsec");
429
740
  oj_tv_sec_id = rb_intern("tv_sec");
430
741
  oj_tv_usec_id = rb_intern("tv_usec");
742
+ oj_write_id = rb_intern("write");
431
743
 
432
744
  oj_bag_class = rb_const_get_at(Oj, rb_intern("Bag"));
433
745
  oj_struct_class = rb_const_get(rb_cObject, rb_intern("Struct"));