json_pure 1.0.0 → 1.4.6
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.
- data/CHANGES +155 -1
- data/COPYING +58 -0
- data/GPL +7 -7
- data/README +324 -45
- data/Rakefile +166 -124
- data/TODO +1 -1
- data/VERSION +1 -1
- data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkComparison.log +52 -0
- data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_fast-autocorrelation.dat +1000 -0
- data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_fast.dat +1001 -0
- data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_pretty-autocorrelation.dat +900 -0
- data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_pretty.dat +901 -0
- data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_safe-autocorrelation.dat +1000 -0
- data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_safe.dat +1001 -0
- data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt.log +261 -0
- data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_fast-autocorrelation.dat +1000 -0
- data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_fast.dat +1001 -0
- data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_pretty-autocorrelation.dat +1000 -0
- data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_pretty.dat +1001 -0
- data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_safe-autocorrelation.dat +1000 -0
- data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_safe.dat +1001 -0
- data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure.log +262 -0
- data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkRails#generator-autocorrelation.dat +1000 -0
- data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkRails#generator.dat +1001 -0
- data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkRails.log +82 -0
- data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkComparison.log +34 -0
- data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkExt#parser-autocorrelation.dat +900 -0
- data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkExt#parser.dat +901 -0
- data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkExt.log +81 -0
- data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkPure#parser-autocorrelation.dat +1000 -0
- data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkPure#parser.dat +1001 -0
- data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkPure.log +82 -0
- data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkRails#parser-autocorrelation.dat +1000 -0
- data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkRails#parser.dat +1001 -0
- data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkRails.log +82 -0
- data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkYAML#parser-autocorrelation.dat +1000 -0
- data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkYAML#parser.dat +1001 -0
- data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkYAML.log +82 -0
- data/benchmarks/generator2_benchmark.rb +222 -0
- data/benchmarks/generator_benchmark.rb +224 -0
- data/benchmarks/ohai.json +1216 -0
- data/benchmarks/ohai.ruby +1 -0
- data/benchmarks/parser2_benchmark.rb +251 -0
- data/benchmarks/parser_benchmark.rb +259 -0
- data/bin/edit_json.rb +1 -3
- data/bin/prettify_json.rb +75 -0
- data/data/index.html +5 -4
- data/data/prototype.js +2764 -1095
- data/ext/json/ext/generator/extconf.rb +14 -3
- data/ext/json/ext/generator/generator.c +1022 -334
- data/ext/json/ext/generator/generator.h +197 -0
- data/ext/json/ext/parser/extconf.rb +9 -3
- data/ext/json/ext/parser/parser.c +961 -577
- data/ext/json/ext/parser/parser.h +71 -0
- data/ext/json/ext/parser/parser.rl +400 -123
- data/install.rb +0 -0
- data/lib/json/add/core.rb +148 -0
- data/lib/json/add/rails.rb +58 -0
- data/lib/json/common.rb +254 -47
- data/lib/json/editor.rb +236 -72
- data/lib/json/ext.rb +2 -0
- data/lib/json/pure/generator.rb +235 -117
- data/lib/json/pure/parser.rb +124 -25
- data/lib/json/pure.rb +5 -3
- data/lib/json/version.rb +1 -1
- data/lib/json.rb +2 -197
- data/tests/fixtures/fail18.json +1 -0
- data/tests/test_json.rb +181 -22
- data/tests/test_json_addition.rb +84 -16
- data/tests/test_json_encoding.rb +68 -0
- data/tests/test_json_fixtures.rb +9 -5
- data/tests/test_json_generate.rb +114 -14
- data/tests/test_json_rails.rb +144 -0
- data/tests/test_json_unicode.rb +35 -14
- data/tools/fuzz.rb +13 -7
- data/tools/server.rb +0 -1
- metadata +156 -122
- data/benchmarks/benchmark.txt +0 -133
- data/benchmarks/benchmark_generator.rb +0 -44
- data/benchmarks/benchmark_parser.rb +0 -22
- data/benchmarks/benchmark_rails.rb +0 -26
- data/ext/json/ext/generator/Makefile +0 -149
- data/ext/json/ext/generator/unicode.c +0 -184
- data/ext/json/ext/generator/unicode.h +0 -40
- data/ext/json/ext/parser/Makefile +0 -149
- data/ext/json/ext/parser/unicode.c +0 -156
- data/ext/json/ext/parser/unicode.h +0 -44
- data/tests/fixtures/pass18.json +0 -1
- data/tests/runner.rb +0 -24
- /data/tests/fixtures/{fail15.json → pass15.json} +0 -0
- /data/tests/fixtures/{fail16.json → pass16.json} +0 -0
- /data/tests/fixtures/{fail17.json → pass17.json} +0 -0
- /data/tests/fixtures/{fail26.json → pass26.json} +0 -0
data/install.rb
CHANGED
|
File without changes
|
|
@@ -0,0 +1,148 @@
|
|
|
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
|
+
require 'date'
|
|
9
|
+
|
|
10
|
+
class Symbol
|
|
11
|
+
def to_json(*a)
|
|
12
|
+
{
|
|
13
|
+
JSON.create_id => self.class.name,
|
|
14
|
+
's' => to_s,
|
|
15
|
+
}.to_json(*a)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def self.json_create(o)
|
|
19
|
+
o['s'].to_sym
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
class Time
|
|
24
|
+
def self.json_create(object)
|
|
25
|
+
if usec = object.delete('u') # used to be tv_usec -> tv_nsec
|
|
26
|
+
object['n'] = usec * 1000
|
|
27
|
+
end
|
|
28
|
+
if respond_to?(:tv_nsec)
|
|
29
|
+
at(*object.values_at('s', 'n'))
|
|
30
|
+
else
|
|
31
|
+
at(object['s'], object['n'] / 1000)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def to_json(*args)
|
|
36
|
+
{
|
|
37
|
+
JSON.create_id => self.class.name,
|
|
38
|
+
's' => tv_sec,
|
|
39
|
+
'n' => respond_to?(:tv_nsec) ? tv_nsec : tv_usec * 1000
|
|
40
|
+
}.to_json(*args)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
class Date
|
|
45
|
+
def self.json_create(object)
|
|
46
|
+
civil(*object.values_at('y', 'm', 'd', 'sg'))
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
alias start sg unless method_defined?(:start)
|
|
50
|
+
|
|
51
|
+
def to_json(*args)
|
|
52
|
+
{
|
|
53
|
+
JSON.create_id => self.class.name,
|
|
54
|
+
'y' => year,
|
|
55
|
+
'm' => month,
|
|
56
|
+
'd' => day,
|
|
57
|
+
'sg' => start,
|
|
58
|
+
}.to_json(*args)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
class DateTime
|
|
63
|
+
def self.json_create(object)
|
|
64
|
+
args = object.values_at('y', 'm', 'd', 'H', 'M', 'S')
|
|
65
|
+
of_a, of_b = object['of'].split('/')
|
|
66
|
+
if of_b and of_b != '0'
|
|
67
|
+
args << Rational(of_a.to_i, of_b.to_i)
|
|
68
|
+
else
|
|
69
|
+
args << of_a
|
|
70
|
+
end
|
|
71
|
+
args << object['sg']
|
|
72
|
+
civil(*args)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
alias start sg unless method_defined?(:start)
|
|
76
|
+
|
|
77
|
+
def to_json(*args)
|
|
78
|
+
{
|
|
79
|
+
JSON.create_id => self.class.name,
|
|
80
|
+
'y' => year,
|
|
81
|
+
'm' => month,
|
|
82
|
+
'd' => day,
|
|
83
|
+
'H' => hour,
|
|
84
|
+
'M' => min,
|
|
85
|
+
'S' => sec,
|
|
86
|
+
'of' => offset.to_s,
|
|
87
|
+
'sg' => start,
|
|
88
|
+
}.to_json(*args)
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
class Range
|
|
93
|
+
def self.json_create(object)
|
|
94
|
+
new(*object['a'])
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def to_json(*args)
|
|
98
|
+
{
|
|
99
|
+
JSON.create_id => self.class.name,
|
|
100
|
+
'a' => [ first, last, exclude_end? ]
|
|
101
|
+
}.to_json(*args)
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
class Struct
|
|
106
|
+
def self.json_create(object)
|
|
107
|
+
new(*object['v'])
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def to_json(*args)
|
|
111
|
+
klass = self.class.name
|
|
112
|
+
klass.to_s.empty? and raise JSON::JSONError, "Only named structs are supported!"
|
|
113
|
+
{
|
|
114
|
+
JSON.create_id => klass,
|
|
115
|
+
'v' => values,
|
|
116
|
+
}.to_json(*args)
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
class Exception
|
|
121
|
+
def self.json_create(object)
|
|
122
|
+
result = new(object['m'])
|
|
123
|
+
result.set_backtrace object['b']
|
|
124
|
+
result
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def to_json(*args)
|
|
128
|
+
{
|
|
129
|
+
JSON.create_id => self.class.name,
|
|
130
|
+
'm' => message,
|
|
131
|
+
'b' => backtrace,
|
|
132
|
+
}.to_json(*args)
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
class Regexp
|
|
137
|
+
def self.json_create(object)
|
|
138
|
+
new(object['s'], object['o'])
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def to_json(*)
|
|
142
|
+
{
|
|
143
|
+
JSON.create_id => self.class.name,
|
|
144
|
+
'o' => options,
|
|
145
|
+
's' => source,
|
|
146
|
+
}.to_json
|
|
147
|
+
end
|
|
148
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
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.create_id
|
|
14
|
+
instance_variable_set "@#{key}", value
|
|
15
|
+
end
|
|
16
|
+
obj
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def to_json(*a)
|
|
20
|
+
result = {
|
|
21
|
+
JSON.create_id => 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
|
+
class Symbol
|
|
32
|
+
def to_json(*a)
|
|
33
|
+
to_s.to_json(*a)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
module Enumerable
|
|
38
|
+
def to_json(*a)
|
|
39
|
+
to_a.to_json(*a)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# class Regexp
|
|
44
|
+
# def to_json(*)
|
|
45
|
+
# inspect
|
|
46
|
+
# end
|
|
47
|
+
# end
|
|
48
|
+
#
|
|
49
|
+
# The above rails definition has some problems:
|
|
50
|
+
#
|
|
51
|
+
# 1. { 'foo' => /bar/ }.to_json # => "{foo: /bar/}"
|
|
52
|
+
# This isn't valid JSON, because the regular expression syntax is not
|
|
53
|
+
# defined in RFC 4627. (And unquoted strings are disallowed there, too.)
|
|
54
|
+
# Though it is valid Javascript.
|
|
55
|
+
#
|
|
56
|
+
# 2. { 'foo' => /bar/mix }.to_json # => "{foo: /bar/mix}"
|
|
57
|
+
# This isn't even valid Javascript.
|
|
58
|
+
|
data/lib/json/common.rb
CHANGED
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
require 'json/version'
|
|
2
|
+
require 'iconv'
|
|
2
3
|
|
|
3
4
|
module JSON
|
|
4
5
|
class << self
|
|
5
|
-
# If
|
|
6
|
-
# Ruby data structure. Otherwise generate a JSON text from the Ruby
|
|
7
|
-
# structure object and return it.
|
|
8
|
-
|
|
6
|
+
# If _object_ is string-like parse the string and return the parsed result
|
|
7
|
+
# as a Ruby data structure. Otherwise generate a JSON text from the Ruby
|
|
8
|
+
# data structure object and return it.
|
|
9
|
+
#
|
|
10
|
+
# The _opts_ argument is passed through to generate/parse respectively, see
|
|
11
|
+
# generate and parse for their documentation.
|
|
12
|
+
def [](object, opts = {})
|
|
9
13
|
if object.respond_to? :to_str
|
|
10
|
-
JSON.parse(object.to_str)
|
|
14
|
+
JSON.parse(object.to_str, opts)
|
|
11
15
|
else
|
|
12
|
-
JSON.generate(object)
|
|
16
|
+
JSON.generate(object, opts)
|
|
13
17
|
end
|
|
14
18
|
end
|
|
15
19
|
|
|
@@ -29,11 +33,16 @@ module JSON
|
|
|
29
33
|
# level (absolute namespace path?). If there doesn't exist a constant at
|
|
30
34
|
# the given path, an ArgumentError is raised.
|
|
31
35
|
def deep_const_get(path) # :nodoc:
|
|
32
|
-
path.split(/::/).inject(Object) do |p, c|
|
|
36
|
+
path.to_s.split(/::/).inject(Object) do |p, c|
|
|
33
37
|
case
|
|
34
38
|
when c.empty? then p
|
|
35
39
|
when p.const_defined?(c) then p.const_get(c)
|
|
36
|
-
else
|
|
40
|
+
else
|
|
41
|
+
begin
|
|
42
|
+
p.const_missing(c)
|
|
43
|
+
rescue NameError
|
|
44
|
+
raise ArgumentError, "can't find const #{path}"
|
|
45
|
+
end
|
|
37
46
|
end
|
|
38
47
|
end
|
|
39
48
|
end
|
|
@@ -54,6 +63,20 @@ module JSON
|
|
|
54
63
|
end
|
|
55
64
|
self.state = generator::State
|
|
56
65
|
const_set :State, self.state
|
|
66
|
+
const_set :SAFE_STATE_PROTOTYPE, State.new
|
|
67
|
+
const_set :FAST_STATE_PROTOTYPE, State.new(
|
|
68
|
+
:indent => '',
|
|
69
|
+
:space => '',
|
|
70
|
+
:object_nl => "",
|
|
71
|
+
:array_nl => "",
|
|
72
|
+
:max_nesting => false
|
|
73
|
+
)
|
|
74
|
+
const_set :PRETTY_STATE_PROTOTYPE, State.new(
|
|
75
|
+
:indent => ' ',
|
|
76
|
+
:space => ' ',
|
|
77
|
+
:object_nl => "\n",
|
|
78
|
+
:array_nl => "\n"
|
|
79
|
+
)
|
|
57
80
|
end
|
|
58
81
|
|
|
59
82
|
# Returns the JSON generator modul, that is used by JSON. This might be
|
|
@@ -70,83 +93,265 @@ module JSON
|
|
|
70
93
|
end
|
|
71
94
|
self.create_id = 'json_class'
|
|
72
95
|
|
|
96
|
+
NaN = 0.0/0
|
|
97
|
+
|
|
98
|
+
Infinity = 1.0/0
|
|
99
|
+
|
|
100
|
+
MinusInfinity = -Infinity
|
|
101
|
+
|
|
73
102
|
# The base exception for JSON errors.
|
|
74
103
|
class JSONError < StandardError; end
|
|
75
104
|
|
|
76
105
|
# This exception is raised, if a parser error occurs.
|
|
77
106
|
class ParserError < JSONError; end
|
|
78
107
|
|
|
108
|
+
# This exception is raised, if the nesting of parsed datastructures is too
|
|
109
|
+
# deep.
|
|
110
|
+
class NestingError < ParserError; end
|
|
111
|
+
|
|
112
|
+
# :stopdoc:
|
|
113
|
+
class CircularDatastructure < NestingError; end
|
|
114
|
+
# :startdoc:
|
|
115
|
+
|
|
79
116
|
# This exception is raised, if a generator or unparser error occurs.
|
|
80
117
|
class GeneratorError < JSONError; end
|
|
81
118
|
# For backwards compatibility
|
|
82
119
|
UnparserError = GeneratorError
|
|
83
120
|
|
|
84
|
-
# If a circular data structure is encountered while unparsing
|
|
85
|
-
# this exception is raised.
|
|
86
|
-
class CircularDatastructure < GeneratorError; end
|
|
87
|
-
|
|
88
121
|
# This exception is raised, if the required unicode support is missing on the
|
|
89
122
|
# system. Usually this means, that the iconv library is not installed.
|
|
90
123
|
class MissingUnicodeSupport < JSONError; end
|
|
91
124
|
|
|
92
125
|
module_function
|
|
93
126
|
|
|
94
|
-
# Parse the JSON
|
|
95
|
-
|
|
96
|
-
|
|
127
|
+
# Parse the JSON document _source_ into a Ruby data structure and return it.
|
|
128
|
+
#
|
|
129
|
+
# _opts_ can have the following
|
|
130
|
+
# keys:
|
|
131
|
+
# * *max_nesting*: The maximum depth of nesting allowed in the parsed data
|
|
132
|
+
# structures. Disable depth checking with :max_nesting => false, it defaults
|
|
133
|
+
# to 19.
|
|
134
|
+
# * *allow_nan*: If set to true, allow NaN, Infinity and -Infinity in
|
|
135
|
+
# defiance of RFC 4627 to be parsed by the Parser. This option defaults
|
|
136
|
+
# to false.
|
|
137
|
+
# * *symbolize_names*: If set to true, returns symbols for the names
|
|
138
|
+
# (keys) in a JSON object. Otherwise strings are returned, which is also
|
|
139
|
+
# the default.
|
|
140
|
+
# * *create_additions*: If set to false, the Parser doesn't create
|
|
141
|
+
# additions even if a matchin class and create_id was found. This option
|
|
142
|
+
# defaults to true.
|
|
143
|
+
# * *object_class*: Defaults to Hash
|
|
144
|
+
# * *array_class*: Defaults to Array
|
|
145
|
+
def parse(source, opts = {})
|
|
146
|
+
Parser.new(source, opts).parse
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
# Parse the JSON document _source_ into a Ruby data structure and return it.
|
|
150
|
+
# The bang version of the parse method, defaults to the more dangerous values
|
|
151
|
+
# for the _opts_ hash, so be sure only to parse trusted _source_ documents.
|
|
152
|
+
#
|
|
153
|
+
# _opts_ can have the following keys:
|
|
154
|
+
# * *max_nesting*: The maximum depth of nesting allowed in the parsed data
|
|
155
|
+
# structures. Enable depth checking with :max_nesting => anInteger. The parse!
|
|
156
|
+
# methods defaults to not doing max depth checking: This can be dangerous,
|
|
157
|
+
# if someone wants to fill up your stack.
|
|
158
|
+
# * *allow_nan*: If set to true, allow NaN, Infinity, and -Infinity in
|
|
159
|
+
# defiance of RFC 4627 to be parsed by the Parser. This option defaults
|
|
160
|
+
# to true.
|
|
161
|
+
# * *create_additions*: If set to false, the Parser doesn't create
|
|
162
|
+
# additions even if a matchin class and create_id was found. This option
|
|
163
|
+
# defaults to true.
|
|
164
|
+
def parse!(source, opts = {})
|
|
165
|
+
opts = {
|
|
166
|
+
:max_nesting => false,
|
|
167
|
+
:allow_nan => true
|
|
168
|
+
}.update(opts)
|
|
169
|
+
Parser.new(source, opts).parse
|
|
97
170
|
end
|
|
98
171
|
|
|
99
|
-
#
|
|
100
|
-
#
|
|
101
|
-
#
|
|
172
|
+
# Generate a JSON document from the Ruby data structure _obj_ and return
|
|
173
|
+
# it. _state_ is * a JSON::State object,
|
|
174
|
+
# * or a Hash like object (responding to to_hash),
|
|
175
|
+
# * an object convertible into a hash by a to_h method,
|
|
176
|
+
# that is used as or to configure a State object.
|
|
102
177
|
#
|
|
103
178
|
# It defaults to a state object, that creates the shortest possible JSON text
|
|
104
|
-
# in one line
|
|
105
|
-
#
|
|
106
|
-
#
|
|
107
|
-
#
|
|
108
|
-
|
|
109
|
-
|
|
179
|
+
# in one line, checks for circular data structures and doesn't allow NaN,
|
|
180
|
+
# Infinity, and -Infinity.
|
|
181
|
+
#
|
|
182
|
+
# A _state_ hash can have the following keys:
|
|
183
|
+
# * *indent*: a string used to indent levels (default: ''),
|
|
184
|
+
# * *space*: a string that is put after, a : or , delimiter (default: ''),
|
|
185
|
+
# * *space_before*: a string that is put before a : pair delimiter (default: ''),
|
|
186
|
+
# * *object_nl*: a string that is put at the end of a JSON object (default: ''),
|
|
187
|
+
# * *array_nl*: a string that is put at the end of a JSON array (default: ''),
|
|
188
|
+
# * *allow_nan*: true if NaN, Infinity, and -Infinity should be
|
|
189
|
+
# generated, otherwise an exception is thrown, if these values are
|
|
190
|
+
# encountered. This options defaults to false.
|
|
191
|
+
# * *max_nesting*: The maximum depth of nesting allowed in the data
|
|
192
|
+
# structures from which JSON is to be generated. Disable depth checking
|
|
193
|
+
# with :max_nesting => false, it defaults to 19.
|
|
194
|
+
#
|
|
195
|
+
# See also the fast_generate for the fastest creation method with the least
|
|
196
|
+
# amount of sanity checks, and the pretty_generate method for some
|
|
197
|
+
# defaults for a pretty output.
|
|
198
|
+
def generate(obj, opts = nil)
|
|
199
|
+
state = SAFE_STATE_PROTOTYPE.dup
|
|
200
|
+
if opts
|
|
201
|
+
if opts.respond_to? :to_hash
|
|
202
|
+
opts = opts.to_hash
|
|
203
|
+
elsif opts.respond_to? :to_h
|
|
204
|
+
opts = opts.to_h
|
|
205
|
+
else
|
|
206
|
+
raise TypeError, "can't convert #{opts.class} into Hash"
|
|
207
|
+
end
|
|
208
|
+
state = state.configure(opts)
|
|
209
|
+
end
|
|
210
|
+
state.generate(obj)
|
|
110
211
|
end
|
|
111
212
|
|
|
213
|
+
# :stopdoc:
|
|
214
|
+
# I want to deprecate these later, so I'll first be silent about them, and
|
|
215
|
+
# later delete them.
|
|
112
216
|
alias unparse generate
|
|
113
217
|
module_function :unparse
|
|
218
|
+
# :startdoc:
|
|
114
219
|
|
|
115
|
-
#
|
|
116
|
-
#
|
|
220
|
+
# Generate a JSON document from the Ruby data structure _obj_ and return it.
|
|
221
|
+
# This method disables the checks for circles in Ruby objects.
|
|
117
222
|
#
|
|
118
223
|
# *WARNING*: Be careful not to pass any Ruby data structures with circles as
|
|
119
224
|
# _obj_ argument, because this will cause JSON to go into an infinite loop.
|
|
120
|
-
def fast_generate(obj)
|
|
121
|
-
|
|
225
|
+
def fast_generate(obj, opts = nil)
|
|
226
|
+
state = FAST_STATE_PROTOTYPE.dup
|
|
227
|
+
if opts
|
|
228
|
+
if opts.respond_to? :to_hash
|
|
229
|
+
opts = opts.to_hash
|
|
230
|
+
elsif opts.respond_to? :to_h
|
|
231
|
+
opts = opts.to_h
|
|
232
|
+
else
|
|
233
|
+
raise TypeError, "can't convert #{opts.class} into Hash"
|
|
234
|
+
end
|
|
235
|
+
state.configure(opts)
|
|
236
|
+
end
|
|
237
|
+
state.generate(obj)
|
|
122
238
|
end
|
|
123
239
|
|
|
240
|
+
# :stopdoc:
|
|
241
|
+
# I want to deprecate these later, so I'll first be silent about them, and later delete them.
|
|
124
242
|
alias fast_unparse fast_generate
|
|
125
243
|
module_function :fast_unparse
|
|
244
|
+
# :startdoc:
|
|
126
245
|
|
|
127
|
-
#
|
|
128
|
-
# returned
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
246
|
+
# Generate a JSON document from the Ruby data structure _obj_ and return it.
|
|
247
|
+
# The returned document is a prettier form of the document returned by
|
|
248
|
+
# #unparse.
|
|
249
|
+
#
|
|
250
|
+
# The _opts_ argument can be used to configure the generator, see the
|
|
251
|
+
# generate method for a more detailed explanation.
|
|
252
|
+
def pretty_generate(obj, opts = nil)
|
|
253
|
+
state = PRETTY_STATE_PROTOTYPE.dup
|
|
254
|
+
if opts
|
|
255
|
+
if opts.respond_to? :to_hash
|
|
256
|
+
opts = opts.to_hash
|
|
257
|
+
elsif opts.respond_to? :to_h
|
|
258
|
+
opts = opts.to_h
|
|
259
|
+
else
|
|
260
|
+
raise TypeError, "can't convert #{opts.class} into Hash"
|
|
261
|
+
end
|
|
262
|
+
state.configure(opts)
|
|
263
|
+
end
|
|
264
|
+
state.generate(obj)
|
|
138
265
|
end
|
|
139
266
|
|
|
267
|
+
# :stopdoc:
|
|
268
|
+
# I want to deprecate these later, so I'll first be silent about them, and later delete them.
|
|
140
269
|
alias pretty_unparse pretty_generate
|
|
141
270
|
module_function :pretty_unparse
|
|
271
|
+
# :startdoc:
|
|
272
|
+
|
|
273
|
+
# Load a ruby data structure from a JSON _source_ and return it. A source can
|
|
274
|
+
# either be a string-like object, an IO like object, or an object responding
|
|
275
|
+
# to the read method. If _proc_ was given, it will be called with any nested
|
|
276
|
+
# Ruby object as an argument recursively in depth first order.
|
|
277
|
+
#
|
|
278
|
+
# This method is part of the implementation of the load/dump interface of
|
|
279
|
+
# Marshal and YAML.
|
|
280
|
+
def load(source, proc = nil)
|
|
281
|
+
if source.respond_to? :to_str
|
|
282
|
+
source = source.to_str
|
|
283
|
+
elsif source.respond_to? :to_io
|
|
284
|
+
source = source.to_io.read
|
|
285
|
+
else
|
|
286
|
+
source = source.read
|
|
287
|
+
end
|
|
288
|
+
result = parse(source, :max_nesting => false, :allow_nan => true)
|
|
289
|
+
recurse_proc(result, &proc) if proc
|
|
290
|
+
result
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
def recurse_proc(result, &proc)
|
|
294
|
+
case result
|
|
295
|
+
when Array
|
|
296
|
+
result.each { |x| recurse_proc x, &proc }
|
|
297
|
+
proc.call result
|
|
298
|
+
when Hash
|
|
299
|
+
result.each { |x, y| recurse_proc x, &proc; recurse_proc y, &proc }
|
|
300
|
+
proc.call result
|
|
301
|
+
else
|
|
302
|
+
proc.call result
|
|
303
|
+
end
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
alias restore load
|
|
307
|
+
module_function :restore
|
|
308
|
+
|
|
309
|
+
# Dumps _obj_ as a JSON string, i.e. calls generate on the object and returns
|
|
310
|
+
# the result.
|
|
311
|
+
#
|
|
312
|
+
# If anIO (an IO like object or an object that responds to the write method)
|
|
313
|
+
# was given, the resulting JSON is written to it.
|
|
314
|
+
#
|
|
315
|
+
# If the number of nested arrays or objects exceeds _limit_ an ArgumentError
|
|
316
|
+
# exception is raised. This argument is similar (but not exactly the
|
|
317
|
+
# same!) to the _limit_ argument in Marshal.dump.
|
|
318
|
+
#
|
|
319
|
+
# This method is part of the implementation of the load/dump interface of
|
|
320
|
+
# Marshal and YAML.
|
|
321
|
+
def dump(obj, anIO = nil, limit = nil)
|
|
322
|
+
if anIO and limit.nil?
|
|
323
|
+
anIO = anIO.to_io if anIO.respond_to?(:to_io)
|
|
324
|
+
unless anIO.respond_to?(:write)
|
|
325
|
+
limit = anIO
|
|
326
|
+
anIO = nil
|
|
327
|
+
end
|
|
328
|
+
end
|
|
329
|
+
limit ||= 0
|
|
330
|
+
result = generate(obj, :allow_nan => true, :max_nesting => limit)
|
|
331
|
+
if anIO
|
|
332
|
+
anIO.write result
|
|
333
|
+
anIO
|
|
334
|
+
else
|
|
335
|
+
result
|
|
336
|
+
end
|
|
337
|
+
rescue JSON::NestingError
|
|
338
|
+
raise ArgumentError, "exceed depth limit"
|
|
339
|
+
end
|
|
340
|
+
|
|
341
|
+
# Shortuct for iconv.
|
|
342
|
+
def self.iconv(to, from, string)
|
|
343
|
+
Iconv.iconv(to, from, string).first
|
|
344
|
+
end
|
|
142
345
|
end
|
|
143
346
|
|
|
144
347
|
module ::Kernel
|
|
348
|
+
private
|
|
349
|
+
|
|
145
350
|
# Outputs _objs_ to STDOUT as JSON strings in the shortest form, that is in
|
|
146
351
|
# one line.
|
|
147
352
|
def j(*objs)
|
|
148
353
|
objs.each do |obj|
|
|
149
|
-
puts JSON::generate(obj)
|
|
354
|
+
puts JSON::generate(obj, :allow_nan => true, :max_nesting => false)
|
|
150
355
|
end
|
|
151
356
|
nil
|
|
152
357
|
end
|
|
@@ -155,19 +360,22 @@ module ::Kernel
|
|
|
155
360
|
# indentation and over many lines.
|
|
156
361
|
def jj(*objs)
|
|
157
362
|
objs.each do |obj|
|
|
158
|
-
puts JSON::pretty_generate(obj)
|
|
363
|
+
puts JSON::pretty_generate(obj, :allow_nan => true, :max_nesting => false)
|
|
159
364
|
end
|
|
160
365
|
nil
|
|
161
366
|
end
|
|
162
367
|
|
|
163
|
-
# If
|
|
164
|
-
# Ruby data structure. Otherwise generate a JSON text from the Ruby data
|
|
368
|
+
# If _object_ is string-like parse the string and return the parsed result as
|
|
369
|
+
# a Ruby data structure. Otherwise generate a JSON text from the Ruby data
|
|
165
370
|
# structure object and return it.
|
|
166
|
-
|
|
371
|
+
#
|
|
372
|
+
# The _opts_ argument is passed through to generate/parse respectively, see
|
|
373
|
+
# generate and parse for their documentation.
|
|
374
|
+
def JSON(object, *args)
|
|
167
375
|
if object.respond_to? :to_str
|
|
168
|
-
JSON.parse(object.to_str)
|
|
376
|
+
JSON.parse(object.to_str, args.first)
|
|
169
377
|
else
|
|
170
|
-
JSON.generate(object)
|
|
378
|
+
JSON.generate(object, args.first)
|
|
171
379
|
end
|
|
172
380
|
end
|
|
173
381
|
end
|
|
@@ -181,4 +389,3 @@ class ::Class
|
|
|
181
389
|
respond_to?(:json_create)
|
|
182
390
|
end
|
|
183
391
|
end
|
|
184
|
-
# vim: set et sw=2 ts=2:
|