Module: Oj
- Defined in:
- lib/oj.rb,
lib/oj/saj.rb,
lib/oj/bag.rb,
lib/oj/error.rb,
lib/oj/mimic.rb,
lib/oj/version.rb,
lib/oj/schandler.rb,
ext/oj/oj.c
Overview
Optimized JSON (Oj), as the name implies was written to provide speed optimized JSON handling.
Oj has several dump or serialization modes which control how Objects are converted to JSON. These modes are set with the :mode option in either the default options or as one of the options to the dump() method.
-
:strict mode will only allow the 7 basic JSON types to be serialized. Any other Object will raise and Exception.
-
:null mode replaces any Object that is not one of the JSON types is replaced by a JSON null.
-
:object mode will dump any Object as a JSON Object with keys that match the Ruby Object's variable names without the '@' character. This is the highest performance mode.
-
:compat mode is is the compatible with other systems. It will serialize any Object but will check to see if the Object implements a to_hash() or to_json() method. If either exists that method is used for serializing the Object. The to_hash() is more flexible and produces more consistent output so it has a preference over the to_json() method. If neither the to_json() or to_hash() methods exist then the Oj internal Object variable encoding is used.
Defined Under Namespace
Classes: Bag, DepthError, Doc, Error, LoadError, MimicError, ParseError, Saj, ScHandler
Constant Summary
- VERSION =
Current version of the module.
'2.1.0'
Class Method Summary (collapse)
-
+ (Object, ...) compat_load(json, options)
Parses a JSON document String into an Object, Hash, Array, String, Fixnum, Float, true, false, or nil.
-
+ (Hash) default_options
Returns the default load and dump options as a Hash.
-
+ (nil) default_options=(opts)
Sets the default options for load and dump.
-
+ (Object) dump(obj, options)
Dumps an Object (obj) to a string.
-
+ (Object, ...) load(json, options)
Parses a JSON document String into a Object, Hash, Array, String, Fixnum, Float, true, false, or nil according to the default mode or the mode specified.
-
+ (Object) load_file
call-seq: load_file(path, options) => Object, Hash, Array, String, Fixnum, Float, true, false, or nil.
-
+ (Object) mimic_JSON
call-seq: mimic_JSON() => Module.
- + (Object) mimic_loaded(mimic_paths = [])
-
+ (Object, ...) object_load(json, options)
Parses a JSON document String into an Object, Hash, Array, String, Fixnum, Float, true, false, or nil.
-
+ (Hash|Array|String|Fixnum|Bignum|BigDecimal|nil|True|False) safe_load(doc)
Loads a JSON document in strict mode with :auto_define and :symbol_keys turned off.
- + (Object) saj_parse
- + (Object) sc_parse
-
+ (Hash, ...) strict_load(json, options)
Parses a JSON document String into an Hash, Array, String, Fixnum, Float, true, false, or nil.
-
+ (Object) to_file(file_path, obj, options)
Dumps an Object to the specified file.
Class Method Details
+ (Object, ...) compat_load(json, options)
Parses a JSON document String into an Object, Hash, Array, String, Fixnum, Float, true, false, or nil. It parses using a mode that is generally compatible with other Ruby JSON parsers in that it will create objects based on the :create_id value. It is not compatible in every way to every other parser though as each parser has it's own variations.
Raises an exception if the JSON is malformed or the classes specified are not valid. If the input is not a valid JSON document (an empty string is not a valid JSON document) an exception is raised.
+ (Hash) default_options
Returns the default load and dump options as a Hash. The options are
-
indent: [Fixnum] number of spaces to indent each element in an JSON document
-
circular: [true|false|nil] support circular references while dumping
-
auto_define: [true|false|nil] automatically define classes if they do not exist
-
symbol_keys: [true|false|nil] use symbols instead of strings for hash keys
-
class_cache: [true|false|nil] cache classes for faster parsing (if dynamically modifying classes or reloading classes then don't use this)
-
mode: [:object|:strict|:compat|:null] load and dump modes to use for JSON
-
time_format: [:unix|:xmlschema|:ruby] time format when dumping in :compat mode
-
bigdecimal_as_decimal: [true|false|nil] dump BigDecimal as a decimal number or as a String
-
bigdecimal_load: [true|false|nil] load decimals as BigDecimal instead of as a Float
-
create_id: [String|nil] create id for json compatible object encoding, default is 'json_create'
-
second_precision: [Fixnum|nil] number of digits after the decimal when dumping the seconds portion of time
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 |
# File 'ext/oj/oj.c', line 163
static VALUE
get_def_opts(VALUE self) {
VALUE opts = rb_hash_new();
rb_hash_aset(opts, indent_sym, INT2FIX(oj_default_options.indent));
rb_hash_aset(opts, sec_prec_sym, INT2FIX(oj_default_options.sec_prec));
rb_hash_aset(opts, circular_sym, (Yes == oj_default_options.circular) ? Qtrue : ((No == oj_default_options.circular) ? Qfalse : Qnil));
rb_hash_aset(opts, class_cache_sym, (Yes == oj_default_options.class_cache) ? Qtrue : ((No == oj_default_options.class_cache) ? Qfalse : Qnil));
rb_hash_aset(opts, auto_define_sym, (Yes == oj_default_options.auto_define) ? Qtrue : ((No == oj_default_options.auto_define) ? Qfalse : Qnil));
rb_hash_aset(opts, ascii_only_sym, (Yes == oj_default_options.ascii_only) ? Qtrue : ((No == oj_default_options.ascii_only) ? Qfalse : Qnil));
rb_hash_aset(opts, symbol_keys_sym, (Yes == oj_default_options.sym_key) ? Qtrue : ((No == oj_default_options.sym_key) ? Qfalse : Qnil));
rb_hash_aset(opts, bigdecimal_as_decimal_sym, (Yes == oj_default_options.bigdec_as_num) ? Qtrue : ((No == oj_default_options.bigdec_as_num) ? Qfalse : Qnil));
rb_hash_aset(opts, bigdecimal_load_sym, (Yes == oj_default_options.bigdec_load) ? Qtrue : ((No == oj_default_options.bigdec_load) ? Qfalse : Qnil));
switch (oj_default_options.mode) {
case StrictMode: rb_hash_aset(opts, mode_sym, strict_sym); break;
case CompatMode: rb_hash_aset(opts, mode_sym, compat_sym); break;
case NullMode: rb_hash_aset(opts, mode_sym, null_sym); break;
case ObjectMode:
default: rb_hash_aset(opts, mode_sym, object_sym); break;
}
switch (oj_default_options.time_format) {
case XmlTime: rb_hash_aset(opts, time_format_sym, xmlschema_sym); break;
case RubyTime: rb_hash_aset(opts, time_format_sym, ruby_sym); break;
case UnixTime:
default: rb_hash_aset(opts, time_format_sym, unix_sym); break;
}
rb_hash_aset(opts, create_id_sym, (0 == oj_default_options.create_id) ? Qnil : rb_str_new2(oj_default_options.create_id));
return opts;
}
|
+ (nil) default_options=(opts)
Sets the default options for load and dump.
222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 |
# File 'ext/oj/oj.c', line 222
static VALUE
set_def_opts(VALUE self, VALUE opts) {
struct _YesNoOpt ynos[] = {
{ circular_sym, &oj_default_options.circular },
{ auto_define_sym, &oj_default_options.auto_define },
{ symbol_keys_sym, &oj_default_options.sym_key },
{ class_cache_sym, &oj_default_options.class_cache },
{ ascii_only_sym, &oj_default_options.ascii_only },
{ bigdecimal_as_decimal_sym, &oj_default_options.bigdec_as_num },
{ bigdecimal_load_sym, &oj_default_options.bigdec_load },
{ Qnil, 0 }
};
YesNoOpt o;
VALUE v;
Check_Type(opts, T_HASH);
v = rb_hash_aref(opts, indent_sym);
if (Qnil != v) {
Check_Type(v, T_FIXNUM);
oj_default_options.indent = FIX2INT(v);
}
v = rb_hash_aref(opts, sec_prec_sym);
if (Qnil != v) {
int n;
Check_Type(v, T_FIXNUM);
n = FIX2INT(v);
if (0 > n) {
n = 0;
} else if (9 < n) {
n = 9;
}
oj_default_options.sec_prec = n;
}
v = rb_hash_lookup(opts, mode_sym);
if (Qnil == v) {
// ignore
} else if (object_sym == v) {
oj_default_options.mode = ObjectMode;
} else if (strict_sym == v) {
oj_default_options.mode = StrictMode;
} else if (compat_sym == v) {
oj_default_options.mode = CompatMode;
} else if (null_sym == v) {
oj_default_options.mode = NullMode;
} else {
rb_raise(rb_eArgError, ":mode must be :object, :strict, :compat, or :null.");
}
v = rb_hash_lookup(opts, time_format_sym);
if (Qnil == v) {
// ignore
} else if (unix_sym == v) {
oj_default_options.time_format = UnixTime;
} else if (xmlschema_sym == v) {
oj_default_options.time_format = XmlTime;
} else if (ruby_sym == v) {
oj_default_options.time_format = RubyTime;
} else {
rb_raise(rb_eArgError, ":time_format must be :unix, :xmlschema, or :ruby.");
}
if (Qtrue == rb_funcall(opts, rb_intern("has_key?"), 1, create_id_sym)) {
if (0 != oj_default_options.create_id) {
if (json_class != oj_default_options.create_id) {
xfree((char*)oj_default_options.create_id);
}
oj_default_options.create_id = 0;
oj_default_options.create_id_len = 0;
}
v = rb_hash_lookup(opts, create_id_sym);
if (Qnil != v) {
size_t len = RSTRING_LEN(v) + 1;
oj_default_options.create_id = ALLOC_N(char, len);
strcpy((char*)oj_default_options.create_id, StringValuePtr(v));
oj_default_options.create_id_len = len - 1;
}
}
for (o = ynos; 0 != o->attr; o++) {
if (Qtrue != rb_funcall(opts, rb_intern("has_key?"), 1, o->sym)) {
continue;
}
if (Qnil != (v = rb_hash_lookup(opts, o->sym))) {
if (Qtrue == v) {
*o->attr = Yes;
} else if (Qfalse == v) {
*o->attr = No;
} else {
rb_raise(rb_eArgError, "%s must be true, false, or nil.", rb_id2name(SYM2ID(o->sym)));
}
}
}
return Qnil;
}
|
+ (Object) dump(obj, options)
Dumps an Object (obj) to a string.
647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 |
# File 'ext/oj/oj.c', line 647
static VALUE
dump(int argc, VALUE *argv, VALUE self) {
char buf[4096];
struct _Out out;
struct _Options copts = oj_default_options;
VALUE rstr;
if (2 == argc) {
oj_parse_options(argv[1], &copts);
}
out.buf = buf;
out.end = buf + sizeof(buf) - 10;
out.allocated = 0;
oj_dump_obj_to_json(*argv, &copts, &out);
if (0 == out.buf) {
rb_raise(rb_eNoMemError, "Not enough memory.");
}
rstr = rb_str_new2(out.buf);
#if HAS_ENCODING_SUPPORT
rb_enc_associate(rstr, oj_utf8_encoding);
#endif
if (out.allocated) {
xfree(out.buf);
}
return rstr;
}
|
+ (Object, ...) load(json, options)
Parses a JSON document String into a Object, Hash, Array, String, Fixnum, Float, true, false, or nil according to the default mode or the mode specified. Raises an exception if the JSON is malformed or the classes specified are not valid. If the string input is not a valid JSON document (an empty string is not a valid JSON document) an exception is raised.
480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 |
# File 'ext/oj/oj.c', line 480
static VALUE
load(int argc, VALUE *argv, VALUE self) {
Mode mode = oj_default_options.mode;
if (1 > argc) {
rb_raise(rb_eArgError, "Wrong number of arguments to load().");
}
if (2 <= argc) {
VALUE ropts = argv[1];
VALUE v;
if (Qnil != (v = rb_hash_lookup(ropts, mode_sym))) {
if (object_sym == v) {
mode = ObjectMode;
} else if (strict_sym == v) {
mode = StrictMode;
} else if (compat_sym == v) {
mode = CompatMode;
} else if (null_sym == v) {
mode = NullMode;
} else {
rb_raise(rb_eArgError, ":mode must be :object, :strict, :compat, or :null.");
}
}
}
switch (mode) {
case StrictMode:
return oj_strict_parse(argc, argv, self);
case NullMode:
case CompatMode:
return oj_compat_parse(argc, argv, self);
case ObjectMode:
default:
break;
}
return oj_object_parse(argc, argv, self);
}
|
+ (Object) load_file
call-seq: load_file(path, options) => Object, Hash, Array, String, Fixnum, Float, true, false, or nil
Parses a JSON document String into a Object, Hash, Array, String, Fixnum, Float, true, false, or nil according to the default mode or the mode specified. Raises an exception if the JSON is malformed or the classes specified are not valid. If the string input is not a valid JSON document (an empty string is not a valid JSON document) an exception is raised.
If the input file is not a valid JSON document (an empty file is not a valid JSON document) an exception is raised.
533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 |
# File 'ext/oj/oj.c', line 533
static VALUE
load_file(int argc, VALUE *argv, VALUE self) {
char *path;
char *json;
FILE *f;
unsigned long len;
Mode mode = oj_default_options.mode;
Check_Type(*argv, T_STRING);
path = StringValuePtr(*argv);
if (0 == (f = fopen(path, "r"))) {
rb_raise(rb_eIOError, "%s", strerror(errno));
}
fseek(f, 0, SEEK_END);
len = ftell(f);
json = ALLOC_N(char, len + 1);
fseek(f, 0, SEEK_SET);
if (len != fread(json, 1, len, f)) {
xfree(json);
fclose(f);
rb_raise(rb_const_get_at(Oj, rb_intern("LoadError")), "Failed to read %ld bytes from %s.", len, path);
}
fclose(f);
json[len] = '\0';
if (1 > argc) {
rb_raise(rb_eArgError, "Wrong number of arguments to load().");
}
if (2 <= argc) {
VALUE ropts = argv[1];
VALUE v;
if (Qnil != (v = rb_hash_lookup(ropts, mode_sym))) {
if (object_sym == v) {
mode = ObjectMode;
} else if (strict_sym == v) {
mode = StrictMode;
} else if (compat_sym == v) {
mode = CompatMode;
} else if (null_sym == v) {
mode = NullMode;
} else {
rb_raise(rb_eArgError, ":mode must be :object, :strict, :compat, or :null.");
}
}
}
// The json string is freed in the parser when it is finished with it.
switch (mode) {
case StrictMode:
return oj_strict_parse_cstr(argc, argv, json);
case NullMode:
case CompatMode:
return oj_compat_parse_cstr(argc, argv, json);
case ObjectMode:
default:
break;
}
return oj_object_parse_cstr(argc, argv, json);
}
|
+ (Object) mimic_JSON
call-seq: mimic_JSON() => Module
Creates the JSON module with methods and classes to mimic the JSON gem. After this method is invoked calls that expect the JSON module will use Oj instead and be faster than the original JSON. Most options that could be passed to the JSON methods are supported. The calls to set parser or generator will not raise an Exception but will not have any effect. The method can also be called after the json gem is loaded. The necessary methods on the json gem will be replaced with Oj methods.
976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 |
# File 'ext/oj/oj.c', line 976
static VALUE
define_mimic_json(int argc, VALUE *argv, VALUE self) {
VALUE ext;
VALUE dummy;
// Either set the paths to indicate JSON has been loaded or replaces the
// methods if it has been loaded.
if (rb_const_defined_at(rb_cObject, rb_intern("JSON"))) {
mimic = rb_const_get_at(rb_cObject, rb_intern("JSON"));
} else {
mimic = rb_define_module("JSON");
}
if (rb_const_defined_at(mimic, rb_intern("Ext"))) {
ext = rb_const_get_at(mimic, rb_intern("Ext"));
} else {
ext = rb_define_module_under(mimic, "Ext");
}
if (!rb_const_defined_at(ext, rb_intern("Parser"))) {
dummy = rb_define_class_under(ext, "Parser", rb_cObject);
}
if (!rb_const_defined_at(ext, rb_intern("Generator"))) {
dummy = rb_define_class_under(ext, "Generator", rb_cObject);
}
// convince Ruby that the json gem has already been loaded
dummy = rb_gv_get("$LOADED_FEATURES");
if (rb_type(dummy) == T_ARRAY) {
rb_ary_push(dummy, rb_str_new2("json"));
if (0 < argc) {
VALUE mimic_args[1];
*mimic_args = *argv;
rb_funcall2(Oj, rb_intern("mimic_loaded"), 1, mimic_args);
} else {
rb_funcall2(Oj, rb_intern("mimic_loaded"), 0, 0);
}
}
dummy = rb_gv_get("$VERBOSE");
rb_gv_set("$VERBOSE", Qfalse);
rb_define_module_function(mimic, "parser=", no_op1, 1);
rb_define_module_function(mimic, "generator=", no_op1, 1);
rb_define_module_function(mimic, "create_id=", mimic_create_id, 1);
rb_define_module_function(mimic, "dump", mimic_dump, -1);
rb_define_module_function(mimic, "load", mimic_load, -1);
rb_define_module_function(mimic, "restore", mimic_load, -1);
rb_define_module_function(mimic, "recurse_proc", mimic_recurse_proc, 1);
rb_define_module_function(mimic, "[]", mimic_dump_load, -1);
rb_define_module_function(mimic, "generate", mimic_generate, -1);
rb_define_module_function(mimic, "fast_generate", mimic_generate, -1);
rb_define_module_function(mimic, "pretty_generate", mimic_pretty_generate, -1);
/* for older versions of JSON, the deprecated unparse methods */
rb_define_module_function(mimic, "unparse", mimic_generate, -1);
rb_define_module_function(mimic, "fast_unparse", mimic_generate, -1);
rb_define_module_function(mimic, "pretty_unparse", mimic_pretty_generate, -1);
rb_define_module_function(mimic, "parse", mimic_parse, -1);
rb_define_module_function(mimic, "parse!", mimic_parse, -1);
rb_gv_set("$VERBOSE", dummy);
array_nl_sym = ID2SYM(rb_intern("array_nl")); rb_gc_register_address(&array_nl_sym);
create_additions_sym = ID2SYM(rb_intern("create_additions")); rb_gc_register_address(&create_additions_sym);
object_nl_sym = ID2SYM(rb_intern("object_nl")); rb_gc_register_address(&object_nl_sym);
space_before_sym = ID2SYM(rb_intern("space_before")); rb_gc_register_address(&space_before_sym);
space_sym = ID2SYM(rb_intern("space")); rb_gc_register_address(&space_sym);
symbolize_names_sym = ID2SYM(rb_intern("symbolize_names")); rb_gc_register_address(&symbolize_names_sym);
oj_default_options.mode = CompatMode;
oj_default_options.ascii_only = Yes;
return mimic;
}
|
+ (Object) mimic_loaded(mimic_paths = [])
4 5 6 7 8 9 10 11 12 13 14 15 |
# File 'lib/oj/mimic.rb', line 4 def self.mimic_loaded(mimic_paths=[]) $LOAD_PATH.each do |d| next unless File.exist?(d) offset = d.size() + 1 Dir.glob(File.join(d, '**', '*.rb')).each do |file| next unless file[offset..-1].start_with?('json') $LOADED_FEATURES << file unless $LOADED_FEATURES.include?(file) end end mimic_paths.each { |p| $LOADED_FEATURES << p } $LOADED_FEATURES << 'json' unless $LOADED_FEATURES.include?('json') end |
+ (Object, ...) object_load(json, options)
Parses a JSON document String into an Object, Hash, Array, String, Fixnum, Float, true, false, or nil. In the :object mode the JSON should have been generated by Oj.dump(). The parser will reconstitute the original marshalled or dumped Object. The :auto_define and :circular options have meaning with this parsing mode.
Raises an exception if the JSON is malformed or the classes specified are not valid. If the input is not a valid JSON document (an empty string is not a valid JSON document) an exception is raised.
+ (Hash|Array|String|Fixnum|Bignum|BigDecimal|nil|True|False) safe_load(doc)
Loads a JSON document in strict mode with :auto_define and :symbol_keys turned off. This function should be safe to use with JSON received on an unprotected public interface.
602 603 604 605 606 607 608 609 610 611 612 613 614 615 |
# File 'ext/oj/oj.c', line 602
static VALUE
safe_load(VALUE self, VALUE doc) {
struct _ParseInfo pi;
VALUE args[1];
pi.options = oj_default_options;
pi.options.auto_define = No;
pi.options.sym_key = No;
pi.options.mode = StrictMode;
oj_set_strict_callbacks(&pi);
*args = doc;
return oj_pi_parse(1, args, &pi, 0);
}
|
+ (Object) saj_parse
+ (Object) sc_parse
+ (Hash, ...) strict_load(json, options)
Parses a JSON document String into an Hash, Array, String, Fixnum, Float, true, false, or nil. It parses using a mode that is strict in that it maps each primitive JSON type to a similar Ruby type. The :create_id is not honored in this mode. Note that a Ruby Hash is used to represent the JSON Object type. These two are not the same since teh JSON Object type can have repeating entries with the same key and Ruby Hash can not.
Raises an exception if the JSON is malformed or the classes specified are not valid. If the input is not a valid JSON document (an empty string is not a valid JSON document) an exception is raised.
+ (Object) to_file(file_path, obj, options)
Dumps an Object to the specified file.
684 685 686 687 688 689 690 691 692 693 694 695 |
# File 'ext/oj/oj.c', line 684
static VALUE
to_file(int argc, VALUE *argv, VALUE self) {
struct _Options copts = oj_default_options;
if (3 == argc) {
oj_parse_options(argv[2], &copts);
}
Check_Type(*argv, T_STRING);
oj_write_obj_to_file(argv[1], StringValuePtr(*argv), &copts);
return Qnil;
}
|