json 1.1.0-mswin32 → 1.1.1-mswin32
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of json might be problematic. Click here for more details.
- data/CHANGES +18 -0
- data/Rakefile +5 -5
- data/VERSION +1 -1
- data/benchmarks/benchmark_generator.rb +5 -1
- data/benchmarks/benchmark_parser.rb +5 -1
- data/bin/edit_json.rb +11 -11
- data/ext/json/ext/generator.so +0 -0
- data/ext/json/ext/generator/extconf.rb +2 -2
- data/ext/json/ext/generator/generator.c +185 -50
- data/ext/json/ext/parser.so +0 -0
- data/ext/json/ext/parser/extconf.rb +2 -2
- data/ext/json/ext/parser/parser.c +246 -117
- data/ext/json/ext/parser/parser.rl +54 -6
- data/lib/json.rb +23 -0
- data/lib/json/add/core.rb +119 -0
- data/lib/json/add/rails.rb +52 -0
- data/lib/json/common.rb +174 -23
- data/lib/json/editor.rb +12 -14
- data/lib/json/pure/generator.rb +83 -10
- data/lib/json/pure/parser.rb +15 -1
- data/lib/json/version.rb +1 -1
- data/tests/fixtures/fail18.json +1 -1
- data/tests/test_json.rb +51 -12
- data/tests/test_json_addition.rb +34 -3
- data/tests/test_json_fixtures.rb +2 -2
- data/tests/test_json_generate.rb +21 -2
- data/tests/test_json_unicode.rb +4 -1
- data/tools/fuzz.rb +2 -1
- metadata +5 -2
@@ -8,8 +8,12 @@
|
|
8
8
|
#define EVIL 0x666
|
9
9
|
|
10
10
|
static VALUE mJSON, mExt, cParser, eParserError, eNestingError;
|
11
|
+
static VALUE CNaN, CInfinity, CMinusInfinity;
|
11
12
|
|
12
|
-
static ID i_json_creatable_p, i_json_create, i_create_id, i_chr, i_max_nesting
|
13
|
+
static ID i_json_creatable_p, i_json_create, i_create_id, i_chr, i_max_nesting,
|
14
|
+
i_allow_nan;
|
15
|
+
|
16
|
+
#define MinusInfinity "-Infinity"
|
13
17
|
|
14
18
|
typedef struct JSON_ParserStruct {
|
15
19
|
VALUE Vsource;
|
@@ -19,6 +23,7 @@ typedef struct JSON_ParserStruct {
|
|
19
23
|
VALUE create_id;
|
20
24
|
int max_nesting;
|
21
25
|
int current_nesting;
|
26
|
+
int allow_nan;
|
22
27
|
} JSON_Parser;
|
23
28
|
|
24
29
|
static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *result);
|
@@ -47,7 +52,10 @@ static char *JSON_parse_float(JSON_Parser *json, char *p, char *pe, VALUE *resul
|
|
47
52
|
Vnull = 'null';
|
48
53
|
Vfalse = 'false';
|
49
54
|
Vtrue = 'true';
|
50
|
-
|
55
|
+
VNaN = 'NaN';
|
56
|
+
VInfinity = 'Infinity';
|
57
|
+
VMinusInfinity = '-Infinity';
|
58
|
+
begin_value = [nft"\-[{NI] | digit;
|
51
59
|
begin_object = '{';
|
52
60
|
end_object = '}';
|
53
61
|
begin_array = '[';
|
@@ -133,6 +141,20 @@ static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *resu
|
|
133
141
|
action parse_true {
|
134
142
|
*result = Qtrue;
|
135
143
|
}
|
144
|
+
action parse_nan {
|
145
|
+
if (json->allow_nan) {
|
146
|
+
*result = CNaN;
|
147
|
+
} else {
|
148
|
+
rb_raise(eParserError, "unexpected token at '%s'", p - 2);
|
149
|
+
}
|
150
|
+
}
|
151
|
+
action parse_infinity {
|
152
|
+
if (json->allow_nan) {
|
153
|
+
*result = CInfinity;
|
154
|
+
} else {
|
155
|
+
rb_raise(eParserError, "unexpected token at '%s'", p - 8);
|
156
|
+
}
|
157
|
+
}
|
136
158
|
action parse_string {
|
137
159
|
char *np = JSON_parse_string(json, fpc, pe, result);
|
138
160
|
if (np == NULL) fbreak; else fexec np;
|
@@ -140,6 +162,15 @@ static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *resu
|
|
140
162
|
|
141
163
|
action parse_number {
|
142
164
|
char *np;
|
165
|
+
if(pe > fpc + 9 && !strncmp(MinusInfinity, fpc, 9)) {
|
166
|
+
if (json->allow_nan) {
|
167
|
+
*result = CMinusInfinity;
|
168
|
+
fexec p + 10;
|
169
|
+
fbreak;
|
170
|
+
} else {
|
171
|
+
rb_raise(eParserError, "unexpected token at '%s'", p);
|
172
|
+
}
|
173
|
+
}
|
143
174
|
np = JSON_parse_float(json, fpc, pe, result);
|
144
175
|
if (np != NULL) fexec np;
|
145
176
|
np = JSON_parse_integer(json, fpc, pe, result);
|
@@ -169,6 +200,8 @@ main := (
|
|
169
200
|
Vnull @parse_null |
|
170
201
|
Vfalse @parse_false |
|
171
202
|
Vtrue @parse_true |
|
203
|
+
VNaN @parse_nan |
|
204
|
+
VInfinity @parse_infinity |
|
172
205
|
begin_number >parse_number |
|
173
206
|
begin_string >parse_string |
|
174
207
|
begin_array >parse_array |
|
@@ -435,7 +468,11 @@ static char *JSON_parse_string(JSON_Parser *json, char *p, char *pe, VALUE *resu
|
|
435
468
|
*
|
436
469
|
* _opts_ can have the following keys:
|
437
470
|
* * *max_nesting*: The maximum depth of nesting allowed in the parsed data
|
438
|
-
* structures. Disable depth checking with :max_nesting => false
|
471
|
+
* structures. Disable depth checking with :max_nesting => false|nil|0, it
|
472
|
+
* defaults to 19.
|
473
|
+
* * *allow_nan*: If set to true, allow NaN, Infinity and -Infinity in
|
474
|
+
* defiance of RFC 4627 to be parsed by the Parser. This option defaults to
|
475
|
+
* false.
|
439
476
|
*/
|
440
477
|
static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
|
441
478
|
{
|
@@ -451,14 +488,15 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
|
|
451
488
|
rb_raise(eParserError, "A JSON text must at least contain two octets!");
|
452
489
|
}
|
453
490
|
json->max_nesting = 19;
|
491
|
+
json->allow_nan = 0;
|
454
492
|
if (!NIL_P(opts)) {
|
455
493
|
opts = rb_convert_type(opts, T_HASH, "Hash", "to_hash");
|
456
494
|
if (NIL_P(opts)) {
|
457
495
|
rb_raise(rb_eArgError, "opts needs to be like a hash");
|
458
496
|
} else {
|
459
|
-
VALUE
|
460
|
-
if (st_lookup(RHASH(opts)->tbl,
|
461
|
-
VALUE max_nesting = rb_hash_aref(opts,
|
497
|
+
VALUE tmp = ID2SYM(i_max_nesting);
|
498
|
+
if (st_lookup(RHASH(opts)->tbl, tmp, 0)) {
|
499
|
+
VALUE max_nesting = rb_hash_aref(opts, tmp);
|
462
500
|
if (RTEST(max_nesting)) {
|
463
501
|
Check_Type(max_nesting, T_FIXNUM);
|
464
502
|
json->max_nesting = FIX2INT(max_nesting);
|
@@ -466,6 +504,11 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
|
|
466
504
|
json->max_nesting = 0;
|
467
505
|
}
|
468
506
|
}
|
507
|
+
tmp = ID2SYM(i_allow_nan);
|
508
|
+
if (st_lookup(RHASH(opts)->tbl, tmp, 0)) {
|
509
|
+
VALUE allow_nan = rb_hash_aref(opts, tmp);
|
510
|
+
if (RTEST(allow_nan)) json->allow_nan = 1;
|
511
|
+
}
|
469
512
|
}
|
470
513
|
}
|
471
514
|
json->current_nesting = 0;
|
@@ -561,9 +604,14 @@ void Init_parser()
|
|
561
604
|
rb_define_method(cParser, "parse", cParser_parse, 0);
|
562
605
|
rb_define_method(cParser, "source", cParser_source, 0);
|
563
606
|
|
607
|
+
CNaN = rb_const_get(mJSON, rb_intern("NaN"));
|
608
|
+
CInfinity = rb_const_get(mJSON, rb_intern("Infinity"));
|
609
|
+
CMinusInfinity = rb_const_get(mJSON, rb_intern("MinusInfinity"));
|
610
|
+
|
564
611
|
i_json_creatable_p = rb_intern("json_creatable?");
|
565
612
|
i_json_create = rb_intern("json_create");
|
566
613
|
i_create_id = rb_intern("create_id");
|
567
614
|
i_chr = rb_intern("chr");
|
568
615
|
i_max_nesting = rb_intern("max_nesting");
|
616
|
+
i_allow_nan = rb_intern("allow_nan");
|
569
617
|
}
|
data/lib/json.rb
CHANGED
@@ -47,6 +47,27 @@ require 'json/common'
|
|
47
47
|
#
|
48
48
|
# * http://json.rubyforge.org
|
49
49
|
#
|
50
|
+
# == Usage
|
51
|
+
#
|
52
|
+
# To use JSON you can
|
53
|
+
# require 'json'
|
54
|
+
# to load the installed variant (either the extension 'json' or the pure
|
55
|
+
# variant 'json_pure'). If you have installed the extension variant, you can
|
56
|
+
# pick either the extension variant or the pure variant by typing
|
57
|
+
# require 'json/ext'
|
58
|
+
# or
|
59
|
+
# require 'json/pure'
|
60
|
+
#
|
61
|
+
# You can choose to load a set of common additions to ruby core's objects if
|
62
|
+
# you
|
63
|
+
# require 'json/add/core'
|
64
|
+
#
|
65
|
+
# To get the best compatibility to rails' JSON implementation, you can
|
66
|
+
# require 'json/add/rails'
|
67
|
+
#
|
68
|
+
# Both of the additions attempt to require 'json' (like above) first, if it has
|
69
|
+
# not been required yet.
|
70
|
+
#
|
50
71
|
# == Speed Comparisons
|
51
72
|
#
|
52
73
|
# I have created some benchmark results (see the benchmarks subdir of the
|
@@ -207,4 +228,6 @@ module JSON
|
|
207
228
|
require 'json/pure'
|
208
229
|
end
|
209
230
|
end
|
231
|
+
|
232
|
+
JSON_LOADED = true
|
210
233
|
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
# This file contains implementations of ruby core's custom objects for
|
2
|
+
# serialisation/deserialisation.
|
3
|
+
|
4
|
+
unless Object.const_defined?(:JSON) and ::JSON.const_defined?(:JSON_LOADED) and
|
5
|
+
::JSON::JSON_LOADED
|
6
|
+
require 'json'
|
7
|
+
end
|
8
|
+
|
9
|
+
class Time
|
10
|
+
def self.json_create(object)
|
11
|
+
at(*object.values_at('s', 'u'))
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_json(*args)
|
15
|
+
{
|
16
|
+
'json_class' => self.class.name,
|
17
|
+
's' => tv_sec,
|
18
|
+
'u' => tv_usec,
|
19
|
+
}.to_json(*args)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class Date
|
24
|
+
def self.json_create(object)
|
25
|
+
civil(*object.values_at('y', 'm', 'd', 'sg'))
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_json(*args)
|
29
|
+
{
|
30
|
+
'json_class' => self.class.name,
|
31
|
+
'y' => year,
|
32
|
+
'm' => month,
|
33
|
+
'd' => day,
|
34
|
+
'sg' => sg,
|
35
|
+
}.to_json(*args)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
class DateTime
|
40
|
+
def self.json_create(object)
|
41
|
+
args = object.values_at('y', 'm', 'd', 'H', 'M', 'S')
|
42
|
+
of_a, of_b = object['of'].split('/')
|
43
|
+
args << Rational(of_a.to_i, of_b.to_i)
|
44
|
+
args << object['sg']
|
45
|
+
civil(*args)
|
46
|
+
end
|
47
|
+
|
48
|
+
def to_json(*args)
|
49
|
+
{
|
50
|
+
'json_class' => self.class.name,
|
51
|
+
'y' => year,
|
52
|
+
'm' => month,
|
53
|
+
'd' => day,
|
54
|
+
'H' => hour,
|
55
|
+
'M' => min,
|
56
|
+
'S' => sec,
|
57
|
+
'of' => offset,
|
58
|
+
'sg' => sg,
|
59
|
+
}.to_json(*args)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
class Range
|
64
|
+
def self.json_create(object)
|
65
|
+
new(*object['a'])
|
66
|
+
end
|
67
|
+
|
68
|
+
def to_json(*args)
|
69
|
+
{
|
70
|
+
'json_class' => self.class.name,
|
71
|
+
'a' => [ first, last, exclude_end? ]
|
72
|
+
}.to_json(*args)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
class Struct
|
77
|
+
def self.json_create(object)
|
78
|
+
new(*object['v'])
|
79
|
+
end
|
80
|
+
|
81
|
+
def to_json(*args)
|
82
|
+
klass = self.class.name
|
83
|
+
klass.empty? and raise JSON::JSONError, "Only named structs are supported!"
|
84
|
+
{
|
85
|
+
'json_class' => klass,
|
86
|
+
'v' => values,
|
87
|
+
}.to_json(*args)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
class Exception
|
92
|
+
def self.json_create(object)
|
93
|
+
result = new(object['m'])
|
94
|
+
result.set_backtrace object['b']
|
95
|
+
result
|
96
|
+
end
|
97
|
+
|
98
|
+
def to_json(*args)
|
99
|
+
{
|
100
|
+
'json_class' => self.class.name,
|
101
|
+
'm' => message,
|
102
|
+
'b' => backtrace,
|
103
|
+
}.to_json(*args)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
class Regexp
|
108
|
+
def self.json_create(object)
|
109
|
+
new(object['s'], object['o'])
|
110
|
+
end
|
111
|
+
|
112
|
+
def to_json(*)
|
113
|
+
{
|
114
|
+
'json_class' => self.class.name,
|
115
|
+
'o' => options,
|
116
|
+
's' => source,
|
117
|
+
}.to_json
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# This file contains implementations of rails custom objects for
|
2
|
+
# serialisation/deserialisation.
|
3
|
+
|
4
|
+
unless Object.const_defined?(:JSON) and ::JSON.const_defined?(:JSON_LOADED) and
|
5
|
+
::JSON::JSON_LOADED
|
6
|
+
require 'json'
|
7
|
+
end
|
8
|
+
|
9
|
+
class Object
|
10
|
+
def self.json_create(object)
|
11
|
+
obj = new
|
12
|
+
for key, value in object
|
13
|
+
next if key == 'json_class'
|
14
|
+
instance_variable_set "@#{key}", value
|
15
|
+
end
|
16
|
+
obj
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_json(*a)
|
20
|
+
result = {
|
21
|
+
'json_class' => self.class.name
|
22
|
+
}
|
23
|
+
instance_variables.inject(result) do |r, name|
|
24
|
+
r[name[1..-1]] = instance_variable_get name
|
25
|
+
r
|
26
|
+
end
|
27
|
+
result.to_json(*a)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
module Enumerable
|
32
|
+
def to_json(*a)
|
33
|
+
to_a.to_json(*a)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# class Regexp
|
38
|
+
# def to_json(*)
|
39
|
+
# inspect
|
40
|
+
# end
|
41
|
+
# end
|
42
|
+
#
|
43
|
+
# The above rails definition has some problems:
|
44
|
+
#
|
45
|
+
# 1. { 'foo' => /bar/ }.to_json # => "{foo: /bar/}"
|
46
|
+
# This isn't valid JSON, because the regular expression syntax is not
|
47
|
+
# defined in RFC 4627. (And unquoted strings are disallowed there, too.)
|
48
|
+
# Though it is valid Javascript.
|
49
|
+
#
|
50
|
+
# 2. { 'foo' => /bar/mix }.to_json # => "{foo: /bar/mix}"
|
51
|
+
# This isn't even valid Javascript.
|
52
|
+
|
data/lib/json/common.rb
CHANGED
@@ -2,14 +2,17 @@ require 'json/version'
|
|
2
2
|
|
3
3
|
module JSON
|
4
4
|
class << self
|
5
|
-
# If
|
6
|
-
# Ruby data structure. Otherwise generate a JSON text from the Ruby
|
7
|
-
# structure object and return it.
|
8
|
-
|
5
|
+
# If _object_ is string like parse the string and return the parsed result
|
6
|
+
# as a Ruby data structure. Otherwise generate a JSON text from the Ruby
|
7
|
+
# data structure object and return it.
|
8
|
+
#
|
9
|
+
# The _opts_ argument is passed through to generate/parse respectively, see
|
10
|
+
# generate and parse for their documentation.
|
11
|
+
def [](object, opts = {})
|
9
12
|
if object.respond_to? :to_str
|
10
|
-
JSON.parse(object.to_str)
|
13
|
+
JSON.parse(object.to_str, opts => {})
|
11
14
|
else
|
12
|
-
JSON.generate(object)
|
15
|
+
JSON.generate(object, opts => {})
|
13
16
|
end
|
14
17
|
end
|
15
18
|
|
@@ -71,6 +74,12 @@ module JSON
|
|
71
74
|
end
|
72
75
|
self.create_id = 'json_class'
|
73
76
|
|
77
|
+
NaN = (-1.0) ** 0.5
|
78
|
+
|
79
|
+
Infinity = 1.0/0
|
80
|
+
|
81
|
+
MinusInfinity = -Infinity
|
82
|
+
|
74
83
|
# The base exception for JSON errors.
|
75
84
|
class JSONError < StandardError; end
|
76
85
|
|
@@ -101,29 +110,79 @@ module JSON
|
|
101
110
|
# _opts_ can have the following
|
102
111
|
# keys:
|
103
112
|
# * *max_nesting*: The maximum depth of nesting allowed in the parsed data
|
104
|
-
# structures. Disable depth checking with :max_nesting => false
|
113
|
+
# structures. Disable depth checking with :max_nesting => false, it defaults
|
114
|
+
# to 19.
|
115
|
+
# * *allow_nan*: If set to true, allow NaN, Infinity and -Infinity in
|
116
|
+
# defiance of RFC 4627 to be parsed by the Parser. This option defaults
|
117
|
+
# to false.
|
105
118
|
def parse(source, opts = {})
|
106
119
|
JSON.parser.new(source, opts).parse
|
107
120
|
end
|
108
121
|
|
122
|
+
# Parse the JSON string _source_ into a Ruby data structure and return it.
|
123
|
+
# The bang version of the parse method, defaults to the more dangerous values
|
124
|
+
# for the _opts_ hash, so be sure only to parse trusted _source_ strings.
|
125
|
+
#
|
126
|
+
# _opts_ can have the following keys:
|
127
|
+
# * *max_nesting*: The maximum depth of nesting allowed in the parsed data
|
128
|
+
# structures. Enable depth checking with :max_nesting => anInteger. The parse!
|
129
|
+
# methods defaults to not doing max depth checking: This can be dangerous,
|
130
|
+
# if someone wants to fill up your stack.
|
131
|
+
# * *allow_nan*: If set to true, allow NaN, Infinity, and -Infinity in
|
132
|
+
# defiance of RFC 4627 to be parsed by the Parser. This option defaults
|
133
|
+
# to true.
|
134
|
+
def parse!(source, opts = {})
|
135
|
+
opts = {
|
136
|
+
:max_nesting => false,
|
137
|
+
:allow_nan => true
|
138
|
+
}.update(opts)
|
139
|
+
JSON.parser.new(source, opts).parse
|
140
|
+
end
|
141
|
+
|
109
142
|
# Unparse the Ruby data structure _obj_ into a single line JSON string and
|
110
|
-
# return it. _state_ is
|
111
|
-
#
|
143
|
+
# return it. _state_ is
|
144
|
+
# * a JSON::State object,
|
145
|
+
# * or a Hash like object (responding to to_hash),
|
146
|
+
# * an object convertible into a hash by a to_h method,
|
147
|
+
# that is used as or to configure a State object.
|
112
148
|
#
|
113
149
|
# It defaults to a state object, that creates the shortest possible JSON text
|
114
|
-
# in one line
|
115
|
-
#
|
116
|
-
#
|
117
|
-
#
|
118
|
-
|
150
|
+
# in one line, checks for circular data structures and doesn't allow NaN,
|
151
|
+
# Infinity, and -Infinity.
|
152
|
+
#
|
153
|
+
# A _state_ hash can have the following keys:
|
154
|
+
# * *indent*: a string used to indent levels (default: ''),
|
155
|
+
# * *space*: a string that is put after, a : or , delimiter (default: ''),
|
156
|
+
# * *space_before*: a string that is put before a : pair delimiter (default: ''),
|
157
|
+
# * *object_nl*: a string that is put at the end of a JSON object (default: ''),
|
158
|
+
# * *array_nl*: a string that is put at the end of a JSON array (default: ''),
|
159
|
+
# * *check_circular*: true if checking for circular data structures
|
160
|
+
# should be done (the default), false otherwise.
|
161
|
+
# * *allow_nan*: true if NaN, Infinity, and -Infinity should be
|
162
|
+
# generated, otherwise an exception is thrown, if these values are
|
163
|
+
# encountered. This options defaults to false.
|
164
|
+
#
|
165
|
+
# See also the fast_generate for the fastest creation method with the least
|
166
|
+
# amount of sanity checks, and the pretty_generate method for some
|
167
|
+
# defaults for a pretty output.
|
168
|
+
def generate(obj, state = nil)
|
169
|
+
if state
|
170
|
+
state = State.from_state(state)
|
171
|
+
else
|
172
|
+
state = State.new
|
173
|
+
end
|
119
174
|
obj.to_json(state)
|
120
175
|
end
|
121
176
|
|
177
|
+
# :stopdoc:
|
178
|
+
# I want to deprecate these later, so I'll first be silent about them, and later delete them.
|
122
179
|
alias unparse generate
|
123
180
|
module_function :unparse
|
181
|
+
# :startdoc:
|
124
182
|
|
125
183
|
# Unparse the Ruby data structure _obj_ into a single line JSON string and
|
126
|
-
# return it. This method disables the checks for circles in Ruby objects
|
184
|
+
# return it. This method disables the checks for circles in Ruby objects, and
|
185
|
+
# also generates NaN, Infinity, and, -Infinity float values.
|
127
186
|
#
|
128
187
|
# *WARNING*: Be careful not to pass any Ruby data structures with circles as
|
129
188
|
# _obj_ argument, because this will cause JSON to go into an infinite loop.
|
@@ -131,12 +190,18 @@ module JSON
|
|
131
190
|
obj.to_json(nil)
|
132
191
|
end
|
133
192
|
|
193
|
+
# :stopdoc:
|
194
|
+
# I want to deprecate these later, so I'll first be silent about them, and later delete them.
|
134
195
|
alias fast_unparse fast_generate
|
135
196
|
module_function :fast_unparse
|
197
|
+
# :startdoc:
|
136
198
|
|
137
199
|
# Unparse the Ruby data structure _obj_ into a JSON string and return it. The
|
138
200
|
# returned string is a prettier form of the string returned by #unparse.
|
139
|
-
|
201
|
+
#
|
202
|
+
# The _opts_ argument can be used to configure the generator, see the
|
203
|
+
# generate method for a more detailed explanation.
|
204
|
+
def pretty_generate(obj, opts = nil)
|
140
205
|
state = JSON.state.new(
|
141
206
|
:indent => ' ',
|
142
207
|
:space => ' ',
|
@@ -144,11 +209,94 @@ module JSON
|
|
144
209
|
:array_nl => "\n",
|
145
210
|
:check_circular => true
|
146
211
|
)
|
212
|
+
if opts
|
213
|
+
if opts.respond_to? :to_hash
|
214
|
+
opts = opts.to_hash
|
215
|
+
elsif opts.respond_to? :to_h
|
216
|
+
opts = opts.to_h
|
217
|
+
else
|
218
|
+
raise TypeError, "can't convert #{opts.class} into Hash"
|
219
|
+
end
|
220
|
+
state.configure(opts)
|
221
|
+
end
|
147
222
|
obj.to_json(state)
|
148
223
|
end
|
149
224
|
|
225
|
+
# :stopdoc:
|
226
|
+
# I want to deprecate these later, so I'll first be silent about them, and later delete them.
|
150
227
|
alias pretty_unparse pretty_generate
|
151
228
|
module_function :pretty_unparse
|
229
|
+
# :startdoc:
|
230
|
+
|
231
|
+
# Load a ruby data structure from a JSON _source_ and return it. A source can
|
232
|
+
# either be a string like object, an IO like object, or an object responding
|
233
|
+
# to the read method. If _proc_ was given, it will be called with any nested
|
234
|
+
# Ruby object as an argument recursively in depth first order.
|
235
|
+
#
|
236
|
+
# This method is part of the implementation of the load/dump interface of
|
237
|
+
# Marshal and YAML.
|
238
|
+
def load(source, proc = nil)
|
239
|
+
if source.respond_to? :to_str
|
240
|
+
source = source.to_str
|
241
|
+
elsif source.respond_to? :to_io
|
242
|
+
source = source.to_io.read
|
243
|
+
else
|
244
|
+
source = source.read
|
245
|
+
end
|
246
|
+
result = parse(source, :max_nesting => false, :allow_nan => true)
|
247
|
+
recurse_proc(result, &proc) if proc
|
248
|
+
result
|
249
|
+
end
|
250
|
+
|
251
|
+
def recurse_proc(result, &proc)
|
252
|
+
case result
|
253
|
+
when Array
|
254
|
+
result.each { |x| recurse_proc x, &proc }
|
255
|
+
proc.call result
|
256
|
+
when Hash
|
257
|
+
result.each { |x, y| recurse_proc x, &proc; recurse_proc y, &proc }
|
258
|
+
proc.call result
|
259
|
+
else
|
260
|
+
proc.call result
|
261
|
+
end
|
262
|
+
end
|
263
|
+
private :recurse_proc
|
264
|
+
module_function :recurse_proc
|
265
|
+
|
266
|
+
alias restore load
|
267
|
+
module_function :restore
|
268
|
+
|
269
|
+
# Dumps _obj_ as a JSON string, i.e. calls generate on the object and returns
|
270
|
+
# the result.
|
271
|
+
#
|
272
|
+
# If anIO (an IO like object or an object that responds to the write method)
|
273
|
+
# was given, the resulting JSON is written to it.
|
274
|
+
#
|
275
|
+
# If the number of nested arrays or objects exceeds _limit_ an ArgumentError
|
276
|
+
# exception is raised. This argument is similar (but not exactly the
|
277
|
+
# same!) to the _limit_ argument in Marshal.dump.
|
278
|
+
#
|
279
|
+
# This method is part of the implementation of the load/dump interface of
|
280
|
+
# Marshal and YAML.
|
281
|
+
def dump(obj, anIO = nil, limit = nil)
|
282
|
+
if anIO and limit.nil?
|
283
|
+
anIO = anIO.to_io if anIO.respond_to?(:to_io)
|
284
|
+
unless anIO.respond_to?(:write)
|
285
|
+
limit = anIO
|
286
|
+
anIO = nil
|
287
|
+
end
|
288
|
+
end
|
289
|
+
limit ||= 0
|
290
|
+
result = generate(obj, :allow_nan => true, :max_nesting => limit)
|
291
|
+
if anIO
|
292
|
+
anIO.write result
|
293
|
+
anIO
|
294
|
+
else
|
295
|
+
result
|
296
|
+
end
|
297
|
+
rescue JSON::NestingError
|
298
|
+
raise ArgumentError, "exceed depth limit"
|
299
|
+
end
|
152
300
|
end
|
153
301
|
|
154
302
|
module ::Kernel
|
@@ -156,7 +304,7 @@ module ::Kernel
|
|
156
304
|
# one line.
|
157
305
|
def j(*objs)
|
158
306
|
objs.each do |obj|
|
159
|
-
puts JSON::generate(obj)
|
307
|
+
puts JSON::generate(obj, :allow_nan => true, :max_nesting => false)
|
160
308
|
end
|
161
309
|
nil
|
162
310
|
end
|
@@ -165,19 +313,22 @@ module ::Kernel
|
|
165
313
|
# indentation and over many lines.
|
166
314
|
def jj(*objs)
|
167
315
|
objs.each do |obj|
|
168
|
-
puts JSON::pretty_generate(obj)
|
316
|
+
puts JSON::pretty_generate(obj, :allow_nan => true, :max_nesting => false)
|
169
317
|
end
|
170
318
|
nil
|
171
319
|
end
|
172
320
|
|
173
|
-
# If
|
174
|
-
# Ruby data structure. Otherwise generate a JSON text from the Ruby data
|
321
|
+
# If _object_ is string like parse the string and return the parsed result as
|
322
|
+
# a Ruby data structure. Otherwise generate a JSON text from the Ruby data
|
175
323
|
# structure object and return it.
|
176
|
-
|
324
|
+
#
|
325
|
+
# The _opts_ argument is passed through to generate/parse respectively, see
|
326
|
+
# generate and parse for their documentation.
|
327
|
+
def JSON(object, opts = {})
|
177
328
|
if object.respond_to? :to_str
|
178
|
-
JSON.parse(object.to_str)
|
329
|
+
JSON.parse(object.to_str, opts)
|
179
330
|
else
|
180
|
-
JSON.generate(object)
|
331
|
+
JSON.generate(object, opts)
|
181
332
|
end
|
182
333
|
end
|
183
334
|
end
|