Namespace

Files

Oj

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.


for older versions of JSON, the deprecated unparse methods

Constants

VERSION

Current version of the module.

Public Class Methods

default_options() => Hash click to toggle source

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

  • 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

  • create_id: [String|nil] create id for json compatible object encoding, default is 'json_create'

  • max_stack: [Fixnum|nil] maximum json size to allocate on the stack, default is 65536

@return [Hash] all current option settings.

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, max_stack_sym, INT2FIX(oj_default_options.max_stack));
    rb_hash_aset(opts, circular_sym, (Yes == oj_default_options.circular) ? Qtrue : ((No == oj_default_options.circular) ? 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));
    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;
}
default_options=(opts) click to toggle source

Sets the default options for load and dump. @param [Hash] opts options to change @param [Fixnum] :indent number of spaces to indent each element in an JSON document @param [true|false|nil] :circular support circular references while dumping @param [true|false|nil] :auto_define automatically define classes if they do not exist @param [true|false|nil] :symbol_keys convert hash keys to symbols @param [true|false|nil] :ascii_only encode all high-bit characters as escaped sequences if true @param [:object|:strict|:compat|:null] load and dump mode to use for JSON

:strict raises an exception when a non-supported Object is
encountered. :compat attempts to extract variable values from an
Object using to_json() or to_hash() then it walks the Object's
variables if neither is found. The :object mode ignores to_hash()
and to_json() methods and encodes variables using code internal to
the Oj gem. The :null mode ignores non-supported Objects and
replaces them with a null.

@param [:unix|:xmlschema|:ruby] time format when dumping in :compat mode

:unix decimal number denoting the number of seconds since 1/1/1970,
:xmlschema date-time format taken from XML Schema as a String,
:ruby Time.to_s formatted String

@param [String|nil] :create_id create id for json compatible object encoding @param [Fixnum|nil] :max_stack maximum size to allocate on the stack for a JSON String @return [nil]

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 },
        { ascii_only_sym, &oj_default_options.ascii_only },
        { 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, max_stack_sym);
    if (Qnil != v) {
        int    i;

        Check_Type(v, T_FIXNUM);
        i = FIX2INT(v);
        if (0 > i) {
            i = 0;
        }
        oj_default_options.max_stack = (size_t)i;
    }

    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;
        }
        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));
        }
    }

    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;
}
dump(obj, anIO=nil, limit = nil) → String click to toggle source

Encodes an object as a JSON String.

@param [Object] obj object to convert to encode as JSON @param [IO] anIO an IO that allows writing @param [Fixnum] limit ignored

static VALUE
dump(int argc, VALUE *argv, VALUE self) {
    char                *json;
    struct _Options     copts = oj_default_options;
    VALUE               rstr;
    
    if (2 == argc) {
        parse_options(argv[1], &copts);
    }
    if (0 == (json = oj_write_obj_to_str(*argv, &copts))) {
        rb_raise(rb_eNoMemError, "Not enough memory.");
    }
    rstr = rb_str_new2(json);
#if HAS_ENCODING_SUPPORT
    rb_enc_associate(rstr, oj_utf8_encoding);
#endif
    xfree(json);

    return rstr;
}
load(source, proc=nil) → Object click to toggle source

Loads a Ruby Object from a JSON source that can be either a String or an IO. If Proc is given or a block is providedit is called with each nested element of the loaded Object.

@param [String|IO] source JSON source @param [Proc] proc to yield to on each element or nil

static VALUE
load(int argc, VALUE *argv, VALUE self) {
    struct _Options     options = oj_default_options;

    if (1 > argc) {
        rb_raise(rb_eArgError, "Wrong number of arguments to load().");
    }
    if (2 <= argc) {
        parse_options(argv[1], &options);
    }
    return load_with_opts(*argv, &options);
}
load_file(path, options) => Hash, Array, String, Fixnum, Float, true, false, or nil click to toggle source

Parses a JSON document from a file into a Hash, Array, String, Fixnum, Float, true, false, or nil. Raises an exception if the JSON is malformed or the classes specified are not valid.

@param [String] path path to a file containing a JSON document @param [Hash] options load options (same as default_options)

static VALUE
load_file(int argc, VALUE *argv, VALUE self) {
    char                *path;
    char                *json;
    FILE                *f;
    unsigned long       len;
    VALUE               obj;
    struct _Options     options = oj_default_options;
    size_t              max_stack = oj_default_options.max_stack;

    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);
    if (max_stack < len) {
        json = ALLOC_N(char, len + 1);
    } else {
        json = ALLOCA_N(char, len + 1);
    }
    fseek(f, 0, SEEK_SET);
    if (len != fread(json, 1, len, f)) {
        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 (2 <= argc) {
        parse_options(argv[1], &options);
    }
    obj = oj_parse(json, &options);
    if (max_stack < len) {
        xfree(json);
    }
    return obj;
}
mimic_JSON() => Module click to toggle source

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.

