Module: Iodine::JSON

Defined in:
lib/iodine/json.rb,
ext/iodine/iodine_json.c

Overview

Iodine includes a lenient JSON parser that attempts to ignore JSON errors when possible and adds some extensions such as Hex numerical representations and comments.

Depending on content (specifically, the effects of float number parsing), the Iodine JSON parser speed varies.

On my system, Iodine is about 20%-30% faster than Ruby MRI's parser (Ruby version 2.5.1 vs. Iodine version 0.7.4). When using symbols the speed increase is even higher (50%-90% faster).

It's easy to monkey-patch the system's JSON.parse method (not the JSON.parse! method) by using Iodine.patch_json.

You can benchmark the Iodine JSON performance and decide if you wish to monkey-patch the Ruby implementation.

 JSON_FILENAME="foo.json"

 require 'json'
 require 'iodine'
 TIMES = 100
 STR = IO.binread(JSON_FILENAME); nil

 JSON.parse(STR) == Iodine::JSON.parse(STR) # => true
 JSON.parse!(STR) == Iodine::JSON.parse!(STR) # => undefined, maybe true maybe false

 # warm-up
 TIMES.times { JSON.parse STR }
 TIMES.times { Iodine::JSON.parse STR }

 puts ""; Benchmark.bm do |b|
   sys = b.report("system") { TIMES.times { JSON.parse STR } }
   sys_sym = b.report("system-sym") { TIMES.times { JSON.parse STR, symbolize_names: true } }
   iodine = b.report("iodine") { TIMES.times { Iodine::JSON.parse STR } }
   iodine_sym = b.report("iodine-sym") { TIMES.times { Iodine::JSON.parse STR, symbolize_names: true } }

   puts "----------------------------"
   puts "Iodine::JSON speed as percent of Ruby's native JSON:"
   puts "normal:    #{sys/iodine}"
   puts "symolized: #{sys_sym/iodine_sym}"
 end; nil

Note that the bang(!) method should NOT be used for monkey-patching the default JSON parser, since some important features are unsupported by the Iodine parser.

Class Method Summary collapse

Class Method Details

.parse(*args) ⇒ Object

Parse a JSON string using the iodine lenient parser (it's also faster).


217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
# File 'ext/iodine/iodine_json.c', line 217

static VALUE iodine_json_parse(int argc, VALUE *argv, VALUE self) {
  fiobj2rb_settings_s s = {.str2sym = 0};
  if (argc > 2)
    rb_raise(rb_eTypeError, "function requires supports up to two arguments.");
  if (argc == 2) {
    Check_Type(argv[1], T_HASH);
    iodine_json_update_settings(argv[1], &s);
  }
  if (argc >= 1)
    Check_Type(argv[0], T_STRING);
  else
    rb_raise(rb_eTypeError, "function requires at least one argument.");
  return iodine_json_convert(argv[0], s);
  (void)self;
}

.parse!(*args) ⇒ Object

Parse a JSON string using the iodine lenient parser with a default Symbol rather than String key (this is often faster than the regular parse function).


238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
# File 'ext/iodine/iodine_json.c', line 238

static VALUE iodine_json_parse_bang(int argc, VALUE *argv, VALUE self) {
  fiobj2rb_settings_s s = {.str2sym = 0};
  if (argc > 2)
    rb_raise(rb_eTypeError, "function requires supports up to two arguments.");
  if (argc == 2) {
    Check_Type(argv[1], T_HASH);
    iodine_json_update_settings(argv[1], &s);
  }
  if (argc >= 1)
    Check_Type(argv[0], T_STRING);
  else
    rb_raise(rb_eTypeError, "function requires at least one argument.");
  return iodine_json_convert(argv[0], s);
  (void)self;
}