json 2.3.1 → 2.4.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.
@@ -50,6 +50,7 @@ public class Parser extends RubyObject {
50
50
  private int maxNesting;
51
51
  private boolean allowNaN;
52
52
  private boolean symbolizeNames;
53
+ private boolean freeze;
53
54
  private RubyClass objectClass;
54
55
  private RubyClass arrayClass;
55
56
  private RubyClass decimalClass;
@@ -158,6 +159,7 @@ public class Parser extends RubyObject {
158
159
  this.maxNesting = opts.getInt("max_nesting", DEFAULT_MAX_NESTING);
159
160
  this.allowNaN = opts.getBool("allow_nan", false);
160
161
  this.symbolizeNames = opts.getBool("symbolize_names", false);
162
+ this.freeze = opts.getBool("freeze", false);
161
163
  this.createId = opts.getString("create_id", getCreateId(context));
162
164
  this.createAdditions = opts.getBool("create_additions", false);
163
165
  this.objectClass = opts.getClass("object_class", runtime.getHash());
@@ -452,6 +454,9 @@ public class Parser extends RubyObject {
452
454
  %% write exec;
453
455
 
454
456
  if (cs >= JSON_value_first_final && result != null) {
457
+ if (parser.freeze) {
458
+ result.setFrozen(true);
459
+ }
455
460
  res.update(result, p);
456
461
  } else {
457
462
  res.update(null, p);
@@ -633,9 +638,16 @@ public class Parser extends RubyObject {
633
638
 
634
639
  if (cs >= JSON_string_first_final && result != null) {
635
640
  if (result instanceof RubyString) {
636
- ((RubyString)result).force_encoding(context, info.utf8.get());
641
+ RubyString string = (RubyString)result;
642
+ string.force_encoding(context, info.utf8.get());
643
+ if (parser.freeze) {
644
+ string.setFrozen(true);
645
+ string = getRuntime().freezeAndDedupString(string);
646
+ }
647
+ res.update(string, p + 1);
648
+ } else {
649
+ res.update(result, p + 1);
637
650
  }
638
- res.update(result, p + 1);
639
651
  } else {
640
652
  res.update(null, p + 1);
641
653
  }
@@ -15,7 +15,7 @@ import org.jruby.util.ByteList;
15
15
  * and throws a GeneratorError if any problem is found.
16
16
  */
17
17
  final class StringEncoder extends ByteListTranscoder {
18
- private final boolean asciiOnly;
18
+ private final boolean asciiOnly, escapeSlash;
19
19
 
20
20
  // Escaped characters will reuse this array, to avoid new allocations
21
21
  // or appending them byte-by-byte
@@ -37,9 +37,10 @@ final class StringEncoder extends ByteListTranscoder {
37
37
  new byte[] {'0', '1', '2', '3', '4', '5', '6', '7',
38
38
  '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
39
39
 
40
- StringEncoder(ThreadContext context, boolean asciiOnly) {
40
+ StringEncoder(ThreadContext context, boolean asciiOnly, boolean escapeSlash) {
41
41
  super(context);
42
42
  this.asciiOnly = asciiOnly;
43
+ this.escapeSlash = escapeSlash;
43
44
  }
44
45
 
45
46
  void encode(ByteList src, ByteList out) {
@@ -73,6 +74,11 @@ final class StringEncoder extends ByteListTranscoder {
73
74
  case '\b':
74
75
  escapeChar('b');
75
76
  break;
77
+ case '/':
78
+ if(escapeSlash) {
79
+ escapeChar((char)c);
80
+ break;
81
+ }
76
82
  default:
77
83
  if (c >= 0x20 && c <= 0x7f ||
78
84
  (c >= 0x80 && !asciiOnly)) {
@@ -1,33 +1,34 @@
1
- #!/usr/bin/env jruby
2
- require "rubygems"
1
+ # -*- encoding: utf-8 -*-
3
2
 
4
3
  spec = Gem::Specification.new do |s|
5
4
  s.name = "json"
6
5
  s.version = File.read("VERSION").chomp
7
- s.summary = "JSON implementation for JRuby"
6
+
7
+ s.summary = "JSON Implementation for Ruby"
8
8
  s.description = "A JSON implementation as a JRuby extension."
9
+ s.licenses = ["Ruby"]
9
10
  s.author = "Daniel Luz"
10
11
  s.email = "dev+ruby@mernen.com"
11
- s.homepage = "http://flori.github.com/json"
12
+
12
13
  s.platform = 'java'
13
- s.licenses = ["Ruby"]
14
14
 
15
- s.files = Dir["{docs,lib,tests}/**/*"]
16
-
17
- if s.respond_to? :specification_version then
18
- s.specification_version = 4
19
-
20
- if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
21
- s.add_development_dependency(%q<rake>, [">= 0"])
22
- s.add_development_dependency(%q<test-unit>, [">= 2.0", "< 4.0"])
23
- else
24
- s.add_dependency(%q<rake>, [">= 0"])
25
- s.add_dependency(%q<test-unit>, [">= 2.0", "< 4.0"])
26
- end
27
- else
28
- s.add_dependency(%q<rake>, [">= 0"])
29
- s.add_dependency(%q<test-unit>, [">= 2.0", "< 4.0"])
30
- end
15
+ s.files = Dir["{docs,lib,tests}/**/*", "LICENSE"]
16
+
17
+ s.homepage = "http://flori.github.com/json"
18
+ s.metadata = {
19
+ 'bug_tracker_uri' => 'https://github.com/flori/json/issues',
20
+ 'changelog_uri' => 'https://github.com/flori/json/blob/master/CHANGES.md',
21
+ 'documentation_uri' => 'http://flori.github.io/json/doc/index.html',
22
+ 'homepage_uri' => 'http://flori.github.io/json/',
23
+ 'source_code_uri' => 'https://github.com/flori/json',
24
+ 'wiki_uri' => 'https://github.com/flori/json/wiki'
25
+ }
26
+
27
+ s.required_ruby_version = Gem::Requirement.new(">= 2.0")
28
+ s.test_files = ["tests/test_helper.rb"]
29
+
30
+ s.add_development_dependency("rake", [">= 0"])
31
+ s.add_development_dependency("test-unit", [">= 2.0", "< 4.0"])
31
32
  end
32
33
 
33
34
  if $0 == __FILE__
@@ -4,18 +4,21 @@ Gem::Specification.new do |s|
4
4
  s.name = "json"
5
5
  s.version = File.read('VERSION').chomp
6
6
 
7
- s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
- s.require_paths = ["lib"]
9
- s.authors = ["Florian Frank"]
7
+ s.summary = "JSON Implementation for Ruby"
10
8
  s.description = "This is a JSON implementation as a Ruby extension in C."
9
+ s.licenses = ["Ruby"]
10
+ s.authors = ["Florian Frank"]
11
11
  s.email = "flori@ping.de"
12
+
12
13
  s.extensions = ["ext/json/ext/generator/extconf.rb", "ext/json/ext/parser/extconf.rb", "ext/json/extconf.rb"]
13
14
  s.extra_rdoc_files = ["README.md"]
15
+ s.rdoc_options = ["--title", "JSON implemention for Ruby", "--main", "README.md"]
14
16
  s.files = [
15
17
  ".gitignore",
16
18
  ".travis.yml",
17
19
  "CHANGES.md",
18
20
  "Gemfile",
21
+ "LICENSE",
19
22
  "README-json-jruby.md",
20
23
  "README.md",
21
24
  "Rakefile",
@@ -128,10 +131,8 @@ Gem::Specification.new do |s|
128
131
  'source_code_uri' => 'https://github.com/flori/json',
129
132
  'wiki_uri' => 'https://github.com/flori/json/wiki'
130
133
  }
131
- s.licenses = ["Ruby"]
132
- s.rdoc_options = ["--title", "JSON implemention for Ruby", "--main", "README.md"]
134
+
133
135
  s.required_ruby_version = Gem::Requirement.new(">= 2.0")
134
- s.summary = "JSON Implementation for Ruby"
135
136
  s.test_files = ["tests/test_helper.rb"]
136
137
 
137
138
  s.add_development_dependency("rake", [">= 0"])
@@ -107,6 +107,89 @@ require 'json/common'
107
107
  # ruby # => nil
108
108
  # ruby.class # => NilClass
109
109
  #
110
+ # ==== Parsing Options
111
+ #
112
+ # ====== Input Options
113
+ #
114
+ # Option +max_nesting+ (\Integer) specifies the maximum nesting depth allowed;
115
+ # defaults to +100+; specify +false+ to disable depth checking.
116
+ #
117
+ # With the default, +false+:
118
+ # source = '[0, [1, [2, [3]]]]'
119
+ # ruby = JSON.parse(source)
120
+ # ruby # => [0, [1, [2, [3]]]]
121
+ # Too deep:
122
+ # # Raises JSON::NestingError (nesting of 2 is too deep):
123
+ # JSON.parse(source, {max_nesting: 1})
124
+ # Bad value:
125
+ # # Raises TypeError (wrong argument type Symbol (expected Fixnum)):
126
+ # JSON.parse(source, {max_nesting: :foo})
127
+ #
128
+ # ---
129
+ #
130
+ # Option +allow_nan+ (boolean) specifies whether to allow
131
+ # NaN, Infinity, and MinusInfinity in +source+;
132
+ # defaults to +false+.
133
+ #
134
+ # With the default, +false+:
135
+ # # Raises JSON::ParserError (225: unexpected token at '[NaN]'):
136
+ # JSON.parse('[NaN]')
137
+ # # Raises JSON::ParserError (232: unexpected token at '[Infinity]'):
138
+ # JSON.parse('[Infinity]')
139
+ # # Raises JSON::ParserError (248: unexpected token at '[-Infinity]'):
140
+ # JSON.parse('[-Infinity]')
141
+ # Allow:
142
+ # source = '[NaN, Infinity, -Infinity]'
143
+ # ruby = JSON.parse(source, {allow_nan: true})
144
+ # ruby # => [NaN, Infinity, -Infinity]
145
+ #
146
+ # ====== Output Options
147
+ #
148
+ # Option +symbolize_names+ (boolean) specifies whether returned \Hash keys
149
+ # should be Symbols;
150
+ # defaults to +false+ (use Strings).
151
+ #
152
+ # With the default, +false+:
153
+ # source = '{"a": "foo", "b": 1.0, "c": true, "d": false, "e": null}'
154
+ # ruby = JSON.parse(source)
155
+ # ruby # => {"a"=>"foo", "b"=>1.0, "c"=>true, "d"=>false, "e"=>nil}
156
+ # Use Symbols:
157
+ # ruby = JSON.parse(source, {symbolize_names: true})
158
+ # ruby # => {:a=>"foo", :b=>1.0, :c=>true, :d=>false, :e=>nil}
159
+ #
160
+ # ---
161
+ #
162
+ # Option +object_class+ (\Class) specifies the Ruby class to be used
163
+ # for each \JSON object;
164
+ # defaults to \Hash.
165
+ #
166
+ # With the default, \Hash:
167
+ # source = '{"a": "foo", "b": 1.0, "c": true, "d": false, "e": null}'
168
+ # ruby = JSON.parse(source)
169
+ # ruby.class # => Hash
170
+ # Use class \OpenStruct:
171
+ # ruby = JSON.parse(source, {object_class: OpenStruct})
172
+ # ruby # => #<OpenStruct a="foo", b=1.0, c=true, d=false, e=nil>
173
+ #
174
+ # ---
175
+ #
176
+ # Option +array_class+ (\Class) specifies the Ruby class to be used
177
+ # for each \JSON array;
178
+ # defaults to \Array.
179
+ #
180
+ # With the default, \Array:
181
+ # source = '["foo", 1.0, true, false, null]'
182
+ # ruby = JSON.parse(source)
183
+ # ruby.class # => Array
184
+ # Use class \Set:
185
+ # ruby = JSON.parse(source, {array_class: Set})
186
+ # ruby # => #<Set: {"foo", 1.0, true, false, nil}>
187
+ #
188
+ # ---
189
+ #
190
+ # Option +create_additions+ (boolean) specifies whether to use \JSON additions in parsing.
191
+ # See {\JSON Additions}[#module-JSON-label-JSON+Additions].
192
+ #
110
193
  # === Generating \JSON
111
194
  #
112
195
  # To generate a Ruby \String containing \JSON data,
@@ -169,6 +252,94 @@ require 'json/common'
169
252
  # JSON.generate(Complex(0, 0)) # => '"0+0i"'
170
253
  # JSON.generate(Dir.new('.')) # => '"#<Dir>"'
171
254
  #
255
+ # ==== Generating Options
256
+ #
257
+ # ====== Input Options
258
+ #
259
+ # Option +allow_nan+ (boolean) specifies whether
260
+ # +NaN+, +Infinity+, and <tt>-Infinity</tt> may be generated;
261
+ # defaults to +false+.
262
+ #
263
+ # With the default, +false+:
264
+ # # Raises JSON::GeneratorError (920: NaN not allowed in JSON):
265
+ # JSON.generate(JSON::NaN)
266
+ # # Raises JSON::GeneratorError (917: Infinity not allowed in JSON):
267
+ # JSON.generate(JSON::Infinity)
268
+ # # Raises JSON::GeneratorError (917: -Infinity not allowed in JSON):
269
+ # JSON.generate(JSON::MinusInfinity)
270
+ #
271
+ # Allow:
272
+ # ruby = [Float::NaN, Float::Infinity, Float::MinusInfinity]
273
+ # JSON.generate(ruby, allow_nan: true) # => '[NaN,Infinity,-Infinity]'
274
+ #
275
+ # ---
276
+ #
277
+ # Option +max_nesting+ (\Integer) specifies the maximum nesting depth
278
+ # in +obj+; defaults to +100+.
279
+ #
280
+ # With the default, +100+:
281
+ # obj = [[[[[[0]]]]]]
282
+ # JSON.generate(obj) # => '[[[[[[0]]]]]]'
283
+ #
284
+ # Too deep:
285
+ # # Raises JSON::NestingError (nesting of 2 is too deep):
286
+ # JSON.generate(obj, max_nesting: 2)
287
+ #
288
+ # ====== Output Options
289
+ #
290
+ # The default formatting options generate the most compact
291
+ # \JSON data, all on one line and with no whitespace.
292
+ #
293
+ # You can use these formatting options to generate
294
+ # \JSON data in a more open format, using whitespace.
295
+ # See also JSON.pretty_generate.
296
+ #
297
+ # - Option +array_nl+ (\String) specifies a string (usually a newline)
298
+ # to be inserted after each \JSON array; defaults to the empty \String, <tt>''</tt>.
299
+ # - Option +object_nl+ (\String) specifies a string (usually a newline)
300
+ # to be inserted after each \JSON object; defaults to the empty \String, <tt>''</tt>.
301
+ # - Option +indent+ (\String) specifies the string (usually spaces) to be
302
+ # used for indentation; defaults to the empty \String, <tt>''</tt>;
303
+ # defaults to the empty \String, <tt>''</tt>;
304
+ # has no effect unless options +array_nl+ or +object_nl+ specify newlines.
305
+ # - Option +space+ (\String) specifies a string (usually a space) to be
306
+ # inserted after the colon in each \JSON object's pair;
307
+ # defaults to the empty \String, <tt>''</tt>.
308
+ # - Option +space_before+ (\String) specifies a string (usually a space) to be
309
+ # inserted before the colon in each \JSON object's pair;
310
+ # defaults to the empty \String, <tt>''</tt>.
311
+ #
312
+ # In this example, +obj+ is used first to generate the shortest
313
+ # \JSON data (no whitespace), then again with all formatting options
314
+ # specified:
315
+ #
316
+ # obj = {foo: [:bar, :baz], bat: {bam: 0, bad: 1}}
317
+ # json = JSON.generate(obj)
318
+ # puts 'Compact:', json
319
+ # opts = {
320
+ # array_nl: "\n",
321
+ # object_nl: "\n",
322
+ # indent: ' ',
323
+ # space_before: ' ',
324
+ # space: ' '
325
+ # }
326
+ # puts 'Open:', JSON.generate(obj, opts)
327
+ #
328
+ # Output:
329
+ # Compact:
330
+ # {"foo":["bar","baz"],"bat":{"bam":0,"bad":1}}
331
+ # Open:
332
+ # {
333
+ # "foo" : [
334
+ # "bar",
335
+ # "baz"
336
+ # ],
337
+ # "bat" : {
338
+ # "bam" : 0,
339
+ # "bad" : 1
340
+ # }
341
+ # }
342
+ #
172
343
  # == \JSON Additions
173
344
  #
174
345
  # When you "round trip" a non-\String object from Ruby to \JSON and back,
@@ -2,7 +2,6 @@
2
2
  unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED
3
3
  require 'json'
4
4
  end
5
- defined?(::Complex) or require 'complex'
6
5
 
7
6
  class Complex
8
7
 
@@ -2,7 +2,6 @@
2
2
  unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED
3
3
  require 'json'
4
4
  end
5
- defined?(::Rational) or require 'rational'
6
5
 
7
6
  class Rational
8
7
  # Deserializes JSON string by converting numerator value <tt>n</tt>,
@@ -4,13 +4,15 @@ require 'json/generic_object'
4
4
 
5
5
  module JSON
6
6
  class << self
7
- # If +object+ is a
8
- # {String-convertible object}[doc/implicit_conversion_rdoc.html#label-String-Convertible+Objects]
9
- # (implementing +to_str+), calls JSON.parse with +object+ and +opts+:
7
+ # :call-seq:
8
+ # JSON[object] -> new_array or new_string
9
+ #
10
+ # If +object+ is a \String,
11
+ # calls JSON.parse with +object+ and +opts+ (see method #parse):
10
12
  # json = '[0, 1, null]'
11
13
  # JSON[json]# => [0, 1, nil]
12
14
  #
13
- # Otherwise, calls JSON.generate with +object+ and +opts+:
15
+ # Otherwise, calls JSON.generate with +object+ and +opts+ (see method #generate):
14
16
  # ruby = [0, 1, nil]
15
17
  # JSON[ruby] # => '[0,1,null]'
16
18
  def [](object, opts = {})
@@ -144,15 +146,12 @@ module JSON
144
146
  # :call-seq:
145
147
  # JSON.parse(source, opts) -> object
146
148
  #
147
- # Argument +source+ contains the \String to be parsed. It must be a
148
- # {String-convertible object}[doc/implicit_conversion_rdoc.html#label-String-Convertible+Objects]
149
- # (implementing +to_str+), and must contain valid \JSON data.
149
+ # Returns the Ruby objects created by parsing the given +source+.
150
150
  #
151
- # Argument +opts+, if given, contains options for the parsing, and must be a
152
- # {Hash-convertible object}[doc/implicit_conversion_rdoc.html#label-Hash-Convertible+Objects]
153
- # (implementing +to_hash+).
151
+ # Argument +source+ contains the \String to be parsed.
154
152
  #
155
- # Returns the Ruby objects created by parsing the given +source+.
153
+ # Argument +opts+, if given, contains a \Hash of options for the parsing.
154
+ # See {Parsing Options}[#module-JSON-label-Parsing+Options].
156
155
  #
157
156
  # ---
158
157
  #
@@ -171,91 +170,24 @@ module JSON
171
170
  # For examples of parsing for all \JSON data types, see
172
171
  # {Parsing \JSON}[#module-JSON-label-Parsing+JSON].
173
172
  #
174
- # ====== Input Options
175
- #
176
- # Option +max_nesting+ (\Integer) specifies the maximum nesting depth allowed;
177
- # defaults to +100+; specify +false+ to disable depth checking.
178
- #
179
- # With the default, +false+:
180
- # source = '[0, [1, [2, [3]]]]'
181
- # ruby = JSON.parse(source)
182
- # ruby # => [0, [1, [2, [3]]]]
183
- # Too deep:
184
- # # Raises JSON::NestingError (nesting of 2 is too deep):
185
- # JSON.parse(source, {max_nesting: 1})
186
- # Bad value:
187
- # # Raises TypeError (wrong argument type Symbol (expected Fixnum)):
188
- # JSON.parse(source, {max_nesting: :foo})
189
- #
190
- # ---
191
- #
192
- # Option +allow_nan+ (boolean) specifies whether to allow
193
- # NaN, Infinity, and MinusInfinity in +source+;
194
- # defaults to +false+.
195
- #
196
- # With the default, +false+:
197
- # # Raises JSON::ParserError (225: unexpected token at '[NaN]'):
198
- # JSON.parse('[NaN]')
199
- # # Raises JSON::ParserError (232: unexpected token at '[Infinity]'):
200
- # JSON.parse('[Infinity]')
201
- # # Raises JSON::ParserError (248: unexpected token at '[-Infinity]'):
202
- # JSON.parse('[-Infinity]')
203
- # Allow:
204
- # source = '[NaN, Infinity, -Infinity]'
205
- # ruby = JSON.parse(source, {allow_nan: true})
206
- # ruby # => [NaN, Infinity, -Infinity]
207
- #
208
- # ====== Output Options
209
- #
210
- # Option +symbolize_names+ (boolean) specifies whether returned \Hash keys
211
- # should be Symbols;
212
- # defaults to +false+ (use Strings).
213
- #
214
- # With the default, +false+:
215
- # source = '{"a": "foo", "b": 1.0, "c": true, "d": false, "e": null}'
216
- # ruby = JSON.parse(source)
217
- # ruby # => {"a"=>"foo", "b"=>1.0, "c"=>true, "d"=>false, "e"=>nil}
218
- # Use Symbols:
219
- # ruby = JSON.parse(source, {symbolize_names: true})
220
- # ruby # => {:a=>"foo", :b=>1.0, :c=>true, :d=>false, :e=>nil}
221
- #
222
- # ---
223
- #
224
- # Option +object_class+ (\Class) specifies the Ruby class to be used
225
- # for each \JSON object;
226
- # defaults to \Hash.
227
- #
228
- # With the default, \Hash:
229
- # source = '{"a": "foo", "b": 1.0, "c": true, "d": false, "e": null}'
230
- # ruby = JSON.parse(source)
231
- # ruby.class # => Hash
232
- # Use class \OpenStruct:
233
- # ruby = JSON.parse(source, {object_class: OpenStruct})
234
- # ruby # => #<OpenStruct a="foo", b=1.0, c=true, d=false, e=nil>
235
- #
236
- # ---
237
- #
238
- # Option +array_class+ (\Class) specifies the Ruby class to be used
239
- # for each \JSON array;
240
- # defaults to \Array.
241
- #
242
- # With the default, \Array:
243
- # source = '["foo", 1.0, true, false, null]'
173
+ # Parses nested JSON objects:
174
+ # source = <<-EOT
175
+ # {
176
+ # "name": "Dave",
177
+ # "age" :40,
178
+ # "hats": [
179
+ # "Cattleman's",
180
+ # "Panama",
181
+ # "Tophat"
182
+ # ]
183
+ # }
184
+ # EOT
244
185
  # ruby = JSON.parse(source)
245
- # ruby.class # => Array
246
- # Use class \Set:
247
- # ruby = JSON.parse(source, {array_class: Set})
248
- # ruby # => #<Set: {"foo", 1.0, true, false, nil}>
186
+ # ruby # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]}
249
187
  #
250
188
  # ---
251
189
  #
252
- # Option +create_additions+ (boolean) specifies whether to use \JSON additions in parsing.
253
- # See {\JSON Additions}[#module-JSON-label-JSON+Additions].
254
- #
255
- # ====== Exceptions
256
- #
257
190
  # Raises an exception if +source+ is not valid JSON:
258
- #
259
191
  # # Raises JSON::ParserError (783: unexpected token at ''):
260
192
  # JSON.parse('')
261
193
  #
@@ -283,30 +215,47 @@ module JSON
283
215
  end
284
216
 
285
217
  # :call-seq:
286
- # JSON.generate(obj, opts = nil) -> new_string
218
+ # JSON.load_file(path, opts={}) -> object
287
219
  #
288
- # Argument +obj+ is the Ruby object to be converted to \JSON.
220
+ # Calls:
221
+ # parse(File.read(path), opts)
289
222
  #
290
- # Argument +opts+, if given, contains options for the generation, and must be a
291
- # {Hash-convertible object}[doc/implicit_conversion_rdoc.html#label-Hash-Convertible+Objects]
292
- # (implementing +to_hash+).
223
+ # See method #parse.
224
+ def load_file(filespec, opts = {})
225
+ parse(File.read(filespec), opts)
226
+ end
227
+
228
+ # :call-seq:
229
+ # JSON.load_file!(path, opts = {})
230
+ #
231
+ # Calls:
232
+ # JSON.parse!(File.read(path, opts))
233
+ #
234
+ # See method #parse!
235
+ def load_file!(filespec, opts = {})
236
+ parse!(File.read(filespec), opts)
237
+ end
238
+
239
+ # :call-seq:
240
+ # JSON.generate(obj, opts = nil) -> new_string
293
241
  #
294
242
  # Returns a \String containing the generated \JSON data.
295
243
  #
296
244
  # See also JSON.fast_generate, JSON.pretty_generate.
297
245
  #
246
+ # Argument +obj+ is the Ruby object to be converted to \JSON.
247
+ #
248
+ # Argument +opts+, if given, contains a \Hash of options for the generation.
249
+ # See {Generating Options}[#module-JSON-label-Generating+Options].
250
+ #
298
251
  # ---
299
252
  #
300
- # When +obj+ is an
301
- # {Array-convertible object}[doc/implicit_conversion_rdoc.html#label-Array-Convertible+Objects]
302
- # (implementing +to_ary+), returns a \String containing a \JSON array:
253
+ # When +obj+ is an \Array, returns a \String containing a \JSON array:
303
254
  # obj = ["foo", 1.0, true, false, nil]
304
255
  # json = JSON.generate(obj)
305
256
  # json # => '["foo",1.0,true,false,null]'
306
257
  #
307
- # When +obj+ is a
308
- # {Hash-convertible object}[doc/implicit_conversion_rdoc.html#label-Hash-Convertible+Objects],
309
- # return a \String containing a \JSON object:
258
+ # When +obj+ is a \Hash, returns a \String containing a \JSON object:
310
259
  # obj = {foo: 0, bar: 's', baz: :bat}
311
260
  # json = JSON.generate(obj)
312
261
  # json # => '{"foo":0,"bar":"s","baz":"bat"}'
@@ -314,98 +263,10 @@ module JSON
314
263
  # For examples of generating from other Ruby objects, see
315
264
  # {Generating \JSON from Other Objects}[#module-JSON-label-Generating+JSON+from+Other+Objects].
316
265
  #
317
- # ====== Input Options
318
- #
319
- # Option +allow_nan+ (boolean) specifies whether
320
- # +NaN+, +Infinity+, and <tt>-Infinity</tt> may be generated;
321
- # defaults to +false+.
322
- #
323
- # With the default, +false+:
324
- # # Raises JSON::GeneratorError (920: NaN not allowed in JSON):
325
- # JSON.generate(JSON::NaN)
326
- # # Raises JSON::GeneratorError (917: Infinity not allowed in JSON):
327
- # JSON.generate(JSON::Infinity)
328
- # # Raises JSON::GeneratorError (917: -Infinity not allowed in JSON):
329
- # JSON.generate(JSON::MinusInfinity)
330
- #
331
- # Allow:
332
- # ruby = [Float::NaN, Float::Infinity, Float::MinusInfinity]
333
- # JSON.generate(ruby, allow_nan: true) # => '[NaN,Infinity,-Infinity]'
334
- #
335
- # ---
336
- #
337
- # Option +max_nesting+ (\Integer) specifies the maximum nesting depth
338
- # in +obj+; defaults to +100+.
339
- #
340
- # With the default, +100+:
341
- # obj = [[[[[[0]]]]]]
342
- # JSON.generate(obj) # => '[[[[[[0]]]]]]'
343
- #
344
- # Too deep:
345
- # # Raises JSON::NestingError (nesting of 2 is too deep):
346
- # JSON.generate(obj, max_nesting: 2)
347
- #
348
- # ====== Output Options
349
- #
350
- # The default formatting options generate the most compact
351
- # \JSON data, all on one line and with no whitespace.
352
- #
353
- # You can use these formatting options to generate
354
- # \JSON data in a more open format, using whitespace.
355
- # See also JSON.pretty_generate.
356
- #
357
- # - Option +array_nl+ (\String) specifies a string (usually a newline)
358
- # to be inserted after each \JSON array; defaults to the empty \String, <tt>''</tt>.
359
- # - Option +object_nl+ (\String) specifies a string (usually a newline)
360
- # to be inserted after each \JSON object; defaults to the empty \String, <tt>''</tt>.
361
- # - Option +indent+ (\String) specifies the string (usually spaces) to be
362
- # used for indentation; defaults to the empty \String, <tt>''</tt>;
363
- # defaults to the empty \String, <tt>''</tt>;
364
- # has no effect unless options +array_nl+ or +object_nl+ specify newlines.
365
- # - Option +space+ (\String) specifies a string (usually a space) to be
366
- # inserted after the colon in each \JSON object's pair;
367
- # defaults to the empty \String, <tt>''</tt>.
368
- # - Option +space_before+ (\String) specifies a string (usually a space) to be
369
- # inserted before the colon in each \JSON object's pair;
370
- # defaults to the empty \String, <tt>''</tt>.
371
- #
372
- # In this example, +obj+ is used first to generate the shortest
373
- # \JSON data (no whitespace), then again with all formatting options
374
- # specified:
375
- #
376
- # obj = {foo: [:bar, :baz], bat: {bam: 0, bad: 1}}
377
- # json = JSON.generate(obj)
378
- # puts 'Compact:', json
379
- # opts = {
380
- # array_nl: "\n",
381
- # object_nl: "\n",
382
- # indent+: ' ',
383
- # space_before: ' ',
384
- # space: ' '
385
- # }
386
- # puts 'Open:', JSON.generate(obj, opts)
387
- #
388
- # Output:
389
- # Compact:
390
- # {"foo":["bar","baz"],"bat":{"bam":0,"bad":1}}
391
- # Open:
392
- # {
393
- # "foo" : [
394
- # "bar",
395
- # "baz"
396
- # ],
397
- # "bat" : {
398
- # "bam" : 0,
399
- # "bad" : 1
400
- # }
401
- # }
402
- #
403
266
  # ---
404
267
  #
405
268
  # Raises an exception if any formatting option is not a \String.
406
269
  #
407
- # ====== Exceptions
408
- #
409
270
  # Raises an exception if +obj+ contains circular references:
410
271
  # a = []; b = []; a.push(b); b.push(a)
411
272
  # # Raises JSON::NestingError (nesting of 100 is too deep):
@@ -437,6 +298,9 @@ module JSON
437
298
  module_function :unparse
438
299
  # :startdoc:
439
300
 
301
+ # :call-seq:
302
+ # JSON.fast_generate(obj, opts) -> new_string
303
+ #
440
304
  # Arguments +obj+ and +opts+ here are the same as
441
305
  # arguments +obj+ and +opts+ in JSON.generate.
442
306
  #
@@ -541,20 +405,134 @@ module JSON
541
405
  :create_additions => true,
542
406
  }
543
407
 
544
- # Load a ruby data structure from a JSON _source_ and return it. A source can
545
- # either be a string-like object, an IO-like object, or an object responding
546
- # to the read method. If _proc_ was given, it will be called with any nested
547
- # Ruby object as an argument recursively in depth first order. To modify the
548
- # default options pass in the optional _options_ argument as well.
408
+ # :call-seq:
409
+ # JSON.load(source, proc = nil, options = {}) -> object
549
410
  #
550
- # BEWARE: This method is meant to serialise data from trusted user input,
551
- # like from your own database server or clients under your control, it could
552
- # be dangerous to allow untrusted users to pass JSON sources into it. The
553
- # default options for the parser can be changed via the load_default_options
554
- # method.
411
+ # Returns the Ruby objects created by parsing the given +source+.
412
+ #
413
+ # - Argument +source+ must be, or be convertible to, a \String:
414
+ # - If +source+ responds to instance method +to_str+,
415
+ # <tt>source.to_str</tt> becomes the source.
416
+ # - If +source+ responds to instance method +to_io+,
417
+ # <tt>source.to_io.read</tt> becomes the source.
418
+ # - If +source+ responds to instance method +read+,
419
+ # <tt>source.read</tt> becomes the source.
420
+ # - If both of the following are true, source becomes the \String <tt>'null'</tt>:
421
+ # - Option +allow_blank+ specifies a truthy value.
422
+ # - The source, as defined above, is +nil+ or the empty \String <tt>''</tt>.
423
+ # - Otherwise, +source+ remains the source.
424
+ # - Argument +proc+, if given, must be a \Proc that accepts one argument.
425
+ # It will be called recursively with each result (depth-first order).
426
+ # See details below.
427
+ # BEWARE: This method is meant to serialise data from trusted user input,
428
+ # like from your own database server or clients under your control, it could
429
+ # be dangerous to allow untrusted users to pass JSON sources into it.
430
+ # - Argument +opts+, if given, contains a \Hash of options for the parsing.
431
+ # See {Parsing Options}[#module-JSON-label-Parsing+Options].
432
+ # The default options can be changed via method JSON.load_default_options=.
433
+ #
434
+ # ---
435
+ #
436
+ # When no +proc+ is given, modifies +source+ as above and returns the result of
437
+ # <tt>parse(source, opts)</tt>; see #parse.
438
+ #
439
+ # Source for following examples:
440
+ # source = <<-EOT
441
+ # {
442
+ # "name": "Dave",
443
+ # "age" :40,
444
+ # "hats": [
445
+ # "Cattleman's",
446
+ # "Panama",
447
+ # "Tophat"
448
+ # ]
449
+ # }
450
+ # EOT
451
+ #
452
+ # Load a \String:
453
+ # ruby = JSON.load(source)
454
+ # ruby # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]}
455
+ #
456
+ # Load an \IO object:
457
+ # require 'stringio'
458
+ # object = JSON.load(StringIO.new(source))
459
+ # object # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]}
460
+ #
461
+ # Load a \File object:
462
+ # path = 't.json'
463
+ # File.write(path, source)
464
+ # File.open(path) do |file|
465
+ # JSON.load(file)
466
+ # end # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]}
467
+ #
468
+ # ---
469
+ #
470
+ # When +proc+ is given:
471
+ # - Modifies +source+ as above.
472
+ # - Gets the +result+ from calling <tt>parse(source, opts)</tt>.
473
+ # - Recursively calls <tt>proc(result)</tt>.
474
+ # - Returns the final result.
475
+ #
476
+ # Example:
477
+ # require 'json'
478
+ #
479
+ # # Some classes for the example.
480
+ # class Base
481
+ # def initialize(attributes)
482
+ # @attributes = attributes
483
+ # end
484
+ # end
485
+ # class User < Base; end
486
+ # class Account < Base; end
487
+ # class Admin < Base; end
488
+ # # The JSON source.
489
+ # json = <<-EOF
490
+ # {
491
+ # "users": [
492
+ # {"type": "User", "username": "jane", "email": "jane@example.com"},
493
+ # {"type": "User", "username": "john", "email": "john@example.com"}
494
+ # ],
495
+ # "accounts": [
496
+ # {"account": {"type": "Account", "paid": true, "account_id": "1234"}},
497
+ # {"account": {"type": "Account", "paid": false, "account_id": "1235"}}
498
+ # ],
499
+ # "admins": {"type": "Admin", "password": "0wn3d"}
500
+ # }
501
+ # EOF
502
+ # # Deserializer method.
503
+ # def deserialize_obj(obj, safe_types = %w(User Account Admin))
504
+ # type = obj.is_a?(Hash) && obj["type"]
505
+ # safe_types.include?(type) ? Object.const_get(type).new(obj) : obj
506
+ # end
507
+ # # Call to JSON.load
508
+ # ruby = JSON.load(json, proc {|obj|
509
+ # case obj
510
+ # when Hash
511
+ # obj.each {|k, v| obj[k] = deserialize_obj v }
512
+ # when Array
513
+ # obj.map! {|v| deserialize_obj v }
514
+ # end
515
+ # })
516
+ # pp ruby
517
+ # Output:
518
+ # {"users"=>
519
+ # [#<User:0x00000000064c4c98
520
+ # @attributes=
521
+ # {"type"=>"User", "username"=>"jane", "email"=>"jane@example.com"}>,
522
+ # #<User:0x00000000064c4bd0
523
+ # @attributes=
524
+ # {"type"=>"User", "username"=>"john", "email"=>"john@example.com"}>],
525
+ # "accounts"=>
526
+ # [{"account"=>
527
+ # #<Account:0x00000000064c4928
528
+ # @attributes={"type"=>"Account", "paid"=>true, "account_id"=>"1234"}>},
529
+ # {"account"=>
530
+ # #<Account:0x00000000064c4680
531
+ # @attributes={"type"=>"Account", "paid"=>false, "account_id"=>"1235"}>}],
532
+ # "admins"=>
533
+ # #<Admin:0x00000000064c41f8
534
+ # @attributes={"type"=>"Admin", "password"=>"0wn3d"}>}
555
535
  #
556
- # This method is part of the implementation of the load/dump interface of
557
- # Marshal and YAML.
558
536
  def load(source, proc = nil, options = {})
559
537
  opts = load_default_options.merge options
560
538
  if source.respond_to? :to_str
@@ -573,7 +551,7 @@ module JSON
573
551
  end
574
552
 
575
553
  # Recursively calls passed _Proc_ if the parsed data structure is an _Array_ or _Hash_
576
- def recurse_proc(result, &proc)
554
+ def recurse_proc(result, &proc) # :nodoc:
577
555
  case result
578
556
  when Array
579
557
  result.each { |x| recurse_proc x, &proc }
@@ -593,29 +571,42 @@ module JSON
593
571
  # Sets or returns the default options for the JSON.dump method.
594
572
  # Initially:
595
573
  # opts = JSON.dump_default_options
596
- # opts # => {:max_nesting=>false, :allow_nan=>true}
574
+ # opts # => {:max_nesting=>false, :allow_nan=>true, :escape_slash=>false}
597
575
  attr_accessor :dump_default_options
598
576
  end
599
577
  self.dump_default_options = {
600
578
  :max_nesting => false,
601
579
  :allow_nan => true,
580
+ :escape_slash => false,
602
581
  }
603
582
 
604
- # Dumps _obj_ as a JSON string, i.e. calls generate on the object and returns
605
- # the result.
583
+ # :call-seq:
584
+ # JSON.dump(obj, io = nil, limit = nil)
606
585
  #
607
- # If anIO (an IO-like object or an object that responds to the write method)
608
- # was given, the resulting JSON is written to it.
586
+ # Dumps +obj+ as a \JSON string, i.e. calls generate on the object and returns the result.
609
587
  #
610
- # If the number of nested arrays or objects exceeds _limit_, an ArgumentError
611
- # exception is raised. This argument is similar (but not exactly the
612
- # same!) to the _limit_ argument in Marshal.dump.
588
+ # The default options can be changed via method JSON.dump_default_options.
613
589
  #
614
- # The default options for the generator can be changed via the
615
- # dump_default_options method.
590
+ # - Argument +io+, if given, should respond to method +write+;
591
+ # the \JSON \String is written to +io+, and +io+ is returned.
592
+ # If +io+ is not given, the \JSON \String is returned.
593
+ # - Argument +limit+, if given, is passed to JSON.generate as option +max_nesting+.
616
594
  #
617
- # This method is part of the implementation of the load/dump interface of
618
- # Marshal and YAML.
595
+ # ---
596
+ #
597
+ # When argument +io+ is not given, returns the \JSON \String generated from +obj+:
598
+ # obj = {foo: [0, 1], bar: {baz: 2, bat: 3}, bam: :bad}
599
+ # json = JSON.dump(obj)
600
+ # json # => "{\"foo\":[0,1],\"bar\":{\"baz\":2,\"bat\":3},\"bam\":\"bad\"}"
601
+ #
602
+ # When argument +io+ is given, writes the \JSON \String to +io+ and returns +io+:
603
+ # path = 't.json'
604
+ # File.open(path, 'w') do |file|
605
+ # JSON.dump(obj, file)
606
+ # end # => #<File:t.json (closed)>
607
+ # puts File.read(path)
608
+ # Output:
609
+ # {"foo":[0,1],"bar":{"baz":2,"bat":3},"bam":"bad"}
619
610
  def dump(obj, anIO = nil, limit = nil)
620
611
  if anIO and limit.nil?
621
612
  anIO = anIO.to_io if anIO.respond_to?(:to_io)