static VALUE
define_mimic_json(int argc, VALUE *argv, VALUE self) {
    if (Qnil == mimic) {
        VALUE  ext;
        VALUE  dummy;

        if (rb_const_defined_at(rb_cObject, rb_intern("JSON"))) {
            rb_raise(rb_const_get_at(Oj, rb_intern("MimicError")),
                     "JSON module already exists. Can not mimic. Do not require 'json' before calling mimic_JSON.");
        }
        mimic = rb_define_module("JSON");
        ext = rb_define_module_under(mimic, "Ext");
        dummy = rb_define_class_under(ext, "Parser", rb_cObject);
        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);
            }
        }

        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);

        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;
}
mimic_loaded(mimic_paths=[]) click to toggle source
# File lib/oj/mimic.rb, line 4
def self.mimic_loaded(mimic_paths=[])
  gems_dir = File.dirname(File.dirname(File.dirname(File.dirname(__FILE__))))
  Dir.foreach(gems_dir) do |gem|
    next unless (gem.start_with?('json-') || gem.start_with?('json_pure'))
    $LOADED_FEATURES << File.join(gems_dir, gem, 'lib', 'json.rb')
  end
  mimic_paths.each { |p| $LOADED_FEATURES << p }
end
saj_parse(handler, io) click to toggle source

Parses an IO stream or file containing an JSON document. Raises an exception if the JSON is malformed. @param [Oj::Saj] handler SAJ (responds to Oj::Saj methods) like handler @param [IO|String] io IO Object to read from

static VALUE
saj_parse(int argc, VALUE *argv, VALUE self) {
    struct _Options     copts = oj_default_options;
    char                *json;
    size_t              len;
    VALUE               input = argv[1];

    if (argc < 2) {
        rb_raise(rb_eArgError, "Wrong number of arguments to saj_parse.\n");
    }
    if (rb_type(input) == T_STRING) {
        // the json string gets modified so make a copy of it
        len = RSTRING_LEN(input) + 1;
        if (copts.max_stack < len) {
            json = ALLOC_N(char, len);
        } else {
            json = ALLOCA_N(char, len);
        }
        strcpy(json, StringValuePtr(input));
    } else {
        VALUE  clas = rb_obj_class(input);
        VALUE  s;

        if (oj_stringio_class == clas) {
            s = rb_funcall2(input, oj_string_id, 0, 0);
            len = RSTRING_LEN(s) + 1;
            if (copts.max_stack < len) {
                json = ALLOC_N(char, len);
            } else {
                json = ALLOCA_N(char, len);
            }
            strcpy(json, StringValuePtr(s));
#ifndef JRUBY_RUBY
#if !IS_WINDOWS
            // JRuby gets confused with what is the real fileno.
        } else if (rb_respond_to(input, oj_fileno_id) && Qnil != (s = rb_funcall(input, oj_fileno_id, 0))) {
            int                fd = FIX2INT(s);
            ssize_t    cnt;

            len = lseek(fd, 0, SEEK_END);
            lseek(fd, 0, SEEK_SET);
            if (copts.max_stack < len) {
                json = ALLOC_N(char, len + 1);
            } else {
                json = ALLOCA_N(char, len + 1);
            }
            if (0 >= (cnt = read(fd, json, len)) || cnt != (ssize_t)len) {
                rb_raise(rb_eIOError, "failed to read from IO Object.");
            }
            json[len] = '\0';
#endif
#endif
        } else if (rb_respond_to(input, oj_read_id)) {
            s = rb_funcall2(input, oj_read_id, 0, 0);
            len = RSTRING_LEN(s) + 1;
            if (copts.max_stack < len) {
                json = ALLOC_N(char, len);
            } else {
                json = ALLOCA_N(char, len);
            }
            strcpy(json, StringValuePtr(s));
        } else {
            rb_raise(rb_eArgError, "saj_parse() expected a String or IO Object.");
        }
    }
    oj_saj_parse(*argv, json);
    if (copts.max_stack < len) {
        xfree(json);
    }
    return Qnil;
}
to_file(file_path, obj, options) click to toggle source

Dumps an Object to the specified file. @param [String] file_path file path to write the JSON document to @param [Object] obj Object to serialize as an JSON document String @param [Hash] options formating options @param [Fixnum] :indent format expected @param [true|false] :circular allow circular references, default: false

static VALUE
to_file(int argc, VALUE *argv, VALUE self) {
    struct _Options     copts = oj_default_options;
    
    if (3 == argc) {
        parse_options(argv[2], &copts);
    }
    Check_Type(*argv, T_STRING);
    oj_write_obj_to_file(argv[1], StringValuePtr(*argv), &copts);

    return Qnil;
}

[Validate]

Generated with the Darkfish Rdoc Generator 2.