oj 3.12.3 → 3.13.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.
data/ext/oj/intern.h ADDED
@@ -0,0 +1,27 @@
1
+ // Copyright (c) 2011, 2021 Peter Ohler. All rights reserved.
2
+ // Licensed under the MIT License. See LICENSE file in the project root for license details.
3
+
4
+ #ifndef OJ_INTERN_H
5
+ #define OJ_INTERN_H
6
+
7
+ #include <stdbool.h>
8
+ #include <ruby.h>
9
+
10
+ struct _parseInfo;
11
+
12
+ extern void oj_hash_init();
13
+
14
+ extern VALUE oj_str_intern(const char *key, size_t len);
15
+ extern VALUE oj_sym_intern(const char *key, size_t len);
16
+ extern ID oj_attr_intern(const char *key, size_t len);
17
+ extern VALUE oj_class_intern(const char * key,
18
+ size_t len,
19
+ bool safe,
20
+ struct _parseInfo *pi,
21
+ int auto_define,
22
+ VALUE error_class);
23
+
24
+ extern void oj_hash_print();
25
+ extern char *oj_strndup(const char *s, size_t len);
26
+
27
+ #endif /* OJ_INTERN_H */
data/ext/oj/object.c CHANGED
@@ -7,7 +7,7 @@
7
7
 
8
8
  #include "encode.h"
9
9
  #include "err.h"
10
- #include "hash.h"
10
+ #include "intern.h"
11
11
  #include "odd.h"
12
12
  #include "oj.h"
13
13
  #include "parse.h"
@@ -59,17 +59,17 @@ static VALUE calc_hash_key(ParseInfo pi, Val kval, char k1) {
59
59
  }
60
60
  #else
61
61
  if (':' == k1) {
62
- rkey = rb_str_new(kval->key + 1, kval->klen - 1);
63
- rkey = oj_encode(rkey);
64
- rkey = rb_str_intern(rkey);
62
+ rkey = ID2SYM(rb_intern3(kval->key + 1, kval->klen - 1, oj_utf8_encoding));
65
63
  } else {
66
- rkey = rb_str_new(kval->key, kval->klen);
67
- rkey = oj_encode(rkey);
68
64
  if (Yes == pi->options.sym_key) {
69
- rkey = rb_str_intern(rkey);
65
+ rkey = ID2SYM(rb_intern3(kval->key, kval->klen, oj_utf8_encoding));
66
+ } else {
67
+ rkey = rb_str_new(kval->key, kval->klen);
68
+ rkey = oj_encode(rkey);
70
69
  }
71
70
  }
72
71
  #endif
72
+ OBJ_FREEZE(rkey);
73
73
  return rkey;
74
74
  }
75
75
 
