json 2.7.2 → 2.8.2
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/BSDL +22 -0
- data/CHANGES.md +73 -17
- data/LEGAL +60 -0
- data/README.md +15 -236
- data/ext/json/ext/fbuffer/fbuffer.h +76 -79
- data/ext/json/ext/generator/extconf.rb +8 -2
- data/ext/json/ext/generator/generator.c +776 -816
- data/ext/json/ext/parser/extconf.rb +7 -27
- data/ext/json/ext/parser/parser.c +1697 -670
- data/ext/json/ext/parser/parser.rl +832 -338
- data/json.gemspec +45 -49
- data/lib/json/add/bigdecimal.rb +2 -2
- data/lib/json/add/complex.rb +1 -1
- data/lib/json/add/core.rb +1 -1
- data/lib/json/add/date.rb +1 -1
- data/lib/json/add/date_time.rb +1 -1
- data/lib/json/add/exception.rb +1 -1
- data/lib/json/add/ostruct.rb +1 -1
- data/lib/json/add/range.rb +1 -1
- data/lib/json/add/rational.rb +1 -1
- data/lib/json/add/regexp.rb +1 -1
- data/lib/json/add/struct.rb +1 -1
- data/lib/json/add/symbol.rb +1 -2
- data/lib/json/add/time.rb +3 -10
- data/lib/json/common.rb +273 -95
- data/lib/json/ext/generator/state.rb +105 -0
- data/lib/json/ext.rb +13 -5
- data/lib/json/generic_object.rb +1 -1
- data/lib/json/{pure → truffle_ruby}/generator.rb +228 -120
- data/lib/json/version.rb +3 -7
- data/lib/json.rb +16 -21
- metadata +19 -21
- data/ext/json/ext/generator/depend +0 -1
- data/ext/json/ext/generator/generator.h +0 -177
- data/ext/json/ext/parser/depend +0 -1
- data/ext/json/ext/parser/parser.h +0 -96
- data/ext/json/extconf.rb +0 -3
- data/lib/json/pure/parser.rb +0 -337
- data/lib/json/pure.rb +0 -15
- /data/{LICENSE → COPYING} +0 -0
data/lib/json/common.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
|
-
#frozen_string_literal:
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require 'json/version'
|
3
4
|
|
4
5
|
module JSON
|
@@ -20,16 +21,19 @@ module JSON
|
|
20
21
|
# ruby = [0, 1, nil]
|
21
22
|
# JSON[ruby] # => '[0,1,null]'
|
22
23
|
def [](object, opts = {})
|
23
|
-
if object.
|
24
|
-
JSON.parse(object
|
25
|
-
|
26
|
-
|
24
|
+
if object.is_a?(String)
|
25
|
+
return JSON.parse(object, opts)
|
26
|
+
elsif object.respond_to?(:to_str)
|
27
|
+
str = object.to_str
|
28
|
+
if str.is_a?(String)
|
29
|
+
return JSON.parse(str, opts)
|
30
|
+
end
|
27
31
|
end
|
32
|
+
|
33
|
+
JSON.generate(object, opts)
|
28
34
|
end
|
29
35
|
|
30
|
-
# Returns the JSON parser class that is used by JSON.
|
31
|
-
# JSON::Ext::Parser or JSON::Pure::Parser:
|
32
|
-
# JSON.parser # => JSON::Ext::Parser
|
36
|
+
# Returns the JSON parser class that is used by JSON.
|
33
37
|
attr_reader :parser
|
34
38
|
|
35
39
|
# Set the JSON parser class _parser_ to be used by JSON.
|
@@ -44,18 +48,9 @@ module JSON
|
|
44
48
|
# level (absolute namespace path?). If there doesn't exist a constant at
|
45
49
|
# the given path, an ArgumentError is raised.
|
46
50
|
def deep_const_get(path) # :nodoc:
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
when p.const_defined?(c, true) then p.const_get(c)
|
51
|
-
else
|
52
|
-
begin
|
53
|
-
p.const_missing(c)
|
54
|
-
rescue NameError => e
|
55
|
-
raise ArgumentError, "can't get const #{path}: #{e}"
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
51
|
+
Object.const_get(path)
|
52
|
+
rescue NameError => e
|
53
|
+
raise ArgumentError, "can't get const #{path}: #{e}"
|
59
54
|
end
|
60
55
|
|
61
56
|
# Set the module _generator_ to be used by JSON.
|
@@ -64,7 +59,7 @@ module JSON
|
|
64
59
|
@generator = generator
|
65
60
|
generator_methods = generator::GeneratorMethods
|
66
61
|
for const in generator_methods.constants
|
67
|
-
klass =
|
62
|
+
klass = const_get(const)
|
68
63
|
modul = generator_methods.const_get(const)
|
69
64
|
klass.class_eval do
|
70
65
|
instance_methods(false).each do |m|
|
@@ -101,34 +96,24 @@ module JSON
|
|
101
96
|
)
|
102
97
|
end
|
103
98
|
|
104
|
-
# Returns the JSON generator module that is used by JSON.
|
105
|
-
# either JSON::Ext::Generator or JSON::Pure::Generator:
|
106
|
-
# JSON.generator # => JSON::Ext::Generator
|
99
|
+
# Returns the JSON generator module that is used by JSON.
|
107
100
|
attr_reader :generator
|
108
101
|
|
109
|
-
# Sets or Returns the JSON generator state class that is used by JSON.
|
110
|
-
# either JSON::Ext::Generator::State or JSON::Pure::Generator::State:
|
111
|
-
# JSON.state # => JSON::Ext::Generator::State
|
102
|
+
# Sets or Returns the JSON generator state class that is used by JSON.
|
112
103
|
attr_accessor :state
|
113
104
|
end
|
114
105
|
|
115
|
-
DEFAULT_CREATE_ID = 'json_class'.freeze
|
116
|
-
private_constant :DEFAULT_CREATE_ID
|
117
|
-
|
118
|
-
CREATE_ID_TLS_KEY = "JSON.create_id".freeze
|
119
|
-
private_constant :CREATE_ID_TLS_KEY
|
120
|
-
|
121
106
|
# Sets create identifier, which is used to decide if the _json_create_
|
122
107
|
# hook of a class should be called; initial value is +json_class+:
|
123
108
|
# JSON.create_id # => 'json_class'
|
124
109
|
def self.create_id=(new_value)
|
125
|
-
Thread.current[
|
110
|
+
Thread.current[:"JSON.create_id"] = new_value.dup.freeze
|
126
111
|
end
|
127
112
|
|
128
113
|
# Returns the current create identifier.
|
129
114
|
# See also JSON.create_id=.
|
130
115
|
def self.create_id
|
131
|
-
Thread.current[
|
116
|
+
Thread.current[:"JSON.create_id"] || 'json_class'
|
132
117
|
end
|
133
118
|
|
134
119
|
NaN = 0.0/0
|
@@ -196,17 +181,17 @@ module JSON
|
|
196
181
|
# {Parsing \JSON}[#module-JSON-label-Parsing+JSON].
|
197
182
|
#
|
198
183
|
# Parses nested JSON objects:
|
199
|
-
# source =
|
200
|
-
#
|
201
|
-
#
|
202
|
-
#
|
203
|
-
#
|
204
|
-
#
|
205
|
-
#
|
206
|
-
#
|
207
|
-
#
|
208
|
-
#
|
209
|
-
#
|
184
|
+
# source = <<~JSON
|
185
|
+
# {
|
186
|
+
# "name": "Dave",
|
187
|
+
# "age" :40,
|
188
|
+
# "hats": [
|
189
|
+
# "Cattleman's",
|
190
|
+
# "Panama",
|
191
|
+
# "Tophat"
|
192
|
+
# ]
|
193
|
+
# }
|
194
|
+
# JSON
|
210
195
|
# ruby = JSON.parse(source)
|
211
196
|
# ruby # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]}
|
212
197
|
#
|
@@ -216,8 +201,8 @@ module JSON
|
|
216
201
|
# # Raises JSON::ParserError (783: unexpected token at ''):
|
217
202
|
# JSON.parse('')
|
218
203
|
#
|
219
|
-
def parse(source, opts =
|
220
|
-
Parser.
|
204
|
+
def parse(source, opts = nil)
|
205
|
+
Parser.parse(source, opts)
|
221
206
|
end
|
222
207
|
|
223
208
|
# :call-seq:
|
@@ -246,8 +231,8 @@ module JSON
|
|
246
231
|
# parse(File.read(path), opts)
|
247
232
|
#
|
248
233
|
# See method #parse.
|
249
|
-
def load_file(filespec, opts =
|
250
|
-
parse(File.read(filespec), opts)
|
234
|
+
def load_file(filespec, opts = nil)
|
235
|
+
parse(File.read(filespec, encoding: Encoding::UTF_8), opts)
|
251
236
|
end
|
252
237
|
|
253
238
|
# :call-seq:
|
@@ -258,7 +243,7 @@ module JSON
|
|
258
243
|
#
|
259
244
|
# See method #parse!
|
260
245
|
def load_file!(filespec, opts = {})
|
261
|
-
parse!(File.read(filespec), opts)
|
246
|
+
parse!(File.read(filespec, encoding: Encoding::UTF_8), opts)
|
262
247
|
end
|
263
248
|
|
264
249
|
# :call-seq:
|
@@ -299,11 +284,10 @@ module JSON
|
|
299
284
|
#
|
300
285
|
def generate(obj, opts = nil)
|
301
286
|
if State === opts
|
302
|
-
|
287
|
+
opts.generate(obj)
|
303
288
|
else
|
304
|
-
|
289
|
+
State.generate(obj, opts)
|
305
290
|
end
|
306
|
-
state.generate(obj)
|
307
291
|
end
|
308
292
|
|
309
293
|
# :stopdoc:
|
@@ -396,6 +380,20 @@ module JSON
|
|
396
380
|
module_function :pretty_unparse
|
397
381
|
# :startdoc:
|
398
382
|
|
383
|
+
class << self
|
384
|
+
# Sets or returns default options for the JSON.unsafe_load method.
|
385
|
+
# Initially:
|
386
|
+
# opts = JSON.load_default_options
|
387
|
+
# opts # => {:max_nesting=>false, :allow_nan=>true, :allow_blank=>true, :create_additions=>true}
|
388
|
+
attr_accessor :unsafe_load_default_options
|
389
|
+
end
|
390
|
+
self.unsafe_load_default_options = {
|
391
|
+
:max_nesting => false,
|
392
|
+
:allow_nan => true,
|
393
|
+
:allow_blank => true,
|
394
|
+
:create_additions => true,
|
395
|
+
}
|
396
|
+
|
399
397
|
class << self
|
400
398
|
# Sets or returns default options for the JSON.load method.
|
401
399
|
# Initially:
|
@@ -404,11 +402,162 @@ module JSON
|
|
404
402
|
attr_accessor :load_default_options
|
405
403
|
end
|
406
404
|
self.load_default_options = {
|
407
|
-
:max_nesting => false,
|
408
405
|
:allow_nan => true,
|
409
|
-
:allow_blank
|
410
|
-
:create_additions =>
|
406
|
+
:allow_blank => true,
|
407
|
+
:create_additions => nil,
|
411
408
|
}
|
409
|
+
# :call-seq:
|
410
|
+
# JSON.unsafe_load(source, proc = nil, options = {}) -> object
|
411
|
+
#
|
412
|
+
# Returns the Ruby objects created by parsing the given +source+.
|
413
|
+
#
|
414
|
+
# - Argument +source+ must be, or be convertible to, a \String:
|
415
|
+
# - If +source+ responds to instance method +to_str+,
|
416
|
+
# <tt>source.to_str</tt> becomes the source.
|
417
|
+
# - If +source+ responds to instance method +to_io+,
|
418
|
+
# <tt>source.to_io.read</tt> becomes the source.
|
419
|
+
# - If +source+ responds to instance method +read+,
|
420
|
+
# <tt>source.read</tt> becomes the source.
|
421
|
+
# - If both of the following are true, source becomes the \String <tt>'null'</tt>:
|
422
|
+
# - Option +allow_blank+ specifies a truthy value.
|
423
|
+
# - The source, as defined above, is +nil+ or the empty \String <tt>''</tt>.
|
424
|
+
# - Otherwise, +source+ remains the source.
|
425
|
+
# - Argument +proc+, if given, must be a \Proc that accepts one argument.
|
426
|
+
# It will be called recursively with each result (depth-first order).
|
427
|
+
# See details below.
|
428
|
+
# BEWARE: This method is meant to serialise data from trusted user input,
|
429
|
+
# like from your own database server or clients under your control, it could
|
430
|
+
# be dangerous to allow untrusted users to pass JSON sources into it.
|
431
|
+
# - Argument +opts+, if given, contains a \Hash of options for the parsing.
|
432
|
+
# See {Parsing Options}[#module-JSON-label-Parsing+Options].
|
433
|
+
# The default options can be changed via method JSON.unsafe_load_default_options=.
|
434
|
+
#
|
435
|
+
# ---
|
436
|
+
#
|
437
|
+
# When no +proc+ is given, modifies +source+ as above and returns the result of
|
438
|
+
# <tt>parse(source, opts)</tt>; see #parse.
|
439
|
+
#
|
440
|
+
# Source for following examples:
|
441
|
+
# source = <<~JSON
|
442
|
+
# {
|
443
|
+
# "name": "Dave",
|
444
|
+
# "age" :40,
|
445
|
+
# "hats": [
|
446
|
+
# "Cattleman's",
|
447
|
+
# "Panama",
|
448
|
+
# "Tophat"
|
449
|
+
# ]
|
450
|
+
# }
|
451
|
+
# JSON
|
452
|
+
#
|
453
|
+
# Load a \String:
|
454
|
+
# ruby = JSON.unsafe_load(source)
|
455
|
+
# ruby # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]}
|
456
|
+
#
|
457
|
+
# Load an \IO object:
|
458
|
+
# require 'stringio'
|
459
|
+
# object = JSON.unsafe_load(StringIO.new(source))
|
460
|
+
# object # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]}
|
461
|
+
#
|
462
|
+
# Load a \File object:
|
463
|
+
# path = 't.json'
|
464
|
+
# File.write(path, source)
|
465
|
+
# File.open(path) do |file|
|
466
|
+
# JSON.unsafe_load(file)
|
467
|
+
# end # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]}
|
468
|
+
#
|
469
|
+
# ---
|
470
|
+
#
|
471
|
+
# When +proc+ is given:
|
472
|
+
# - Modifies +source+ as above.
|
473
|
+
# - Gets the +result+ from calling <tt>parse(source, opts)</tt>.
|
474
|
+
# - Recursively calls <tt>proc(result)</tt>.
|
475
|
+
# - Returns the final result.
|
476
|
+
#
|
477
|
+
# Example:
|
478
|
+
# require 'json'
|
479
|
+
#
|
480
|
+
# # Some classes for the example.
|
481
|
+
# class Base
|
482
|
+
# def initialize(attributes)
|
483
|
+
# @attributes = attributes
|
484
|
+
# end
|
485
|
+
# end
|
486
|
+
# class User < Base; end
|
487
|
+
# class Account < Base; end
|
488
|
+
# class Admin < Base; end
|
489
|
+
# # The JSON source.
|
490
|
+
# json = <<-EOF
|
491
|
+
# {
|
492
|
+
# "users": [
|
493
|
+
# {"type": "User", "username": "jane", "email": "jane@example.com"},
|
494
|
+
# {"type": "User", "username": "john", "email": "john@example.com"}
|
495
|
+
# ],
|
496
|
+
# "accounts": [
|
497
|
+
# {"account": {"type": "Account", "paid": true, "account_id": "1234"}},
|
498
|
+
# {"account": {"type": "Account", "paid": false, "account_id": "1235"}}
|
499
|
+
# ],
|
500
|
+
# "admins": {"type": "Admin", "password": "0wn3d"}
|
501
|
+
# }
|
502
|
+
# EOF
|
503
|
+
# # Deserializer method.
|
504
|
+
# def deserialize_obj(obj, safe_types = %w(User Account Admin))
|
505
|
+
# type = obj.is_a?(Hash) && obj["type"]
|
506
|
+
# safe_types.include?(type) ? Object.const_get(type).new(obj) : obj
|
507
|
+
# end
|
508
|
+
# # Call to JSON.unsafe_load
|
509
|
+
# ruby = JSON.unsafe_load(json, proc {|obj|
|
510
|
+
# case obj
|
511
|
+
# when Hash
|
512
|
+
# obj.each {|k, v| obj[k] = deserialize_obj v }
|
513
|
+
# when Array
|
514
|
+
# obj.map! {|v| deserialize_obj v }
|
515
|
+
# end
|
516
|
+
# })
|
517
|
+
# pp ruby
|
518
|
+
# Output:
|
519
|
+
# {"users"=>
|
520
|
+
# [#<User:0x00000000064c4c98
|
521
|
+
# @attributes=
|
522
|
+
# {"type"=>"User", "username"=>"jane", "email"=>"jane@example.com"}>,
|
523
|
+
# #<User:0x00000000064c4bd0
|
524
|
+
# @attributes=
|
525
|
+
# {"type"=>"User", "username"=>"john", "email"=>"john@example.com"}>],
|
526
|
+
# "accounts"=>
|
527
|
+
# [{"account"=>
|
528
|
+
# #<Account:0x00000000064c4928
|
529
|
+
# @attributes={"type"=>"Account", "paid"=>true, "account_id"=>"1234"}>},
|
530
|
+
# {"account"=>
|
531
|
+
# #<Account:0x00000000064c4680
|
532
|
+
# @attributes={"type"=>"Account", "paid"=>false, "account_id"=>"1235"}>}],
|
533
|
+
# "admins"=>
|
534
|
+
# #<Admin:0x00000000064c41f8
|
535
|
+
# @attributes={"type"=>"Admin", "password"=>"0wn3d"}>}
|
536
|
+
#
|
537
|
+
def unsafe_load(source, proc = nil, options = nil)
|
538
|
+
opts = if options.nil?
|
539
|
+
unsafe_load_default_options
|
540
|
+
else
|
541
|
+
unsafe_load_default_options.merge(options)
|
542
|
+
end
|
543
|
+
|
544
|
+
unless source.is_a?(String)
|
545
|
+
if source.respond_to? :to_str
|
546
|
+
source = source.to_str
|
547
|
+
elsif source.respond_to? :to_io
|
548
|
+
source = source.to_io.read
|
549
|
+
elsif source.respond_to?(:read)
|
550
|
+
source = source.read
|
551
|
+
end
|
552
|
+
end
|
553
|
+
|
554
|
+
if opts[:allow_blank] && (source.nil? || source.empty?)
|
555
|
+
source = 'null'
|
556
|
+
end
|
557
|
+
result = parse(source, opts)
|
558
|
+
recurse_proc(result, &proc) if proc
|
559
|
+
result
|
560
|
+
end
|
412
561
|
|
413
562
|
# :call-seq:
|
414
563
|
# JSON.load(source, proc = nil, options = {}) -> object
|
@@ -432,6 +581,7 @@ module JSON
|
|
432
581
|
# BEWARE: This method is meant to serialise data from trusted user input,
|
433
582
|
# like from your own database server or clients under your control, it could
|
434
583
|
# be dangerous to allow untrusted users to pass JSON sources into it.
|
584
|
+
# If you must use it, use JSON.unsafe_load instead to make it clear.
|
435
585
|
# - Argument +opts+, if given, contains a \Hash of options for the parsing.
|
436
586
|
# See {Parsing Options}[#module-JSON-label-Parsing+Options].
|
437
587
|
# The default options can be changed via method JSON.load_default_options=.
|
@@ -442,17 +592,17 @@ module JSON
|
|
442
592
|
# <tt>parse(source, opts)</tt>; see #parse.
|
443
593
|
#
|
444
594
|
# Source for following examples:
|
445
|
-
# source =
|
446
|
-
#
|
447
|
-
#
|
448
|
-
#
|
449
|
-
#
|
450
|
-
#
|
451
|
-
#
|
452
|
-
#
|
453
|
-
#
|
454
|
-
#
|
455
|
-
#
|
595
|
+
# source = <<~JSON
|
596
|
+
# {
|
597
|
+
# "name": "Dave",
|
598
|
+
# "age" :40,
|
599
|
+
# "hats": [
|
600
|
+
# "Cattleman's",
|
601
|
+
# "Panama",
|
602
|
+
# "Tophat"
|
603
|
+
# ]
|
604
|
+
# }
|
605
|
+
# JSON
|
456
606
|
#
|
457
607
|
# Load a \String:
|
458
608
|
# ruby = JSON.load(source)
|
@@ -538,15 +688,23 @@ module JSON
|
|
538
688
|
# #<Admin:0x00000000064c41f8
|
539
689
|
# @attributes={"type"=>"Admin", "password"=>"0wn3d"}>}
|
540
690
|
#
|
541
|
-
def load(source, proc = nil, options =
|
542
|
-
opts =
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
691
|
+
def load(source, proc = nil, options = nil)
|
692
|
+
opts = if options.nil?
|
693
|
+
load_default_options
|
694
|
+
else
|
695
|
+
load_default_options.merge(options)
|
696
|
+
end
|
697
|
+
|
698
|
+
unless source.is_a?(String)
|
699
|
+
if source.respond_to? :to_str
|
700
|
+
source = source.to_str
|
701
|
+
elsif source.respond_to? :to_io
|
702
|
+
source = source.to_io.read
|
703
|
+
elsif source.respond_to?(:read)
|
704
|
+
source = source.read
|
705
|
+
end
|
549
706
|
end
|
707
|
+
|
550
708
|
if opts[:allow_blank] && (source.nil? || source.empty?)
|
551
709
|
source = 'null'
|
552
710
|
end
|
@@ -576,13 +734,12 @@ module JSON
|
|
576
734
|
# Sets or returns the default options for the JSON.dump method.
|
577
735
|
# Initially:
|
578
736
|
# opts = JSON.dump_default_options
|
579
|
-
# opts # => {:max_nesting=>false, :allow_nan=>true
|
737
|
+
# opts # => {:max_nesting=>false, :allow_nan=>true}
|
580
738
|
attr_accessor :dump_default_options
|
581
739
|
end
|
582
740
|
self.dump_default_options = {
|
583
741
|
:max_nesting => false,
|
584
742
|
:allow_nan => true,
|
585
|
-
:script_safe => false,
|
586
743
|
}
|
587
744
|
|
588
745
|
# :call-seq:
|
@@ -613,26 +770,42 @@ module JSON
|
|
613
770
|
# Output:
|
614
771
|
# {"foo":[0,1],"bar":{"baz":2,"bat":3},"bam":"bad"}
|
615
772
|
def dump(obj, anIO = nil, limit = nil, kwargs = nil)
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
773
|
+
if kwargs.nil?
|
774
|
+
if limit.nil?
|
775
|
+
if anIO.is_a?(Hash)
|
776
|
+
kwargs = anIO
|
777
|
+
anIO = nil
|
778
|
+
end
|
779
|
+
elsif limit.is_a?(Hash)
|
780
|
+
kwargs = limit
|
781
|
+
limit = nil
|
782
|
+
end
|
623
783
|
end
|
784
|
+
|
785
|
+
unless anIO.nil?
|
786
|
+
if anIO.respond_to?(:to_io)
|
787
|
+
anIO = anIO.to_io
|
788
|
+
elsif limit.nil? && !anIO.respond_to?(:write)
|
789
|
+
anIO, limit = nil, anIO
|
790
|
+
end
|
791
|
+
end
|
792
|
+
|
624
793
|
opts = JSON.dump_default_options
|
625
794
|
opts = opts.merge(:max_nesting => limit) if limit
|
626
795
|
opts = merge_dump_options(opts, **kwargs) if kwargs
|
627
|
-
|
628
|
-
|
796
|
+
|
797
|
+
result = begin
|
798
|
+
generate(obj, opts)
|
799
|
+
rescue JSON::NestingError
|
800
|
+
raise ArgumentError, "exceed depth limit"
|
801
|
+
end
|
802
|
+
|
803
|
+
if anIO.nil?
|
804
|
+
result
|
805
|
+
else
|
629
806
|
anIO.write result
|
630
807
|
anIO
|
631
|
-
else
|
632
|
-
result
|
633
808
|
end
|
634
|
-
rescue JSON::NestingError
|
635
|
-
raise ArgumentError, "exceed depth limit"
|
636
809
|
end
|
637
810
|
|
638
811
|
# Encodes string using String.encode.
|
@@ -678,11 +851,16 @@ module ::Kernel
|
|
678
851
|
# The _opts_ argument is passed through to generate/parse respectively. See
|
679
852
|
# generate and parse for their documentation.
|
680
853
|
def JSON(object, *args)
|
681
|
-
if object.
|
682
|
-
JSON.parse(object
|
683
|
-
|
684
|
-
|
854
|
+
if object.is_a?(String)
|
855
|
+
return JSON.parse(object, args.first)
|
856
|
+
elsif object.respond_to?(:to_str)
|
857
|
+
str = object.to_str
|
858
|
+
if str.is_a?(String)
|
859
|
+
return JSON.parse(object.to_str, args.first)
|
860
|
+
end
|
685
861
|
end
|
862
|
+
|
863
|
+
JSON.generate(object, args.first)
|
686
864
|
end
|
687
865
|
end
|
688
866
|
|
@@ -0,0 +1,105 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module JSON
|
4
|
+
module Ext
|
5
|
+
module Generator
|
6
|
+
class State
|
7
|
+
# call-seq: new(opts = {})
|
8
|
+
#
|
9
|
+
# Instantiates a new State object, configured by _opts_.
|
10
|
+
#
|
11
|
+
# _opts_ can have the following keys:
|
12
|
+
#
|
13
|
+
# * *indent*: a string used to indent levels (default: ''),
|
14
|
+
# * *space*: a string that is put after, a : or , delimiter (default: ''),
|
15
|
+
# * *space_before*: a string that is put before a : pair delimiter (default: ''),
|
16
|
+
# * *object_nl*: a string that is put at the end of a JSON object (default: ''),
|
17
|
+
# * *array_nl*: a string that is put at the end of a JSON array (default: ''),
|
18
|
+
# * *allow_nan*: true if NaN, Infinity, and -Infinity should be
|
19
|
+
# generated, otherwise an exception is thrown, if these values are
|
20
|
+
# encountered. This options defaults to false.
|
21
|
+
# * *ascii_only*: true if only ASCII characters should be generated. This
|
22
|
+
# option defaults to false.
|
23
|
+
# * *buffer_initial_length*: sets the initial length of the generator's
|
24
|
+
# internal buffer.
|
25
|
+
def initialize(opts = nil)
|
26
|
+
if opts && !opts.empty?
|
27
|
+
configure(opts)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# call-seq: configure(opts)
|
32
|
+
#
|
33
|
+
# Configure this State instance with the Hash _opts_, and return
|
34
|
+
# itself.
|
35
|
+
def configure(opts)
|
36
|
+
unless opts.is_a?(Hash)
|
37
|
+
if opts.respond_to?(:to_hash)
|
38
|
+
opts = opts.to_hash
|
39
|
+
elsif opts.respond_to?(:to_h)
|
40
|
+
opts = opts.to_h
|
41
|
+
else
|
42
|
+
raise TypeError, "can't convert #{opts.class} into Hash"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
_configure(opts)
|
46
|
+
end
|
47
|
+
|
48
|
+
alias_method :merge, :configure
|
49
|
+
|
50
|
+
# call-seq: to_h
|
51
|
+
#
|
52
|
+
# Returns the configuration instance variables as a hash, that can be
|
53
|
+
# passed to the configure method.
|
54
|
+
def to_h
|
55
|
+
result = {
|
56
|
+
indent: indent,
|
57
|
+
space: space,
|
58
|
+
space_before: space_before,
|
59
|
+
object_nl: object_nl,
|
60
|
+
array_nl: array_nl,
|
61
|
+
allow_nan: allow_nan?,
|
62
|
+
ascii_only: ascii_only?,
|
63
|
+
max_nesting: max_nesting,
|
64
|
+
script_safe: script_safe?,
|
65
|
+
strict: strict?,
|
66
|
+
depth: depth,
|
67
|
+
buffer_initial_length: buffer_initial_length,
|
68
|
+
}
|
69
|
+
|
70
|
+
instance_variables.each do |iv|
|
71
|
+
iv = iv.to_s[1..-1]
|
72
|
+
result[iv.to_sym] = self[iv]
|
73
|
+
end
|
74
|
+
|
75
|
+
result
|
76
|
+
end
|
77
|
+
|
78
|
+
alias_method :to_hash, :to_h
|
79
|
+
|
80
|
+
# call-seq: [](name)
|
81
|
+
#
|
82
|
+
# Returns the value returned by method +name+.
|
83
|
+
def [](name)
|
84
|
+
if respond_to?(name)
|
85
|
+
__send__(name)
|
86
|
+
else
|
87
|
+
instance_variable_get("@#{name}") if
|
88
|
+
instance_variables.include?("@#{name}".to_sym) # avoid warning
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
# call-seq: []=(name, value)
|
93
|
+
#
|
94
|
+
# Sets the attribute name to value.
|
95
|
+
def []=(name, value)
|
96
|
+
if respond_to?(name_writer = "#{name}=")
|
97
|
+
__send__ name_writer, value
|
98
|
+
else
|
99
|
+
instance_variable_set "@#{name}", value
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
data/lib/json/ext.rb
CHANGED
@@ -1,14 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'json/common'
|
2
4
|
|
3
5
|
module JSON
|
4
6
|
# This module holds all the modules/classes that implement JSON's
|
5
7
|
# functionality as C extensions.
|
6
8
|
module Ext
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
if RUBY_ENGINE == 'truffleruby'
|
10
|
+
require 'json/ext/parser'
|
11
|
+
require 'json/truffle_ruby/generator'
|
12
|
+
JSON.parser = Parser
|
13
|
+
JSON.generator = ::JSON::TruffleRuby::Generator
|
14
|
+
else
|
15
|
+
require 'json/ext/parser'
|
16
|
+
require 'json/ext/generator'
|
17
|
+
JSON.parser = Parser
|
18
|
+
JSON.generator = Generator
|
19
|
+
end
|
12
20
|
end
|
13
21
|
|
14
22
|
JSON_LOADED = true unless defined?(::JSON::JSON_LOADED)
|
data/lib/json/generic_object.rb
CHANGED