oj 2.13.1 → 2.14.0
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.
- checksums.yaml +4 -4
- data/README.md +177 -104
- data/ext/oj/dump.c +60 -60
- data/ext/oj/oj.c +319 -343
- data/ext/oj/oj.h +27 -25
- data/ext/oj/parse.c +19 -9
- data/lib/oj/version.rb +1 -1
- data/test/test_various.rb +47 -32
- metadata +2 -4
- data/test/zip.rb +0 -34
data/ext/oj/oj.c
CHANGED
@@ -90,6 +90,8 @@ ID oj_utc_offset_id;
|
|
90
90
|
ID oj_utcq_id;
|
91
91
|
ID oj_write_id;
|
92
92
|
|
93
|
+
static ID has_key_id;
|
94
|
+
|
93
95
|
VALUE oj_bag_class;
|
94
96
|
VALUE oj_bigdecimal_class;
|
95
97
|
VALUE oj_cstack_class;
|
@@ -160,26 +162,38 @@ VALUE oj_cache_mutex = Qnil;
|
|
160
162
|
static const char json_class[] = "json_class";
|
161
163
|
|
162
164
|
struct _Options oj_default_options = {
|
163
|
-
0,
|
164
|
-
No,
|
165
|
-
No,
|
166
|
-
No,
|
167
|
-
JSONEsc,
|
168
|
-
ObjectMode,
|
169
|
-
Yes,
|
170
|
-
UnixZTime,
|
171
|
-
Yes,
|
172
|
-
AutoDec,
|
173
|
-
Yes,
|
174
|
-
No,
|
175
|
-
Yes,
|
176
|
-
Yes,
|
177
|
-
json_class,
|
178
|
-
10,
|
179
|
-
9,
|
180
|
-
|
181
|
-
|
182
|
-
|
165
|
+
0, // indent
|
166
|
+
No, // circular
|
167
|
+
No, // auto_define
|
168
|
+
No, // sym_key
|
169
|
+
JSONEsc, // escape_mode
|
170
|
+
ObjectMode, // mode
|
171
|
+
Yes, // class_cache
|
172
|
+
UnixZTime, // time_format
|
173
|
+
Yes, // bigdec_as_num
|
174
|
+
AutoDec, // bigdec_load
|
175
|
+
Yes, // to_json
|
176
|
+
No, // nilnil
|
177
|
+
Yes, // allow_gc
|
178
|
+
Yes, // quirks_mode
|
179
|
+
json_class, // create_id
|
180
|
+
10, // create_id_len
|
181
|
+
9, // sec_prec
|
182
|
+
15, // float_prec
|
183
|
+
"%0.15g", // float_fmt
|
184
|
+
{ // dump_opts
|
185
|
+
false, //use
|
186
|
+
"", // indent
|
187
|
+
"", // before_sep
|
188
|
+
"", // after_sep
|
189
|
+
"", // hash_nl
|
190
|
+
"", // array_nl
|
191
|
+
0, // indent_size
|
192
|
+
0, // before_size
|
193
|
+
0, // after_size
|
194
|
+
0, // hash_size
|
195
|
+
0, // array_size
|
196
|
+
}
|
183
197
|
};
|
184
198
|
|
185
199
|
static VALUE define_mimic_json(int argc, VALUE *argv, VALUE self);
|
@@ -187,7 +201,7 @@ static VALUE define_mimic_json(int argc, VALUE *argv, VALUE self);
|
|
187
201
|
/* call-seq: default_options() => Hash
|
188
202
|
*
|
189
203
|
* Returns the default load and dump options as a Hash. The options are
|
190
|
-
* - indent: [Fixnum] number of spaces to indent each element in an JSON document, zero is no newline between JSON elements, negative indicates no newline between top level JSON elements in a stream
|
204
|
+
* - indent: [Fixnum|String|nil] number of spaces to indent each element in an JSON document, zero or nil is no newline between JSON elements, negative indicates no newline between top level JSON elements in a stream, a String indicates the string should be used for indentation
|
191
205
|
* - circular: [true|false|nil] support circular references while dumping
|
192
206
|
* - auto_define: [true|false|nil] automatically define classes if they do not exist
|
193
207
|
* - symbol_keys: [true|false|nil] use symbols instead of strings for hash keys
|
@@ -204,13 +218,22 @@ static VALUE define_mimic_json(int argc, VALUE *argv, VALUE self);
|
|
204
218
|
* - nilnil: [true|false|nil] if true a nil input to load will return nil and not raise an Exception
|
205
219
|
* - allow_gc: [true|false|nil] allow or prohibit GC during parsing, default is true (allow)
|
206
220
|
* - quirks_mode: [true,|false|nil] Allow single JSON values instead of documents, default is true (allow)
|
221
|
+
* - indent_str: [String|nil] String to use for indentation, overriding the indent option is not nil
|
222
|
+
* - space: [String|nil] String to use for the space after the colon in JSON object fields
|
223
|
+
* - space_before: [String|nil] String to use before the colon separator in JSON object fields
|
224
|
+
* - object_nl: [String|nil] String to use after a JSON object field value
|
225
|
+
* - array_nl: [String|nil] String to use after a JSON array value
|
207
226
|
* @return [Hash] all current option settings.
|
208
227
|
*/
|
209
228
|
static VALUE
|
210
229
|
get_def_opts(VALUE self) {
|
211
230
|
VALUE opts = rb_hash_new();
|
212
|
-
|
213
|
-
|
231
|
+
|
232
|
+
if (0 == oj_default_options.dump_opts.indent_size) {
|
233
|
+
rb_hash_aset(opts, indent_sym, INT2FIX(oj_default_options.indent));
|
234
|
+
} else {
|
235
|
+
rb_hash_aset(opts, indent_sym, rb_str_new2(oj_default_options.dump_opts.indent_str));
|
236
|
+
}
|
214
237
|
rb_hash_aset(opts, sec_prec_sym, INT2FIX(oj_default_options.sec_prec));
|
215
238
|
rb_hash_aset(opts, circular_sym, (Yes == oj_default_options.circular) ? Qtrue : ((No == oj_default_options.circular) ? Qfalse : Qnil));
|
216
239
|
rb_hash_aset(opts, class_cache_sym, (Yes == oj_default_options.class_cache) ? Qtrue : ((No == oj_default_options.class_cache) ? Qfalse : Qnil));
|
@@ -250,6 +273,10 @@ get_def_opts(VALUE self) {
|
|
250
273
|
default: rb_hash_aset(opts, bigdecimal_load_sym, auto_sym); break;
|
251
274
|
}
|
252
275
|
rb_hash_aset(opts, create_id_sym, (0 == oj_default_options.create_id) ? Qnil : rb_str_new2(oj_default_options.create_id));
|
276
|
+
rb_hash_aset(opts, space_sym, (0 == oj_default_options.dump_opts.after_size) ? Qnil : rb_str_new2(oj_default_options.dump_opts.after_sep));
|
277
|
+
rb_hash_aset(opts, space_before_sym, (0 == oj_default_options.dump_opts.before_size) ? Qnil : rb_str_new2(oj_default_options.dump_opts.before_sep));
|
278
|
+
rb_hash_aset(opts, object_nl_sym, (0 == oj_default_options.dump_opts.hash_size) ? Qnil : rb_str_new2(oj_default_options.dump_opts.hash_nl));
|
279
|
+
rb_hash_aset(opts, array_nl_sym, (0 == oj_default_options.dump_opts.array_size) ? Qnil : rb_str_new2(oj_default_options.dump_opts.array_nl));
|
253
280
|
|
254
281
|
return opts;
|
255
282
|
}
|
@@ -258,7 +285,7 @@ get_def_opts(VALUE self) {
|
|
258
285
|
*
|
259
286
|
* Sets the default options for load and dump.
|
260
287
|
* @param [Hash] opts options to change
|
261
|
-
* @param [Fixnum] :indent number of spaces to indent each element in
|
288
|
+
* @param [Fixnum|String|nil] :indent number of spaces to indent each element in a JSON document or the String to use for identation.
|
262
289
|
* @param [true|false|nil] :circular support circular references while dumping
|
263
290
|
* @param [true|false|nil] :auto_define automatically define classes if they do not exist
|
264
291
|
* @param [true|false|nil] :symbol_keys convert hash keys to symbols
|
@@ -289,314 +316,247 @@ get_def_opts(VALUE self) {
|
|
289
316
|
* @param [true|false|nil] :nilnil if true a nil input to load will return nil and not raise an Exception
|
290
317
|
* @param [true|false|nil] :allow_gc allow or prohibit GC during parsing, default is true (allow)
|
291
318
|
* @param [true|false|nil] :quirks_mode allow single JSON values instead of documents, default is true (allow)
|
319
|
+
* @param [String|nil] :space String to use for the space after the colon in JSON object fields
|
320
|
+
* @param [String|nil] :space_before String to use before the colon separator in JSON object fields
|
321
|
+
* @param [String|nil] :object_nl String to use after a JSON object field value
|
322
|
+
* @param [String|nil] :array_nl String to use after a JSON array value
|
292
323
|
* @return [nil]
|
293
324
|
*/
|
294
325
|
static VALUE
|
295
326
|
set_def_opts(VALUE self, VALUE opts) {
|
327
|
+
Check_Type(opts, T_HASH);
|
328
|
+
oj_parse_options(opts, &oj_default_options);
|
329
|
+
|
330
|
+
return Qnil;
|
331
|
+
}
|
332
|
+
|
333
|
+
void
|
334
|
+
oj_parse_options(VALUE ropts, Options copts) {
|
296
335
|
struct _YesNoOpt ynos[] = {
|
297
|
-
{ circular_sym, &
|
298
|
-
{ auto_define_sym, &
|
299
|
-
{ symbol_keys_sym, &
|
300
|
-
{ class_cache_sym, &
|
301
|
-
{ bigdecimal_as_decimal_sym, &
|
302
|
-
{ use_to_json_sym, &
|
303
|
-
{ nilnil_sym, &
|
304
|
-
{ allow_gc_sym, &
|
305
|
-
{ quirks_mode_sym, &
|
336
|
+
{ circular_sym, &copts->circular },
|
337
|
+
{ auto_define_sym, &copts->auto_define },
|
338
|
+
{ symbol_keys_sym, &copts->sym_key },
|
339
|
+
{ class_cache_sym, &copts->class_cache },
|
340
|
+
{ bigdecimal_as_decimal_sym, &copts->bigdec_as_num },
|
341
|
+
{ use_to_json_sym, &copts->to_json },
|
342
|
+
{ nilnil_sym, &copts->nilnil },
|
343
|
+
{ allow_gc_sym, &copts->allow_gc },
|
344
|
+
{ quirks_mode_sym, &copts->quirks_mode },
|
306
345
|
{ Qnil, 0 }
|
307
346
|
};
|
308
|
-
YesNoOpt
|
309
|
-
VALUE v;
|
347
|
+
YesNoOpt o;
|
348
|
+
volatile VALUE v;
|
349
|
+
size_t len;
|
310
350
|
|
311
|
-
|
312
|
-
|
313
|
-
if (Qnil != v) {
|
314
|
-
Check_Type(v, T_FIXNUM);
|
315
|
-
oj_default_options.indent = FIX2INT(v);
|
351
|
+
if (T_HASH != rb_type(ropts)) {
|
352
|
+
return;
|
316
353
|
}
|
317
|
-
|
318
|
-
|
354
|
+
if (Qtrue == rb_funcall(ropts, has_key_id, 1, indent_sym)) {
|
355
|
+
v = rb_hash_lookup(ropts, indent_sym);
|
356
|
+
switch (rb_type(v)) {
|
357
|
+
case T_NIL:
|
358
|
+
copts->dump_opts.indent_size = 0;
|
359
|
+
*copts->dump_opts.indent_str = '\0';
|
360
|
+
copts->indent = 0;
|
361
|
+
break;
|
362
|
+
case T_FIXNUM:
|
363
|
+
copts->dump_opts.indent_size = 0;
|
364
|
+
*copts->dump_opts.indent_str = '\0';
|
365
|
+
copts->indent = FIX2INT(v);
|
366
|
+
break;
|
367
|
+
case T_STRING:
|
368
|
+
if (sizeof(copts->dump_opts.indent_str) <= (len = RSTRING_LEN(v))) {
|
369
|
+
rb_raise(rb_eArgError, "indent string is limited to %lu characters.", sizeof(copts->dump_opts.indent_str));
|
370
|
+
}
|
371
|
+
strcpy(copts->dump_opts.indent_str, StringValuePtr(v));
|
372
|
+
copts->dump_opts.indent_size = (uint8_t)len;
|
373
|
+
copts->indent = 0;
|
374
|
+
break;
|
375
|
+
default:
|
376
|
+
rb_raise(rb_eTypeError, "indent must be a Fixnum, String, or nil.");
|
377
|
+
break;
|
378
|
+
}
|
379
|
+
}
|
380
|
+
if (Qnil != (v = rb_hash_lookup(ropts, float_prec_sym))) {
|
319
381
|
int n;
|
320
382
|
|
383
|
+
if (rb_cFixnum != rb_obj_class(v)) {
|
384
|
+
rb_raise(rb_eArgError, ":float_precision must be a Fixnum.");
|
385
|
+
}
|
321
386
|
Check_Type(v, T_FIXNUM);
|
322
387
|
n = FIX2INT(v);
|
323
388
|
if (0 >= n) {
|
324
|
-
*
|
325
|
-
|
389
|
+
*copts->float_fmt = '\0';
|
390
|
+
copts->float_prec = 0;
|
326
391
|
} else {
|
327
392
|
if (20 < n) {
|
328
393
|
n = 20;
|
329
394
|
}
|
330
|
-
sprintf(
|
331
|
-
|
395
|
+
sprintf(copts->float_fmt, "%%0.%dg", n);
|
396
|
+
copts->float_prec = n;
|
332
397
|
}
|
333
398
|
}
|
334
|
-
v =
|
335
|
-
if (Qnil != v) {
|
399
|
+
if (Qnil != (v = rb_hash_lookup(ropts, sec_prec_sym))) {
|
336
400
|
int n;
|
337
401
|
|
338
|
-
|
339
|
-
|
402
|
+
if (rb_cFixnum != rb_obj_class(v)) {
|
403
|
+
rb_raise(rb_eArgError, ":second_precision must be a Fixnum.");
|
404
|
+
}
|
405
|
+
n = NUM2INT(v);
|
340
406
|
if (0 > n) {
|
341
407
|
n = 0;
|
342
408
|
} else if (9 < n) {
|
343
409
|
n = 9;
|
344
410
|
}
|
345
|
-
|
346
|
-
}
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
} else {
|
360
|
-
rb_raise(rb_eArgError, ":mode must be :object, :strict, :compat, or :null.");
|
361
|
-
}
|
362
|
-
|
363
|
-
v = rb_hash_lookup(opts, time_format_sym);
|
364
|
-
if (Qnil == v) {
|
365
|
-
// ignore
|
366
|
-
} else if (unix_sym == v) {
|
367
|
-
oj_default_options.time_format = UnixTime;
|
368
|
-
} else if (unix_zone_sym == v) {
|
369
|
-
oj_default_options.time_format = UnixZTime;
|
370
|
-
} else if (xmlschema_sym == v) {
|
371
|
-
oj_default_options.time_format = XmlTime;
|
372
|
-
} else if (ruby_sym == v) {
|
373
|
-
oj_default_options.time_format = RubyTime;
|
374
|
-
} else {
|
375
|
-
rb_raise(rb_eArgError, ":time_format must be :unix, :unix_zone, :xmlschema, or :ruby.");
|
376
|
-
}
|
377
|
-
|
378
|
-
v = rb_hash_lookup(opts, escape_mode_sym);
|
379
|
-
if (Qnil == v) {
|
380
|
-
// ignore
|
381
|
-
} else if (newline_sym == v) {
|
382
|
-
oj_default_options.escape_mode = NLEsc;
|
383
|
-
} else if (json_sym == v) {
|
384
|
-
oj_default_options.escape_mode = JSONEsc;
|
385
|
-
} else if (xss_safe_sym == v) {
|
386
|
-
oj_default_options.escape_mode = XSSEsc;
|
387
|
-
} else if (ascii_sym == v) {
|
388
|
-
oj_default_options.escape_mode = ASCIIEsc;
|
389
|
-
} else {
|
390
|
-
rb_raise(rb_eArgError, ":escape_mode must be :newline, :json, :xss_safe, or :ascii.");
|
391
|
-
}
|
392
|
-
|
393
|
-
v = rb_hash_lookup(opts, bigdecimal_load_sym);
|
394
|
-
if (Qnil == v) {
|
395
|
-
// ignore
|
396
|
-
} else if (bigdecimal_sym == v || Qtrue == v) {
|
397
|
-
oj_default_options.bigdec_load = BigDec;
|
398
|
-
} else if (float_sym == v) {
|
399
|
-
oj_default_options.bigdec_load = FloatDec;
|
400
|
-
} else if (auto_sym == v || Qfalse == v) {
|
401
|
-
oj_default_options.bigdec_load = AutoDec;
|
402
|
-
} else {
|
403
|
-
rb_raise(rb_eArgError, ":bigdecimal_load must be :bigdecimal, :float, or :auto.");
|
411
|
+
copts->sec_prec = n;
|
412
|
+
}
|
413
|
+
if (Qnil != (v = rb_hash_lookup(ropts, mode_sym))) {
|
414
|
+
if (object_sym == v) {
|
415
|
+
copts->mode = ObjectMode;
|
416
|
+
} else if (strict_sym == v) {
|
417
|
+
copts->mode = StrictMode;
|
418
|
+
} else if (compat_sym == v) {
|
419
|
+
copts->mode = CompatMode;
|
420
|
+
} else if (null_sym == v) {
|
421
|
+
copts->mode = NullMode;
|
422
|
+
} else {
|
423
|
+
rb_raise(rb_eArgError, ":mode must be :object, :strict, :compat, or :null.");
|
424
|
+
}
|
404
425
|
}
|
405
|
-
|
406
|
-
|
407
|
-
|
426
|
+
if (Qnil != (v = rb_hash_lookup(ropts, time_format_sym))) {
|
427
|
+
if (unix_sym == v) {
|
428
|
+
copts->time_format = UnixTime;
|
429
|
+
} else if (unix_zone_sym == v) {
|
430
|
+
copts->time_format = UnixZTime;
|
431
|
+
} else if (xmlschema_sym == v) {
|
432
|
+
copts->time_format = XmlTime;
|
433
|
+
} else if (ruby_sym == v) {
|
434
|
+
copts->time_format = RubyTime;
|
435
|
+
} else {
|
436
|
+
rb_raise(rb_eArgError, ":time_format must be :unix, :unix_zone, :xmlschema, or :ruby.");
|
437
|
+
}
|
438
|
+
}
|
439
|
+
if (Qnil != (v = rb_hash_lookup(ropts, escape_mode_sym))) {
|
440
|
+
if (newline_sym == v) {
|
441
|
+
copts->escape_mode = NLEsc;
|
442
|
+
} else if (json_sym == v) {
|
443
|
+
copts->escape_mode = JSONEsc;
|
444
|
+
} else if (xss_safe_sym == v) {
|
445
|
+
copts->escape_mode = XSSEsc;
|
446
|
+
} else if (ascii_sym == v) {
|
447
|
+
copts->escape_mode = ASCIIEsc;
|
448
|
+
} else {
|
449
|
+
rb_raise(rb_eArgError, ":encoding must be :newline, :json, :xss_safe, or :ascii.");
|
450
|
+
}
|
451
|
+
}
|
452
|
+
if (Qnil != (v = rb_hash_lookup(ropts, bigdecimal_load_sym))) {
|
453
|
+
if (bigdecimal_sym == v || Qtrue == v) {
|
454
|
+
copts->bigdec_load = BigDec;
|
455
|
+
} else if (float_sym == v) {
|
456
|
+
copts->bigdec_load = FloatDec;
|
457
|
+
} else if (auto_sym == v || Qfalse == v) {
|
458
|
+
copts->bigdec_load = AutoDec;
|
459
|
+
} else {
|
460
|
+
rb_raise(rb_eArgError, ":bigdecimal_load must be :bigdecimal, :float, or :auto.");
|
461
|
+
}
|
462
|
+
}
|
463
|
+
if (Qtrue == rb_funcall(ropts, has_key_id, 1, create_id_sym)) {
|
464
|
+
v = rb_hash_lookup(ropts, create_id_sym);
|
465
|
+
if (Qnil == v) {
|
408
466
|
if (json_class != oj_default_options.create_id) {
|
409
467
|
xfree((char*)oj_default_options.create_id);
|
410
468
|
}
|
411
|
-
|
412
|
-
|
413
|
-
}
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
469
|
+
copts->create_id = NULL;
|
470
|
+
copts->create_id_len = 0;
|
471
|
+
} else if (T_STRING == rb_type(v)) {
|
472
|
+
const char *str = StringValuePtr(v);
|
473
|
+
|
474
|
+
len = RSTRING_LEN(v);
|
475
|
+
if (len != copts->create_id_len ||
|
476
|
+
0 != strcmp(copts->create_id, str)) {
|
477
|
+
copts->create_id = ALLOC_N(char, len + 1);
|
478
|
+
strcpy((char*)copts->create_id, str);
|
479
|
+
copts->create_id_len = len;
|
480
|
+
}
|
481
|
+
} else {
|
482
|
+
rb_raise(rb_eArgError, ":create_id must be string.");
|
421
483
|
}
|
422
484
|
}
|
423
|
-
|
424
485
|
for (o = ynos; 0 != o->attr; o++) {
|
425
|
-
if (
|
426
|
-
continue;
|
427
|
-
}
|
428
|
-
if (Qnil != (v = rb_hash_lookup(opts, o->sym))) {
|
486
|
+
if (Qnil != (v = rb_hash_lookup(ropts, o->sym))) {
|
429
487
|
if (Qtrue == v) {
|
430
488
|
*o->attr = Yes;
|
431
489
|
} else if (Qfalse == v) {
|
432
490
|
*o->attr = No;
|
433
491
|
} else {
|
434
|
-
rb_raise(rb_eArgError, "%s must be true
|
492
|
+
rb_raise(rb_eArgError, "%s must be true or false.", rb_id2name(SYM2ID(o->sym)));
|
435
493
|
}
|
436
494
|
}
|
437
495
|
}
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
}
|
447
|
-
|
448
|
-
void
|
449
|
-
oj_parse_options(VALUE ropts, Options copts) {
|
450
|
-
struct _YesNoOpt ynos[] = {
|
451
|
-
{ circular_sym, &copts->circular },
|
452
|
-
{ auto_define_sym, &copts->auto_define },
|
453
|
-
{ symbol_keys_sym, &copts->sym_key },
|
454
|
-
{ class_cache_sym, &copts->class_cache },
|
455
|
-
{ bigdecimal_as_decimal_sym, &copts->bigdec_as_num },
|
456
|
-
{ use_to_json_sym, &copts->to_json },
|
457
|
-
{ nilnil_sym, &copts->nilnil },
|
458
|
-
{ allow_gc_sym, &copts->allow_gc },
|
459
|
-
{ quirks_mode_sym, &copts->quirks_mode },
|
460
|
-
{ Qnil, 0 }
|
461
|
-
};
|
462
|
-
YesNoOpt o;
|
463
|
-
|
464
|
-
if (rb_cHash == rb_obj_class(ropts)) {
|
465
|
-
VALUE v;
|
466
|
-
|
467
|
-
if (Qnil != (v = rb_hash_lookup(ropts, indent_sym))) {
|
468
|
-
if (rb_cFixnum != rb_obj_class(v)) {
|
469
|
-
rb_raise(rb_eArgError, ":indent must be a Fixnum.");
|
470
|
-
}
|
471
|
-
copts->indent = NUM2INT(v);
|
472
|
-
}
|
473
|
-
if (Qnil != (v = rb_hash_lookup(ropts, float_prec_sym))) {
|
474
|
-
int n;
|
475
|
-
|
476
|
-
if (rb_cFixnum != rb_obj_class(v)) {
|
477
|
-
rb_raise(rb_eArgError, ":float_precision must be a Fixnum.");
|
478
|
-
}
|
479
|
-
Check_Type(v, T_FIXNUM);
|
480
|
-
n = FIX2INT(v);
|
481
|
-
if (0 >= n) {
|
482
|
-
*copts->float_fmt = '\0';
|
483
|
-
copts->float_prec = 0;
|
484
|
-
} else {
|
485
|
-
if (20 < n) {
|
486
|
-
n = 20;
|
487
|
-
}
|
488
|
-
sprintf(copts->float_fmt, "%%0.%dg", n);
|
489
|
-
copts->float_prec = n;
|
490
|
-
}
|
491
|
-
}
|
492
|
-
if (Qnil != (v = rb_hash_lookup(ropts, sec_prec_sym))) {
|
493
|
-
int n;
|
494
|
-
|
495
|
-
if (rb_cFixnum != rb_obj_class(v)) {
|
496
|
-
rb_raise(rb_eArgError, ":second_precision must be a Fixnum.");
|
497
|
-
}
|
498
|
-
n = NUM2INT(v);
|
499
|
-
if (0 > n) {
|
500
|
-
n = 0;
|
501
|
-
} else if (9 < n) {
|
502
|
-
n = 9;
|
503
|
-
}
|
504
|
-
copts->sec_prec = n;
|
505
|
-
}
|
506
|
-
if (Qnil != (v = rb_hash_lookup(ropts, mode_sym))) {
|
507
|
-
if (object_sym == v) {
|
508
|
-
copts->mode = ObjectMode;
|
509
|
-
} else if (strict_sym == v) {
|
510
|
-
copts->mode = StrictMode;
|
511
|
-
} else if (compat_sym == v) {
|
512
|
-
copts->mode = CompatMode;
|
513
|
-
} else if (null_sym == v) {
|
514
|
-
copts->mode = NullMode;
|
515
|
-
} else {
|
516
|
-
rb_raise(rb_eArgError, ":mode must be :object, :strict, :compat, or :null.");
|
517
|
-
}
|
518
|
-
}
|
519
|
-
if (Qnil != (v = rb_hash_lookup(ropts, time_format_sym))) {
|
520
|
-
if (unix_sym == v) {
|
521
|
-
copts->time_format = UnixTime;
|
522
|
-
} else if (unix_zone_sym == v) {
|
523
|
-
copts->time_format = UnixZTime;
|
524
|
-
} else if (xmlschema_sym == v) {
|
525
|
-
copts->time_format = XmlTime;
|
526
|
-
} else if (ruby_sym == v) {
|
527
|
-
copts->time_format = RubyTime;
|
528
|
-
} else {
|
529
|
-
rb_raise(rb_eArgError, ":time_format must be :unix, :unix_zone, :xmlschema, or :ruby.");
|
530
|
-
}
|
531
|
-
}
|
532
|
-
|
533
|
-
if (Qnil != (v = rb_hash_lookup(ropts, escape_mode_sym))) {
|
534
|
-
if (newline_sym == v) {
|
535
|
-
copts->escape_mode = NLEsc;
|
536
|
-
} else if (json_sym == v) {
|
537
|
-
copts->escape_mode = JSONEsc;
|
538
|
-
} else if (xss_safe_sym == v) {
|
539
|
-
copts->escape_mode = XSSEsc;
|
540
|
-
} else if (ascii_sym == v) {
|
541
|
-
copts->escape_mode = ASCIIEsc;
|
542
|
-
} else {
|
543
|
-
rb_raise(rb_eArgError, ":encoding must be :newline, :json, :xss_safe, or :ascii.");
|
496
|
+
if (Qtrue == rb_funcall(ropts, has_key_id, 1, space_sym)) {
|
497
|
+
if (Qnil == (v = rb_hash_lookup(ropts, space_sym))) {
|
498
|
+
copts->dump_opts.after_size = 0;
|
499
|
+
*copts->dump_opts.after_sep = '\0';
|
500
|
+
} else {
|
501
|
+
rb_check_type(v, T_STRING);
|
502
|
+
if (sizeof(copts->dump_opts.after_sep) <= (len = RSTRING_LEN(v))) {
|
503
|
+
rb_raise(rb_eArgError, "space string is limited to %lu characters.", sizeof(copts->dump_opts.after_sep));
|
544
504
|
}
|
505
|
+
strcpy(copts->dump_opts.after_sep, StringValuePtr(v));
|
506
|
+
copts->dump_opts.after_size = (uint8_t)len;
|
545
507
|
}
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
rb_raise(rb_eArgError, ":bigdecimal_load must be :bigdecimal, :float, or :auto.");
|
508
|
+
}
|
509
|
+
if (Qtrue == rb_funcall(ropts, has_key_id, 1, space_before_sym)) {
|
510
|
+
if (Qnil == (v = rb_hash_lookup(ropts, space_before_sym))) {
|
511
|
+
copts->dump_opts.before_size = 0;
|
512
|
+
*copts->dump_opts.before_sep = '\0';
|
513
|
+
} else {
|
514
|
+
rb_check_type(v, T_STRING);
|
515
|
+
if (sizeof(copts->dump_opts.before_sep) <= (len = RSTRING_LEN(v))) {
|
516
|
+
rb_raise(rb_eArgError, "sapce_before string is limited to %lu characters.", sizeof(copts->dump_opts.before_sep));
|
556
517
|
}
|
518
|
+
strcpy(copts->dump_opts.before_sep, StringValuePtr(v));
|
519
|
+
copts->dump_opts.before_size = (uint8_t)len;
|
557
520
|
}
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
copts->
|
567
|
-
} else if (T_STRING == rb_type(v)) {
|
568
|
-
size_t len = RSTRING_LEN(v);
|
569
|
-
const char *str = StringValuePtr(v);
|
570
|
-
|
571
|
-
if (len != copts->create_id_len ||
|
572
|
-
0 != strcmp(copts->create_id, str)) {
|
573
|
-
copts->create_id = ALLOC_N(char, len + 1);
|
574
|
-
strcpy((char*)copts->create_id, str);
|
575
|
-
copts->create_id_len = len;
|
576
|
-
}
|
577
|
-
} else {
|
578
|
-
rb_raise(rb_eArgError, ":create_id must be string.");
|
521
|
+
}
|
522
|
+
if (Qtrue == rb_funcall(ropts, has_key_id, 1, object_nl_sym)) {
|
523
|
+
if (Qnil == (v = rb_hash_lookup(ropts, object_nl_sym))) {
|
524
|
+
copts->dump_opts.hash_size = 0;
|
525
|
+
*copts->dump_opts.hash_nl = '\0';
|
526
|
+
} else {
|
527
|
+
rb_check_type(v, T_STRING);
|
528
|
+
if (sizeof(copts->dump_opts.hash_nl) <= (len = RSTRING_LEN(v))) {
|
529
|
+
rb_raise(rb_eArgError, "object_nl string is limited to %lu characters.", sizeof(copts->dump_opts.hash_nl));
|
579
530
|
}
|
531
|
+
strcpy(copts->dump_opts.hash_nl, StringValuePtr(v));
|
532
|
+
copts->dump_opts.hash_size = (uint8_t)len;
|
580
533
|
}
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
534
|
+
}
|
535
|
+
if (Qtrue == rb_funcall(ropts, has_key_id, 1, array_nl_sym)) {
|
536
|
+
if (Qnil == (v = rb_hash_lookup(ropts, array_nl_sym))) {
|
537
|
+
copts->dump_opts.array_size = 0;
|
538
|
+
*copts->dump_opts.array_nl = '\0';
|
539
|
+
} else {
|
540
|
+
rb_check_type(v, T_STRING);
|
541
|
+
if (sizeof(copts->dump_opts.array_nl) <= (len = RSTRING_LEN(v))) {
|
542
|
+
rb_raise(rb_eArgError, "array_nl string is limited to %lu characters.", sizeof(copts->dump_opts.array_nl));
|
590
543
|
}
|
591
|
-
|
592
|
-
|
593
|
-
v = rb_hash_lookup(ropts, ascii_only_sym);
|
594
|
-
if (Qtrue == v) {
|
595
|
-
copts->escape_mode = ASCIIEsc;
|
596
|
-
} else if (Qfalse == v) {
|
597
|
-
copts->escape_mode = JSONEsc;
|
544
|
+
strcpy(copts->dump_opts.array_nl, StringValuePtr(v));
|
545
|
+
copts->dump_opts.array_size = (uint8_t)len;
|
598
546
|
}
|
599
547
|
}
|
548
|
+
copts->dump_opts.use = (0 < copts->dump_opts.indent_size ||
|
549
|
+
0 < copts->dump_opts.after_size ||
|
550
|
+
0 < copts->dump_opts.before_size ||
|
551
|
+
0 < copts->dump_opts.hash_size ||
|
552
|
+
0 < copts->dump_opts.array_size);
|
553
|
+
// This is here only for backwards compatibility with the original Oj.
|
554
|
+
v = rb_hash_lookup(ropts, ascii_only_sym);
|
555
|
+
if (Qtrue == v) {
|
556
|
+
copts->escape_mode = ASCIIEsc;
|
557
|
+
} else if (Qfalse == v) {
|
558
|
+
copts->escape_mode = JSONEsc;
|
559
|
+
}
|
600
560
|
}
|
601
561
|
|
602
562
|
/* Document-method: strict_load
|
@@ -1665,53 +1625,57 @@ mimic_generate_core(int argc, VALUE *argv, Options copts) {
|
|
1665
1625
|
out.end = buf + sizeof(buf) - 10;
|
1666
1626
|
out.allocated = 0;
|
1667
1627
|
if (2 == argc && Qnil != argv[1]) {
|
1668
|
-
|
1669
|
-
VALUE
|
1670
|
-
|
1628
|
+
VALUE ropts = argv[1];
|
1629
|
+
VALUE v;
|
1630
|
+
size_t len;
|
1671
1631
|
|
1672
|
-
memset(&dump_opts, 0, sizeof(dump_opts)); // may not be needed
|
1673
1632
|
if (T_HASH != rb_type(ropts)) {
|
1674
1633
|
rb_raise(rb_eArgError, "options must be a hash.");
|
1675
1634
|
}
|
1676
|
-
if (Qnil != (v = rb_hash_lookup(ropts, indent_sym))) {
|
1635
|
+
if (Qnil != (v = rb_hash_lookup(ropts, indent_sym))) { // TBD fixnum also ok
|
1677
1636
|
rb_check_type(v, T_STRING);
|
1678
|
-
if (
|
1679
|
-
copts->dump_opts
|
1637
|
+
if (sizeof(copts->dump_opts.indent_str) <= (len = RSTRING_LEN(v))) {
|
1638
|
+
rb_raise(rb_eArgError, "indent string is limited to %lu characters.", sizeof(copts->dump_opts.indent_str));
|
1680
1639
|
}
|
1681
|
-
copts->dump_opts
|
1682
|
-
copts->dump_opts
|
1640
|
+
strcpy(copts->dump_opts.indent_str, StringValuePtr(v));
|
1641
|
+
copts->dump_opts.indent_size = (uint8_t)len;
|
1642
|
+
copts->dump_opts.use = true;
|
1683
1643
|
}
|
1684
1644
|
if (Qnil != (v = rb_hash_lookup(ropts, space_sym))) {
|
1685
1645
|
rb_check_type(v, T_STRING);
|
1686
|
-
if (
|
1687
|
-
copts->dump_opts
|
1646
|
+
if (sizeof(copts->dump_opts.after_sep) <= (len = RSTRING_LEN(v))) {
|
1647
|
+
rb_raise(rb_eArgError, "space string is limited to %lu characters.", sizeof(copts->dump_opts.after_sep));
|
1688
1648
|
}
|
1689
|
-
copts->dump_opts
|
1690
|
-
copts->dump_opts
|
1649
|
+
strcpy(copts->dump_opts.after_sep, StringValuePtr(v));
|
1650
|
+
copts->dump_opts.after_size = (uint8_t)len;
|
1651
|
+
copts->dump_opts.use = true;
|
1691
1652
|
}
|
1692
1653
|
if (Qnil != (v = rb_hash_lookup(ropts, space_before_sym))) {
|
1693
1654
|
rb_check_type(v, T_STRING);
|
1694
|
-
if (
|
1695
|
-
copts->dump_opts
|
1655
|
+
if (sizeof(copts->dump_opts.before_sep) <= (len = RSTRING_LEN(v))) {
|
1656
|
+
rb_raise(rb_eArgError, "space_before string is limited to %lu characters.", sizeof(copts->dump_opts.before_sep));
|
1696
1657
|
}
|
1697
|
-
copts->dump_opts
|
1698
|
-
copts->dump_opts
|
1658
|
+
strcpy(copts->dump_opts.before_sep, StringValuePtr(v));
|
1659
|
+
copts->dump_opts.before_size = (uint8_t)len;
|
1660
|
+
copts->dump_opts.use = true;
|
1699
1661
|
}
|
1700
1662
|
if (Qnil != (v = rb_hash_lookup(ropts, object_nl_sym))) {
|
1701
1663
|
rb_check_type(v, T_STRING);
|
1702
|
-
if (
|
1703
|
-
copts->dump_opts
|
1664
|
+
if (sizeof(copts->dump_opts.hash_nl) <= (len = RSTRING_LEN(v))) {
|
1665
|
+
rb_raise(rb_eArgError, "object_nl string is limited to %lu characters.", sizeof(copts->dump_opts.hash_nl));
|
1704
1666
|
}
|
1705
|
-
copts->dump_opts
|
1706
|
-
copts->dump_opts
|
1667
|
+
strcpy(copts->dump_opts.hash_nl, StringValuePtr(v));
|
1668
|
+
copts->dump_opts.hash_size = (uint8_t)len;
|
1669
|
+
copts->dump_opts.use = true;
|
1707
1670
|
}
|
1708
1671
|
if (Qnil != (v = rb_hash_lookup(ropts, array_nl_sym))) {
|
1709
1672
|
rb_check_type(v, T_STRING);
|
1710
|
-
if (
|
1711
|
-
copts->dump_opts
|
1673
|
+
if (sizeof(copts->dump_opts.array_nl) <= (len = RSTRING_LEN(v))) {
|
1674
|
+
rb_raise(rb_eArgError, "array_nl string is limited to %lu characters.", sizeof(copts->dump_opts.array_nl));
|
1712
1675
|
}
|
1713
|
-
copts->dump_opts
|
1714
|
-
copts->dump_opts
|
1676
|
+
strcpy(copts->dump_opts.array_nl, StringValuePtr(v));
|
1677
|
+
copts->dump_opts.array_size = (uint8_t)len;
|
1678
|
+
copts->dump_opts.use = true;
|
1715
1679
|
}
|
1716
1680
|
// :allow_nan is not supported as Oj always allows_nan
|
1717
1681
|
// :max_nesting is always set to 100
|
@@ -1738,19 +1702,18 @@ mimic_generate(int argc, VALUE *argv, VALUE self) {
|
|
1738
1702
|
static VALUE
|
1739
1703
|
mimic_pretty_generate(int argc, VALUE *argv, VALUE self) {
|
1740
1704
|
struct _Options copts = oj_default_options;
|
1741
|
-
|
1742
|
-
|
1743
|
-
dump_opts.
|
1744
|
-
dump_opts.
|
1745
|
-
dump_opts.
|
1746
|
-
dump_opts.
|
1747
|
-
dump_opts.
|
1748
|
-
dump_opts.
|
1749
|
-
dump_opts.
|
1750
|
-
dump_opts.
|
1751
|
-
dump_opts.
|
1752
|
-
dump_opts.
|
1753
|
-
copts.dump_opts = &dump_opts;
|
1705
|
+
|
1706
|
+
strcpy(copts.dump_opts.indent_str, " ");
|
1707
|
+
copts.dump_opts.indent_size = (uint8_t)strlen(copts.dump_opts.indent_str);
|
1708
|
+
strcpy(copts.dump_opts.before_sep, " ");
|
1709
|
+
copts.dump_opts.before_size = (uint8_t)strlen(copts.dump_opts.before_sep);
|
1710
|
+
strcpy(copts.dump_opts.after_sep, " ");
|
1711
|
+
copts.dump_opts.after_size = (uint8_t)strlen(copts.dump_opts.after_sep);
|
1712
|
+
strcpy(copts.dump_opts.hash_nl, "\n");
|
1713
|
+
copts.dump_opts.hash_size = (uint8_t)strlen(copts.dump_opts.hash_nl);
|
1714
|
+
strcpy(copts.dump_opts.array_nl, "\n");
|
1715
|
+
copts.dump_opts.array_size = (uint8_t)strlen(copts.dump_opts.array_nl);
|
1716
|
+
copts.dump_opts.use = true;
|
1754
1717
|
|
1755
1718
|
return mimic_generate_core(argc, argv, &copts);
|
1756
1719
|
}
|
@@ -1833,26 +1796,38 @@ mimic_create_id(VALUE self, VALUE id) {
|
|
1833
1796
|
}
|
1834
1797
|
|
1835
1798
|
static struct _Options mimic_object_to_json_options = {
|
1836
|
-
0,
|
1837
|
-
No,
|
1838
|
-
No,
|
1839
|
-
No,
|
1840
|
-
JSONEsc,
|
1841
|
-
CompatMode,
|
1842
|
-
No,
|
1843
|
-
RubyTime,
|
1844
|
-
No,
|
1845
|
-
FloatDec,
|
1846
|
-
No,
|
1847
|
-
Yes,
|
1848
|
-
Yes,
|
1849
|
-
Yes,
|
1850
|
-
json_class,
|
1851
|
-
10,
|
1852
|
-
9,
|
1853
|
-
|
1854
|
-
|
1855
|
-
|
1799
|
+
0, // indent
|
1800
|
+
No, // circular
|
1801
|
+
No, // auto_define
|
1802
|
+
No, // sym_key
|
1803
|
+
JSONEsc, // escape_mode
|
1804
|
+
CompatMode, // mode
|
1805
|
+
No, // class_cache
|
1806
|
+
RubyTime, // time_format
|
1807
|
+
No, // bigdec_as_num
|
1808
|
+
FloatDec, // bigdec_load
|
1809
|
+
No, // to_json
|
1810
|
+
Yes, // nilnil
|
1811
|
+
Yes, // allow_gc
|
1812
|
+
Yes, // quirks_mode
|
1813
|
+
json_class, // create_id
|
1814
|
+
10, // create_id_len
|
1815
|
+
9, // sec_prec
|
1816
|
+
15, // float_prec
|
1817
|
+
"%0.15g", // float_fmt
|
1818
|
+
{ // dump_opts
|
1819
|
+
false, //use
|
1820
|
+
"", // indent
|
1821
|
+
"", // before_sep
|
1822
|
+
"", // after_sep
|
1823
|
+
"", // hash_nl
|
1824
|
+
"", // array_nl
|
1825
|
+
0, // indent_size
|
1826
|
+
0, // before_size
|
1827
|
+
0, // after_size
|
1828
|
+
0, // hash_size
|
1829
|
+
0, // array_size
|
1830
|
+
}
|
1856
1831
|
};
|
1857
1832
|
|
1858
1833
|
static VALUE
|
@@ -1961,11 +1936,7 @@ define_mimic_json(int argc, VALUE *argv, VALUE self) {
|
|
1961
1936
|
|
1962
1937
|
rb_gv_set("$VERBOSE", dummy);
|
1963
1938
|
|
1964
|
-
array_nl_sym = ID2SYM(rb_intern("array_nl")); rb_gc_register_address(&array_nl_sym);
|
1965
1939
|
create_additions_sym = ID2SYM(rb_intern("create_additions")); rb_gc_register_address(&create_additions_sym);
|
1966
|
-
object_nl_sym = ID2SYM(rb_intern("object_nl")); rb_gc_register_address(&object_nl_sym);
|
1967
|
-
space_before_sym = ID2SYM(rb_intern("space_before")); rb_gc_register_address(&space_before_sym);
|
1968
|
-
space_sym = ID2SYM(rb_intern("space")); rb_gc_register_address(&space_sym);
|
1969
1940
|
symbolize_names_sym = ID2SYM(rb_intern("symbolize_names")); rb_gc_register_address(&symbolize_names_sym);
|
1970
1941
|
|
1971
1942
|
if (rb_const_defined_at(mimic, rb_intern("ParserError"))) {
|
@@ -2121,6 +2092,7 @@ void Init_oj() {
|
|
2121
2092
|
oj_utc_offset_id = rb_intern("utc_offset");
|
2122
2093
|
oj_utcq_id = rb_intern("utc?");
|
2123
2094
|
oj_write_id = rb_intern("write");
|
2095
|
+
has_key_id = rb_intern("has_key?");
|
2124
2096
|
|
2125
2097
|
rb_require("oj/bag");
|
2126
2098
|
rb_require("oj/error");
|
@@ -2141,6 +2113,7 @@ void Init_oj() {
|
|
2141
2113
|
ascii_sym = ID2SYM(rb_intern("ascii")); rb_gc_register_address(&ascii_sym);
|
2142
2114
|
auto_define_sym = ID2SYM(rb_intern("auto_define")); rb_gc_register_address(&auto_define_sym);
|
2143
2115
|
auto_sym = ID2SYM(rb_intern("auto")); rb_gc_register_address(&auto_sym);
|
2116
|
+
array_nl_sym = ID2SYM(rb_intern("array_nl")); rb_gc_register_address(&array_nl_sym);
|
2144
2117
|
bigdecimal_as_decimal_sym = ID2SYM(rb_intern("bigdecimal_as_decimal"));rb_gc_register_address(&bigdecimal_as_decimal_sym);
|
2145
2118
|
bigdecimal_load_sym = ID2SYM(rb_intern("bigdecimal_load"));rb_gc_register_address(&bigdecimal_load_sym);
|
2146
2119
|
bigdecimal_sym = ID2SYM(rb_intern("bigdecimal")); rb_gc_register_address(&bigdecimal_sym);
|
@@ -2157,10 +2130,13 @@ void Init_oj() {
|
|
2157
2130
|
newline_sym = ID2SYM(rb_intern("newline")); rb_gc_register_address(&newline_sym);
|
2158
2131
|
nilnil_sym = ID2SYM(rb_intern("nilnil")); rb_gc_register_address(&nilnil_sym);
|
2159
2132
|
null_sym = ID2SYM(rb_intern("null")); rb_gc_register_address(&null_sym);
|
2133
|
+
object_nl_sym = ID2SYM(rb_intern("object_nl")); rb_gc_register_address(&object_nl_sym);
|
2160
2134
|
object_sym = ID2SYM(rb_intern("object")); rb_gc_register_address(&object_sym);
|
2161
2135
|
quirks_mode_sym = ID2SYM(rb_intern("quirks_mode")); rb_gc_register_address(&quirks_mode_sym);
|
2162
2136
|
ruby_sym = ID2SYM(rb_intern("ruby")); rb_gc_register_address(&ruby_sym);
|
2163
2137
|
sec_prec_sym = ID2SYM(rb_intern("second_precision"));rb_gc_register_address(&sec_prec_sym);
|
2138
|
+
space_before_sym = ID2SYM(rb_intern("space_before"));rb_gc_register_address(&space_before_sym);
|
2139
|
+
space_sym = ID2SYM(rb_intern("space")); rb_gc_register_address(&space_sym);
|
2164
2140
|
strict_sym = ID2SYM(rb_intern("strict")); rb_gc_register_address(&strict_sym);
|
2165
2141
|
symbol_keys_sym = ID2SYM(rb_intern("symbol_keys")); rb_gc_register_address(&symbol_keys_sym);
|
2166
2142
|
time_format_sym = ID2SYM(rb_intern("time_format")); rb_gc_register_address(&time_format_sym);
|