@@ -77,9 +77,7 @@ static VALUE str_to_value(ParseInfo pi, const char *str, size_t len, const char
77
77
  volatile VALUE rstr = Qnil;
78
78
 
79
79
  if (':' == *orig && 0 < len) {
80
- rstr = rb_str_new(str + 1, len - 1);
81
- rstr = oj_encode(rstr);
82
- rstr = rb_funcall(rstr, oj_to_sym_id, 0);
80
+ rstr = ID2SYM(rb_intern3(str + 1, len - 1, oj_utf8_encoding));
83
81
  } else if (pi->circ_array && 3 <= len && '^' == *orig && 'r' == orig[1]) {
84
82
  long i = read_long(str + 2, len - 2);
85
83
 
@@ -258,9 +256,7 @@ static int hat_cstr(ParseInfo pi, Val parent, Val kval, const char *str, size_t
258
256
  parent->odd_args = oj_odd_alloc_args(odd);
259
257
  } break;
260
258
  case 'm':
261
- parent->val = rb_str_new(str + 1, len - 1);
262
- parent->val = oj_encode(parent->val);
263
- parent->val = rb_funcall(parent->val, oj_to_sym_id, 0);
259
+ parent->val = ID2SYM(rb_intern3(str + 1, len - 1, oj_utf8_encoding));
264
260
  break;
265
261
  case 's':
266
262
  parent->val = rb_str_new(str, len);
@@ -416,51 +412,7 @@ static int hat_value(ParseInfo pi, Val parent, const char *key, size_t klen, vol
416
412
  }
417
413
 
418
414
  void oj_set_obj_ivar(Val parent, Val kval, VALUE value) {
419
- const char *key = kval->key;
420
- int klen = kval->klen;
421
- ID var_id;
422
- ID * slot;
423
-
424
- #ifdef HAVE_PTHREAD_MUTEX_INIT
425
- pthread_mutex_lock(&oj_cache_mutex);
426
- #else
427
- rb_mutex_lock(oj_cache_mutex);
428
- #endif
429
- if (0 == (var_id = oj_attr_hash_get(key, klen, &slot))) {
430
- char attr[256];
431
-
432
- if ((int)sizeof(attr) <= klen + 2) {
433
- char *buf = ALLOC_N(char, klen + 2);
434
-
435
- if ('~' == *key) {
436
- memcpy(buf, key + 1, klen - 1);
437
- buf[klen - 1] = '\0';
438
- } else {
439
- *buf = '@';
440
- memcpy(buf + 1, key, klen);
441
- buf[klen + 1] = '\0';
442
- }
443
- var_id = rb_intern(buf);
444
- xfree(buf);
445
- } else {
446
- if ('~' == *key) {
447
- memcpy(attr, key + 1, klen - 1);
448
- attr[klen - 1] = '\0';
449
- } else {
450
- *attr = '@';
451
- memcpy(attr + 1, key, klen);
452
- attr[klen + 1] = '\0';
453
- }
454
- var_id = rb_intern(attr);
455
- }
456
- *slot = var_id;
457
- }
458
- #ifdef HAVE_PTHREAD_MUTEX_INIT
459
- pthread_mutex_unlock(&oj_cache_mutex);
460
- #else
461
- rb_mutex_unlock(oj_cache_mutex);
462
- #endif
463
- rb_ivar_set(parent->val, var_id, value);
415
+ rb_ivar_set(parent->val, oj_attr_intern(kval->key, kval->klen), value);
464
416
  }
465
417
 
466
418
  static void hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, const char *orig) {
data/ext/oj/odd.c CHANGED
@@ -206,7 +206,7 @@ void oj_reg_odd(VALUE clas,
206
206
  *fp = 0;
207
207
  switch (rb_type(*members)) {
208
208
  case T_STRING:
209
- if (NULL == (*np = strdup(rb_string_value_ptr(members)))) {
209
+ if (NULL == (*np = strdup(RSTRING_PTR(*members)))) {
210
210
  rb_raise(rb_eNoMemError, "for attribute name.");
211
211
  }
212
212
  break;
data/ext/oj/oj.c CHANGED
@@ -13,7 +13,7 @@
13
13
 
14
14
  #include "dump.h"
15
15
  #include "encode.h"
16
- #include "hash.h"
16
+ #include "intern.h"
17
17
  #include "odd.h"
18
18
  #include "parse.h"
19
19
  #include "rails.h"
@@ -158,6 +158,8 @@ pthread_mutex_t oj_cache_mutex;
158
158
  VALUE oj_cache_mutex = Qnil;
159
159
  #endif
160
160
 
161
+ extern void oj_parser_init();
162
+
161
163
  const char oj_json_class[] = "json_class";
162
164
 
163
165
  struct _options oj_default_options = {
@@ -589,7 +591,8 @@ bool oj_hash_has_key(VALUE hash, VALUE key)
589
591
  return true;
590
592
  }
591
593
 
592
- void oj_parse_options(VALUE ropts, Options copts) {
594
+ bool set_yesno_options(VALUE key, VALUE value, Options copts)
595
+ {
593
596
  struct _yesNoOpt ynos[] = {{circular_sym, &copts->circular},
594
597
  {auto_define_sym, &copts->auto_define},
595
598
  {symbol_keys_sym, &copts->sym_key},
@@ -612,15 +615,37 @@ void oj_parse_options(VALUE ropts, Options copts) {
612
615
  {oj_create_additions_sym, &copts->create_ok},
613
616
  {cache_keys_sym, &copts->cache_keys},
614
617
  {Qnil, 0}};
615
- YesNoOpt o;
616
- volatile VALUE v;
617
- size_t len;
618
+ YesNoOpt o;
619
+
620
+ for (o = ynos; 0 != o->attr; o++) {
621
+ if (key == o->sym) {
622
+ if (Qnil == value) {
623
+ *o->attr = NotSet;
624
+ } else if (Qtrue == value) {
625
+ *o->attr = Yes;
626
+ } else if (Qfalse == value) {
627
+ *o->attr = No;
628
+ } else {
629
+ rb_raise(rb_eArgError,
630
+ "%s must be true, false, or nil.",
631
+ rb_id2name(key));
632
+ }
633
+ return true;
634
+ }
635
+ }
636
+ return false;
637
+ }
618
638
 
619
- if (T_HASH != rb_type(ropts)) {
620
- return;
639
+ static int parse_options_cb(VALUE k, VALUE v, VALUE opts)
640
+ {
641
+ Options copts = (Options)opts;
642
+ size_t len;
643
+
644
+ if (set_yesno_options(k, v, copts)) {
645
+ return ST_CONTINUE;
621
646
  }
622
- if (oj_hash_has_key(ropts, oj_indent_sym)) {
623
- v = rb_hash_lookup(ropts, oj_indent_sym);
647
+
648
+ if (oj_indent_sym == k) {
624
649
  switch (rb_type(v)) {
625
650
  case T_NIL:
626
651
  copts->dump_opts.indent_size = 0;
@@ -644,8 +669,7 @@ void oj_parse_options(VALUE ropts, Options copts) {
644
669
  break;
645
670
  default: rb_raise(rb_eTypeError, "indent must be a Fixnum, String, or nil."); break;
646
671
  }
647
- }
648
- if (Qnil != (v = rb_hash_lookup(ropts, float_prec_sym))) {
672
+ } else if (float_prec_sym == k) {
649
673
  int n;
650
674
 
651
675
  #ifdef RUBY_INTEGER_UNIFICATION
@@ -668,8 +692,7 @@ void oj_parse_options(VALUE ropts, Options copts) {
668
692
  sprintf(copts->float_fmt, "%%0.%dg", n);
669
693
  copts->float_prec = n;
670
694
  }
671
- }
672
- if (Qnil != (v = rb_hash_lookup(ropts, cache_str_sym))) {
695
+ } else if (cache_str_sym == k) {
673
696
  int n;
674
697
 
675
698
  #ifdef RUBY_INTEGER_UNIFICATION
@@ -690,8 +713,7 @@ void oj_parse_options(VALUE ropts, Options copts) {
690
713
  }
691
714
  copts->cache_str = (char)n;
692
715
  }
693
- }
694
- if (Qnil != (v = rb_hash_lookup(ropts, sec_prec_sym))) {
716
+ } else if (sec_prec_sym == k) {
695
717
  int n;
696
718
 
697
719
  #ifdef RUBY_INTEGER_UNIFICATION
@@ -714,8 +736,7 @@ void oj_parse_options(VALUE ropts, Options copts) {
714
736
  copts->sec_prec_set = true;
715
737
  }
716
738
  copts->sec_prec = n;
717
- }
718
- if (Qnil != (v = rb_hash_lookup(ropts, mode_sym))) {
739
+ } else if (mode_sym == k) {
719
740
  if (wab_sym == v) {
720
741
  copts->mode = WabMode;
721
742
  } else if (object_sym == v) {
@@ -734,8 +755,7 @@ void oj_parse_options(VALUE ropts, Options copts) {
734
755
  rb_raise(rb_eArgError,
735
756
  ":mode must be :object, :strict, :compat, :null, :custom, :rails, or :wab.");
736
757
  }
737
- }
738
- if (Qnil != (v = rb_hash_lookup(ropts, time_format_sym))) {
758
+ } else if (time_format_sym == k) {
739
759
  if (unix_sym == v) {
740
760
  copts->time_format = UnixTime;
741
761
  } else if (unix_zone_sym == v) {
@@ -747,8 +767,7 @@ void oj_parse_options(VALUE ropts, Options copts) {
747
767
  } else {
748
768
  rb_raise(rb_eArgError, ":time_format must be :unix, :unix_zone, :xmlschema, or :ruby.");
749
769
  }
750
- }
751
- if (Qnil != (v = rb_hash_lookup(ropts, escape_mode_sym))) {
770
+ } else if (escape_mode_sym == k) {
752
771
  if (newline_sym == v) {
753
772
  copts->escape_mode = NLEsc;
754
773
  } else if (json_sym == v) {
@@ -763,8 +782,11 @@ void oj_parse_options(VALUE ropts, Options copts) {
763
782
  rb_raise(rb_eArgError,
764
783
  ":encoding must be :newline, :json, :xss_safe, :unicode_xss, or :ascii.");
765
784
  }
766
- }
767
- if (Qnil != (v = rb_hash_lookup(ropts, bigdecimal_load_sym))) {
785
+ } else if (bigdecimal_load_sym == k) {
786
+ if (Qnil == v) {
787
+ return ST_CONTINUE;
788
+ }
789
+
768
790
  if (bigdecimal_sym == v || Qtrue == v) {
769
791
  copts->bigdec_load = BigDec;
770
792
  } else if (float_sym == v) {
@@ -776,12 +798,13 @@ void oj_parse_options(VALUE ropts, Options copts) {
776
798
  } else {
777
799
  rb_raise(rb_eArgError, ":bigdecimal_load must be :bigdecimal, :float, or :auto.");
778
800
  }
779
- }
780
- if (Qnil != (v = rb_hash_lookup(ropts, compat_bigdecimal_sym))) {
801
+ } else if (compat_bigdecimal_sym == k) {
802
+ if (Qnil == v) {
803
+ return ST_CONTINUE;
804
+ }
805
+
781
806
  copts->compat_bigdec = (Qtrue == v);
782
- }
783
- if (oj_hash_has_key(ropts, oj_decimal_class_sym)) {
784
- v = rb_hash_lookup(ropts, oj_decimal_class_sym);
807
+ } else if (oj_decimal_class_sym == k) {
785
808
  if (rb_cFloat == v) {
786
809
  copts->compat_bigdec = false;
787
810
  } else if (oj_bigdecimal_class == v) {
@@ -789,9 +812,7 @@ void oj_parse_options(VALUE ropts, Options copts) {
789
812
  } else {
790
813
  rb_raise(rb_eArgError, ":decimal_class must be BigDecimal or Float.");
791
814
  }
792
- }
793
- if (oj_hash_has_key(ropts, create_id_sym)) {
794
- v = rb_hash_lookup(ropts, create_id_sym);
815
+ } else if (create_id_sym == k) {
795
816
  if (Qnil == v) {
796
817
  if (oj_json_class != oj_default_options.create_id && NULL != copts->create_id) {
797
818
  xfree((char *)oj_default_options.create_id);
@@ -810,25 +831,8 @@ void oj_parse_options(VALUE ropts, Options copts) {
810
831
  } else {
811
832
  rb_raise(rb_eArgError, ":create_id must be string.");
812
833
  }
813
- }
814
- for (o = ynos; 0 != o->attr; o++) {
815
- if (oj_hash_has_key(ropts, o->sym)) {
816
- v = rb_hash_lookup(ropts, o->sym);
817
- if (Qnil == v) {
818
- *o->attr = NotSet;
819
- } else if (Qtrue == v) {
820
- *o->attr = Yes;
821
- } else if (Qfalse == v) {
822
- *o->attr = No;
823
- } else {
824
- rb_raise(rb_eArgError,
825
- "%s must be true, false, or nil.",
826
- rb_id2name(SYM2ID(o->sym)));
827
- }
828
- }
829
- }
830
- if (oj_hash_has_key(ropts, oj_space_sym)) {
831
- if (Qnil == (v = rb_hash_lookup(ropts, oj_space_sym))) {
834
+ } else if (oj_space_sym == k) {
835
+ if (Qnil == v) {
832
836
  copts->dump_opts.after_size = 0;
833
837
  *copts->dump_opts.after_sep = '\0';
834
838
  } else {
@@ -841,9 +845,8 @@ void oj_parse_options(VALUE ropts, Options copts) {
841
845
  strcpy(copts->dump_opts.after_sep, StringValuePtr(v));
842
846
  copts->dump_opts.after_size = (uint8_t)len;
843
847
  }
844
- }
845
- if (oj_hash_has_key(ropts, oj_space_before_sym)) {
846
- if (Qnil == (v = rb_hash_lookup(ropts, oj_space_before_sym))) {
848
+ } else if (oj_space_before_sym == k) {
849
+ if (Qnil == v) {
847
850
  copts->dump_opts.before_size = 0;
848
851
  *copts->dump_opts.before_sep = '\0';
849
852
  } else {
@@ -856,9 +859,8 @@ void oj_parse_options(VALUE ropts, Options copts) {
856
859
  strcpy(copts->dump_opts.before_sep, StringValuePtr(v));
857
860
  copts->dump_opts.before_size = (uint8_t)len;
858
861
  }
859
- }
860
- if (oj_hash_has_key(ropts, oj_object_nl_sym)) {
861
- if (Qnil == (v = rb_hash_lookup(ropts, oj_object_nl_sym))) {
862
+ } else if (oj_object_nl_sym == k) {
863
+ if (Qnil == v) {
862
864
  copts->dump_opts.hash_size = 0;
863
865
  *copts->dump_opts.hash_nl = '\0';
864
866
  } else {
@@ -871,9 +873,8 @@ void oj_parse_options(VALUE ropts, Options copts) {
871
873
  strcpy(copts->dump_opts.hash_nl, StringValuePtr(v));
872
874
  copts->dump_opts.hash_size = (uint8_t)len;
873
875
  }
874
- }
875
- if (oj_hash_has_key(ropts, oj_array_nl_sym)) {
876
- if (Qnil == (v = rb_hash_lookup(ropts, oj_array_nl_sym))) {
876
+ } else if (oj_array_nl_sym == k) {
877
+ if (Qnil == v) {
877
878
  copts->dump_opts.array_size = 0;
878
879
  *copts->dump_opts.array_nl = '\0';
879
880
  } else {
@@ -886,8 +887,11 @@ void oj_parse_options(VALUE ropts, Options copts) {
886
887
  strcpy(copts->dump_opts.array_nl, StringValuePtr(v));
887
888
  copts->dump_opts.array_size = (uint8_t)len;
888
889
  }
889
- }
890
- if (Qnil != (v = rb_hash_lookup(ropts, nan_sym))) {
890
+ } else if (nan_sym == k) {
891
+ if (Qnil == v) {
892
+ return ST_CONTINUE;
893
+ }
894
+
891
895
  if (null_sym == v) {
892
896
  copts->dump_opts.nan_dump = NullNan;
893
897
  } else if (huge_sym == v) {
@@ -901,11 +905,11 @@ void oj_parse_options(VALUE ropts, Options copts) {
901
905
  } else {
902
906
  rb_raise(rb_eArgError, ":nan must be :null, :huge, :word, :raise, or :auto.");
903
907
  }
904
- }
905
- copts->dump_opts.use = (0 < copts->dump_opts.indent_size || 0 < copts->dump_opts.after_size ||
906
- 0 < copts->dump_opts.before_size || 0 < copts->dump_opts.hash_size ||
907
- 0 < copts->dump_opts.array_size);
908
- if (Qnil != (v = rb_hash_lookup(ropts, omit_nil_sym))) {
908
+ } else if (omit_nil_sym == k) {
909
+ if (Qnil == v) {
910
+ return ST_CONTINUE;
911
+ }
912
+
909
913
  if (Qtrue == v) {
910
914
  copts->dump_opts.omit_nil = true;
911
915
  } else if (Qfalse == v) {
@@ -913,43 +917,38 @@ void oj_parse_options(VALUE ropts, Options copts) {
913
917
  } else {
914
918
  rb_raise(rb_eArgError, ":omit_nil must be true or false.");
915
919
  }
916
- }
917
- // This is here only for backwards compatibility with the original Oj.
918
- v = rb_hash_lookup(ropts, oj_ascii_only_sym);
919
- if (Qtrue == v) {
920
- copts->escape_mode = ASCIIEsc;
921
- } else if (Qfalse == v) {
922
- copts->escape_mode = JSONEsc;
923
- }
924
- if (oj_hash_has_key(ropts, oj_hash_class_sym)) {
925
- if (Qnil == (v = rb_hash_lookup(ropts, oj_hash_class_sym))) {
920
+ } else if(oj_ascii_only_sym == k) {
921
+ // This is here only for backwards compatibility with the original Oj.
922
+ if (Qtrue == v) {
923
+ copts->escape_mode = ASCIIEsc;
924
+ } else if (Qfalse == v) {
925
+ copts->escape_mode = JSONEsc;
926
+ }
927
+ } else if (oj_hash_class_sym == k) {
928
+ if (Qnil == v) {
926
929
  copts->hash_class = Qnil;
927
930
  } else {
928
931
  rb_check_type(v, T_CLASS);
929
932
  copts->hash_class = v;
930
933
  }
931
- }
932
- if (oj_hash_has_key(ropts, oj_object_class_sym)) {
933
- if (Qnil == (v = rb_hash_lookup(ropts, oj_object_class_sym))) {
934
+ } else if (oj_object_class_sym == k) {
935
+ if (Qnil == v) {
934
936
  copts->hash_class = Qnil;
935
937
  } else {
936
938
  rb_check_type(v, T_CLASS);
937
939
  copts->hash_class = v;
938
940
  }
939
- }
940
- if (oj_hash_has_key(ropts, oj_array_class_sym)) {
941
- if (Qnil == (v = rb_hash_lookup(ropts, oj_array_class_sym))) {
941
+ } else if (oj_array_class_sym == k) {
942
+ if (Qnil == v) {
942
943
  copts->array_class = Qnil;
943
944
  } else {
944
945
  rb_check_type(v, T_CLASS);
945
946
  copts->array_class = v;
946
947
  }
947
- }
948
- oj_parse_opt_match_string(&copts->str_rx, ropts);
949
- if (oj_hash_has_key(ropts, ignore_sym)) {
948
+ } else if (ignore_sym == k) {
950
949
  xfree(copts->ignore);
951
950
  copts->ignore = NULL;
952
- if (Qnil != (v = rb_hash_lookup(ropts, ignore_sym))) {
951
+ if (Qnil != v) {
953
952
  int cnt;
954
953
 
955
954
  rb_check_type(v, T_ARRAY);
@@ -964,8 +963,11 @@ void oj_parse_options(VALUE ropts, Options copts) {
964
963
  copts->ignore[i] = Qnil;
965
964
  }
966
965
  }
967
- }
968
- if (Qnil != (v = rb_hash_lookup(ropts, integer_range_sym))) {
966
+ } else if (integer_range_sym == k) {
967
+ if (Qnil == v) {
968
+ return ST_CONTINUE;
969
+ }
970
+
969
971
  if (TYPE(v) == T_STRUCT && rb_obj_class(v) == rb_cRange) {
970
972
  VALUE min = rb_funcall(v, oj_begin_id, 0);
971
973
  VALUE max = rb_funcall(v, oj_end_id, 0);
@@ -980,6 +982,22 @@ void oj_parse_options(VALUE ropts, Options copts) {
980
982
  rb_raise(rb_eArgError, ":integer_range must be a range of Fixnum.");
981
983
  }
982
984
  }
985
+
986
+ return ST_CONTINUE;
987
+ }
988
+
989
+ void oj_parse_options(VALUE ropts, Options copts) {
990
+ if (T_HASH != rb_type(ropts)) {
991
+ return;
992
+ }
993
+
994
+ rb_hash_foreach(ropts, parse_options_cb, (VALUE)copts);
995
+ oj_parse_opt_match_string(&copts->str_rx, ropts);
996
+
997
+ copts->dump_opts.use = (0 < copts->dump_opts.indent_size || 0 < copts->dump_opts.after_size ||
998
+ 0 < copts->dump_opts.before_size || 0 < copts->dump_opts.hash_size ||
999
+ 0 < copts->dump_opts.array_size);
1000
+ return;
983
1001
  }
984
1002
 
985
1003
  static int match_string_cb(VALUE key, VALUE value, VALUE rx) {
@@ -1761,6 +1779,9 @@ static VALUE protect_require(VALUE x) {
1761
1779
  void Init_oj() {
1762
1780
  int err = 0;
1763
1781
 
1782
+ #if HAVE_RB_EXT_RACTOR_SAFE
1783
+ rb_ext_ractor_safe(true);
1784
+ #endif
1764
1785
  Oj = rb_define_module("Oj");
1765
1786
 
1766
1787
  oj_cstack_class = rb_define_class_under(Oj, "CStack", rb_cObject);
@@ -2035,4 +2056,6 @@ void Init_oj() {
2035
2056
  rb_gc_register_address(&oj_cache_mutex);
2036
2057
  #endif
2037
2058
  oj_init_doc();
2059
+
2060
+ oj_parser_init();
2038
2061
  }