piko-lite-mod 0.0.1

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.

Potentially problematic release.


This version of piko-lite-mod might be problematic. Click here for more details.

Files changed (42) hide show
  1. checksums.yaml +7 -0
  2. data/json-2.21.1/BSDL +22 -0
  3. data/json-2.21.1/CHANGES.md +810 -0
  4. data/json-2.21.1/COPYING +56 -0
  5. data/json-2.21.1/LEGAL +20 -0
  6. data/json-2.21.1/README.md +308 -0
  7. data/json-2.21.1/ext/json/ext/fbuffer/fbuffer.h +259 -0
  8. data/json-2.21.1/ext/json/ext/generator/extconf.rb +19 -0
  9. data/json-2.21.1/ext/json/ext/generator/generator.c +2066 -0
  10. data/json-2.21.1/ext/json/ext/json.h +183 -0
  11. data/json-2.21.1/ext/json/ext/parser/extconf.rb +37 -0
  12. data/json-2.21.1/ext/json/ext/parser/parser.c +2917 -0
  13. data/json-2.21.1/ext/json/ext/simd/conf.rb +24 -0
  14. data/json-2.21.1/ext/json/ext/simd/simd.h +208 -0
  15. data/json-2.21.1/ext/json/ext/vendor/fast_float_parser.h +814 -0
  16. data/json-2.21.1/ext/json/ext/vendor/fpconv.c +480 -0
  17. data/json-2.21.1/ext/json/ext/vendor/jeaiii-ltoa.h +267 -0
  18. data/json-2.21.1/json.gemspec +62 -0
  19. data/json-2.21.1/lib/json/add/bigdecimal.rb +58 -0
  20. data/json-2.21.1/lib/json/add/complex.rb +51 -0
  21. data/json-2.21.1/lib/json/add/core.rb +13 -0
  22. data/json-2.21.1/lib/json/add/date.rb +54 -0
  23. data/json-2.21.1/lib/json/add/date_time.rb +67 -0
  24. data/json-2.21.1/lib/json/add/exception.rb +49 -0
  25. data/json-2.21.1/lib/json/add/ostruct.rb +54 -0
  26. data/json-2.21.1/lib/json/add/range.rb +54 -0
  27. data/json-2.21.1/lib/json/add/rational.rb +49 -0
  28. data/json-2.21.1/lib/json/add/regexp.rb +48 -0
  29. data/json-2.21.1/lib/json/add/set.rb +48 -0
  30. data/json-2.21.1/lib/json/add/string.rb +35 -0
  31. data/json-2.21.1/lib/json/add/struct.rb +52 -0
  32. data/json-2.21.1/lib/json/add/symbol.rb +52 -0
  33. data/json-2.21.1/lib/json/add/time.rb +52 -0
  34. data/json-2.21.1/lib/json/common.rb +1182 -0
  35. data/json-2.21.1/lib/json/ext/generator/state.rb +104 -0
  36. data/json-2.21.1/lib/json/ext.rb +71 -0
  37. data/json-2.21.1/lib/json/generic_object.rb +67 -0
  38. data/json-2.21.1/lib/json/truffle_ruby/generator.rb +790 -0
  39. data/json-2.21.1/lib/json/version.rb +5 -0
  40. data/json-2.21.1/lib/json.rb +841 -0
  41. data/piko-lite-mod.gemspec +11 -0
  42. metadata +80 -0
@@ -0,0 +1,1182 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json/version'
4
+
5
+ module JSON
6
+ autoload :GenericObject, 'json/generic_object'
7
+
8
+ module ParserOptions # :nodoc:
9
+ class << self
10
+ def prepare(opts)
11
+ if opts[:object_class] || opts[:array_class]
12
+ opts = opts.dup
13
+ on_load = opts[:on_load]
14
+
15
+ on_load = object_class_proc(opts[:object_class], on_load) if opts[:object_class]
16
+ on_load = array_class_proc(opts[:array_class], on_load) if opts[:array_class]
17
+ opts[:on_load] = on_load
18
+ end
19
+
20
+ if opts.fetch(:create_additions, false) != false
21
+ opts = create_additions_proc(opts)
22
+ end
23
+
24
+ opts
25
+ end
26
+
27
+ private
28
+
29
+ def object_class_proc(object_class, on_load)
30
+ ->(obj) do
31
+ if Hash === obj
32
+ object = object_class.new
33
+ obj.each { |k, v| object[k] = v }
34
+ obj = object
35
+ end
36
+ on_load.nil? ? obj : on_load.call(obj)
37
+ end
38
+ end
39
+
40
+ def array_class_proc(array_class, on_load)
41
+ ->(obj) do
42
+ if Array === obj
43
+ array = array_class.new
44
+ obj.each { |v| array << v }
45
+ obj = array
46
+ end
47
+ on_load.nil? ? obj : on_load.call(obj)
48
+ end
49
+ end
50
+
51
+ # TODO: extract :create_additions support to another gem for version 3.0
52
+ def create_additions_proc(opts)
53
+ if opts[:symbolize_names]
54
+ raise ArgumentError, "options :symbolize_names and :create_additions cannot be used in conjunction"
55
+ end
56
+
57
+ opts = opts.dup
58
+ create_additions = opts.fetch(:create_additions, false)
59
+ on_load = opts[:on_load]
60
+ object_class = opts[:object_class] || Hash
61
+
62
+ opts[:on_load] = ->(object) do
63
+ case object
64
+ when String
65
+ opts[:match_string]&.each do |pattern, klass|
66
+ if match = pattern.match(object)
67
+ create_additions_warning if create_additions.nil?
68
+ object = klass.json_create(object)
69
+ break
70
+ end
71
+ end
72
+ when object_class
73
+ if opts[:create_additions] != false
74
+ if class_path = object[JSON.create_id]
75
+ klass = begin
76
+ Object.const_get(class_path)
77
+ rescue NameError => e
78
+ raise ArgumentError, "can't get const #{class_path}: #{e}"
79
+ end
80
+
81
+ if klass.respond_to?(:json_creatable?) ? klass.json_creatable? : klass.respond_to?(:json_create)
82
+ create_additions_warning if create_additions.nil?
83
+ object = klass.json_create(object)
84
+ end
85
+ end
86
+ end
87
+ end
88
+
89
+ on_load.nil? ? object : on_load.call(object)
90
+ end
91
+
92
+ opts
93
+ end
94
+
95
+ def create_additions_warning
96
+ JSON.deprecation_warning "JSON.load implicit support for `create_additions: true` is deprecated " \
97
+ "and will be removed in 3.0, use JSON.unsafe_load or explicitly " \
98
+ "pass `create_additions: true`"
99
+ end
100
+ end
101
+ end
102
+
103
+ class << self
104
+ def deprecation_warning(message, uplevel = 3) # :nodoc:
105
+ gem_root = File.expand_path("..", __dir__) + "/"
106
+ caller_locations(uplevel, 10).each do |frame|
107
+ if frame.path.nil? || frame.path.start_with?(gem_root) || frame.path.end_with?("/truffle/cext_ruby.rb", ".c")
108
+ uplevel += 1
109
+ else
110
+ break
111
+ end
112
+ end
113
+
114
+ if RUBY_VERSION >= "3.0"
115
+ warn(message, uplevel: uplevel, category: :deprecated)
116
+ else
117
+ warn(message, uplevel: uplevel)
118
+ end
119
+ end
120
+
121
+ # :call-seq:
122
+ # JSON[object] -> new_array or new_string
123
+ #
124
+ # If +object+ is a \String,
125
+ # calls JSON.parse with +object+ and +opts+ (see method #parse):
126
+ # json = '[0, 1, null]'
127
+ # JSON[json]# => [0, 1, nil]
128
+ #
129
+ # Otherwise, calls JSON.generate with +object+ and +opts+ (see method #generate):
130
+ # ruby = [0, 1, nil]
131
+ # JSON[ruby] # => '[0,1,null]'
132
+ def [](object, opts = nil)
133
+ if object.is_a?(String)
134
+ return JSON.parse(object, opts)
135
+ elsif object.respond_to?(:to_str)
136
+ str = object.to_str
137
+ if str.is_a?(String)
138
+ return JSON.parse(str, opts)
139
+ end
140
+ end
141
+
142
+ JSON.generate(object, opts)
143
+ end
144
+
145
+ # Returns the JSON parser class that is used by JSON.
146
+ attr_reader :parser
147
+
148
+ # Set the JSON parser class _parser_ to be used by JSON.
149
+ def parser=(parser) # :nodoc:
150
+ @parser = parser
151
+ remove_const :Parser if const_defined?(:Parser, false)
152
+ const_set :Parser, parser
153
+ end
154
+
155
+ # Set the module _generator_ to be used by JSON.
156
+ def generator=(generator) # :nodoc:
157
+ old, $VERBOSE = $VERBOSE, nil
158
+
159
+ # The default proc used when the +sort_keys+ generation option is +true+.
160
+ # It returns a new hash with the entries sorted by their keys.
161
+ sort_keys_proc = ->(hash) { hash.sort.to_h }
162
+ if defined?(::Ractor) && Ractor.respond_to?(:shareable_lambda)
163
+ sort_keys_proc = Ractor.shareable_lambda(&sort_keys_proc)
164
+ end
165
+ generator::State.default_sort_keys_proc = sort_keys_proc
166
+
167
+ @generator = generator
168
+ if generator.const_defined?(:GeneratorMethods)
169
+ generator_methods = generator::GeneratorMethods
170
+ for const in generator_methods.constants
171
+ klass = const_get(const)
172
+ modul = generator_methods.const_get(const)
173
+ klass.class_eval do
174
+ instance_methods(false).each do |m|
175
+ m.to_s == 'to_json' and remove_method m
176
+ end
177
+ include modul
178
+ end
179
+ end
180
+ end
181
+ self.state = generator::State
182
+ const_set :State, state
183
+ ensure
184
+ $VERBOSE = old
185
+ end
186
+
187
+ # Returns the JSON generator module that is used by JSON.
188
+ attr_reader :generator
189
+
190
+ # Sets or Returns the JSON generator state class that is used by JSON.
191
+ attr_accessor :state
192
+
193
+ private
194
+
195
+ # Called from the extension when a hash has both string and symbol keys
196
+ def on_mixed_keys_hash(hash, do_raise)
197
+ set = {}
198
+ hash.each_key do |key|
199
+ key_str = key.to_s
200
+
201
+ if set[key_str]
202
+ message = "detected duplicate key #{key_str.inspect} in #{hash.inspect}"
203
+ if do_raise
204
+ raise GeneratorError, message
205
+ else
206
+ deprecation_warning("#{message}.\nThis will raise an error in json 3.0 unless enabled via `allow_duplicate_key: true`")
207
+ end
208
+ else
209
+ set[key_str] = true
210
+ end
211
+ end
212
+ end
213
+
214
+ def deprecated_singleton_attr_accessor(*attrs)
215
+ args = RUBY_VERSION >= "3.0" ? ", category: :deprecated" : ""
216
+ attrs.each do |attr|
217
+ singleton_class.class_eval <<~RUBY
218
+ def #{attr}
219
+ warn "JSON.#{attr} is deprecated and will be removed in json 3.0.0", uplevel: 1 #{args}
220
+ @#{attr}
221
+ end
222
+
223
+ def #{attr}=(val)
224
+ warn "JSON.#{attr}= is deprecated and will be removed in json 3.0.0", uplevel: 1 #{args}
225
+ @#{attr} = val
226
+ end
227
+
228
+ def _#{attr}
229
+ @#{attr}
230
+ end
231
+ RUBY
232
+ end
233
+ end
234
+ end
235
+
236
+ # Sets create identifier, which is used to decide if the _json_create_
237
+ # hook of a class should be called; initial value is +json_class+:
238
+ # JSON.create_id # => 'json_class'
239
+ def self.create_id=(new_value)
240
+ Thread.current[:"JSON.create_id"] = new_value.dup.freeze
241
+ end
242
+
243
+ # Returns the current create identifier.
244
+ # See also JSON.create_id=.
245
+ def self.create_id
246
+ Thread.current[:"JSON.create_id"] || 'json_class'
247
+ end
248
+
249
+ NaN = Float::NAN
250
+
251
+ Infinity = Float::INFINITY
252
+
253
+ MinusInfinity = -Infinity
254
+
255
+ # The base exception for JSON errors.
256
+ class JSONError < StandardError; end
257
+
258
+ # This exception is raised if a parser error occurs.
259
+ class ParserError < JSONError
260
+ attr_reader :line, :column
261
+ end
262
+
263
+ # This exception is raised if the nesting of parsed data structures is too
264
+ # deep.
265
+ class NestingError < ParserError; end
266
+
267
+ # This exception is raised if a generator or unparser error occurs.
268
+ class GeneratorError < JSONError
269
+ attr_reader :invalid_object
270
+
271
+ def initialize(message, invalid_object = nil)
272
+ super(message)
273
+ @invalid_object = invalid_object
274
+ end
275
+
276
+ def detailed_message(...)
277
+ # Exception#detailed_message doesn't exist until Ruby 3.2
278
+ super_message = defined?(super) ? super : message
279
+
280
+ if @invalid_object.nil?
281
+ super_message
282
+ else
283
+ "#{super_message}\nInvalid object: #{@invalid_object.inspect}"
284
+ end
285
+ end
286
+ end
287
+
288
+ # Fragment of JSON document that is to be included as is:
289
+ # fragment = JSON::Fragment.new("[1, 2, 3]")
290
+ # JSON.generate({ count: 3, items: fragments })
291
+ #
292
+ # This allows to easily assemble multiple JSON fragments that have
293
+ # been persisted somewhere without having to parse them nor resorting
294
+ # to string interpolation.
295
+ #
296
+ # Note: no validation is performed on the provided string. It is the
297
+ # responsibility of the caller to ensure the string contains valid JSON.
298
+ Fragment = Struct.new(:json) do
299
+ def initialize(json)
300
+ unless string = String.try_convert(json)
301
+ raise TypeError, " no implicit conversion of #{json.class} into String"
302
+ end
303
+
304
+ super(string)
305
+ end
306
+
307
+ def to_json(state = nil, *)
308
+ json
309
+ end
310
+ end
311
+
312
+ module_function
313
+
314
+ # :call-seq:
315
+ # JSON.parse(source, opts) -> object
316
+ #
317
+ # Returns the Ruby objects created by parsing the given +source+.
318
+ #
319
+ # Argument +source+ contains the \String to be parsed.
320
+ #
321
+ # Argument +opts+, if given, contains a \Hash of options for the parsing.
322
+ # See {Parsing Options}[#module-JSON-label-Parsing+Options].
323
+ #
324
+ # ---
325
+ #
326
+ # When +source+ is a \JSON array, returns a Ruby \Array:
327
+ # source = '["foo", 1.0, true, false, null]'
328
+ # ruby = JSON.parse(source)
329
+ # ruby # => ["foo", 1.0, true, false, nil]
330
+ # ruby.class # => Array
331
+ #
332
+ # When +source+ is a \JSON object, returns a Ruby \Hash:
333
+ # source = '{"a": "foo", "b": 1.0, "c": true, "d": false, "e": null}'
334
+ # ruby = JSON.parse(source)
335
+ # ruby # => {"a"=>"foo", "b"=>1.0, "c"=>true, "d"=>false, "e"=>nil}
336
+ # ruby.class # => Hash
337
+ #
338
+ # For examples of parsing for all \JSON data types, see
339
+ # {Parsing \JSON}[#module-JSON-label-Parsing+JSON].
340
+ #
341
+ # Parses nested JSON objects:
342
+ # source = <<~JSON
343
+ # {
344
+ # "name": "Dave",
345
+ # "age" :40,
346
+ # "hats": [
347
+ # "Cattleman's",
348
+ # "Panama",
349
+ # "Tophat"
350
+ # ]
351
+ # }
352
+ # JSON
353
+ # ruby = JSON.parse(source)
354
+ # ruby # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]}
355
+ #
356
+ # ---
357
+ #
358
+ # Raises an exception if +source+ is not valid JSON:
359
+ # # Raises JSON::ParserError (783: unexpected token at ''):
360
+ # JSON.parse('')
361
+ #
362
+ def parse(source, opts = nil)
363
+ opts = ParserOptions.prepare(opts) unless opts.nil?
364
+ Parser.parse(source, opts)
365
+ end
366
+
367
+ PARSE_L_OPTIONS = {
368
+ max_nesting: false,
369
+ allow_nan: true,
370
+ }.freeze
371
+ private_constant :PARSE_L_OPTIONS
372
+
373
+ # :call-seq:
374
+ # JSON.parse!(source, opts) -> object
375
+ #
376
+ # Calls
377
+ # parse(source, opts)
378
+ # with +source+ and possibly modified +opts+.
379
+ #
380
+ # Differences from JSON.parse:
381
+ # - Option +max_nesting+, if not provided, defaults to +false+,
382
+ # which disables checking for nesting depth.
383
+ # - Option +allow_nan+, if not provided, defaults to +true+.
384
+ def parse!(source, opts = nil)
385
+ if opts.nil?
386
+ parse(source, PARSE_L_OPTIONS)
387
+ else
388
+ parse(source, PARSE_L_OPTIONS.merge(opts))
389
+ end
390
+ end
391
+
392
+ # :call-seq:
393
+ # JSON.load_file(path, opts={}) -> object
394
+ #
395
+ # Calls:
396
+ # parse(File.read(path), opts)
397
+ #
398
+ # See method #parse.
399
+ def load_file(filespec, opts = nil)
400
+ parse(File.read(filespec, encoding: Encoding::UTF_8), opts)
401
+ end
402
+
403
+ # :call-seq:
404
+ # JSON.load_file!(path, opts = {})
405
+ #
406
+ # Calls:
407
+ # JSON.parse!(File.read(path, opts))
408
+ #
409
+ # See method #parse!
410
+ def load_file!(filespec, opts = nil)
411
+ parse!(File.read(filespec, encoding: Encoding::UTF_8), opts)
412
+ end
413
+
414
+ # :call-seq:
415
+ # JSON.generate(obj, opts = nil) -> new_string
416
+ #
417
+ # Returns a \String containing the generated \JSON data.
418
+ #
419
+ # See also JSON.pretty_generate.
420
+ #
421
+ # Argument +obj+ is the Ruby object to be converted to \JSON.
422
+ #
423
+ # Argument +opts+, if given, contains a \Hash of options for the generation.
424
+ # See {Generating Options}[#module-JSON-label-Generating+Options].
425
+ #
426
+ # ---
427
+ #
428
+ # When +obj+ is an \Array, returns a \String containing a \JSON array:
429
+ # obj = ["foo", 1.0, true, false, nil]
430
+ # json = JSON.generate(obj)
431
+ # json # => '["foo",1.0,true,false,null]'
432
+ #
433
+ # When +obj+ is a \Hash, returns a \String containing a \JSON object:
434
+ # obj = {foo: 0, bar: 's', baz: :bat}
435
+ # json = JSON.generate(obj)
436
+ # json # => '{"foo":0,"bar":"s","baz":"bat"}'
437
+ #
438
+ # For examples of generating from other Ruby objects, see
439
+ # {Generating \JSON from Other Objects}[#module-JSON-label-Generating+JSON+from+Other+Objects].
440
+ #
441
+ # ---
442
+ #
443
+ # Raises an exception if any formatting option is not a \String.
444
+ #
445
+ # Raises an exception if +obj+ contains circular references:
446
+ # a = []; b = []; a.push(b); b.push(a)
447
+ # # Raises JSON::NestingError (nesting of 100 is too deep):
448
+ # JSON.generate(a)
449
+ #
450
+ def generate(obj, opts = nil)
451
+ if State === opts
452
+ opts.generate(obj)
453
+ else
454
+ State.generate(obj, opts, nil)
455
+ end
456
+ end
457
+
458
+ # :call-seq:
459
+ # JSON.fast_generate(obj, opts) -> new_string
460
+ #
461
+ # Arguments +obj+ and +opts+ here are the same as
462
+ # arguments +obj+ and +opts+ in JSON.generate.
463
+ #
464
+ # By default, generates \JSON data without checking
465
+ # for circular references in +obj+ (option +max_nesting+ set to +false+, disabled).
466
+ #
467
+ # Raises an exception if +obj+ contains circular references:
468
+ # a = []; b = []; a.push(b); b.push(a)
469
+ # # Raises SystemStackError (stack level too deep):
470
+ # JSON.fast_generate(a)
471
+ def fast_generate(obj, opts = nil)
472
+ if RUBY_VERSION >= "3.0"
473
+ warn "JSON.fast_generate is deprecated and will be removed in json 3.0.0, just use JSON.generate", uplevel: 1, category: :deprecated
474
+ else
475
+ warn "JSON.fast_generate is deprecated and will be removed in json 3.0.0, just use JSON.generate", uplevel: 1
476
+ end
477
+ generate(obj, opts)
478
+ end
479
+
480
+ PRETTY_GENERATE_OPTIONS = {
481
+ indent: ' ',
482
+ space: ' ',
483
+ object_nl: "\n",
484
+ array_nl: "\n",
485
+ }.freeze
486
+ private_constant :PRETTY_GENERATE_OPTIONS
487
+
488
+ # :call-seq:
489
+ # JSON.pretty_generate(obj, opts = nil) -> new_string
490
+ #
491
+ # Arguments +obj+ and +opts+ here are the same as
492
+ # arguments +obj+ and +opts+ in JSON.generate.
493
+ #
494
+ # Default options are:
495
+ # {
496
+ # indent: ' ', # Two spaces
497
+ # space: ' ', # One space
498
+ # array_nl: "\n", # Newline
499
+ # object_nl: "\n" # Newline
500
+ # }
501
+ #
502
+ # Example:
503
+ # obj = {foo: [:bar, :baz], bat: {bam: 0, bad: 1}}
504
+ # json = JSON.pretty_generate(obj)
505
+ # puts json
506
+ # Output:
507
+ # {
508
+ # "foo": [
509
+ # "bar",
510
+ # "baz"
511
+ # ],
512
+ # "bat": {
513
+ # "bam": 0,
514
+ # "bad": 1
515
+ # }
516
+ # }
517
+ #
518
+ def pretty_generate(obj, opts = nil)
519
+ return opts.generate(obj) if State === opts
520
+
521
+ options = PRETTY_GENERATE_OPTIONS
522
+
523
+ if opts
524
+ unless opts.is_a?(Hash)
525
+ if opts.respond_to? :to_hash
526
+ opts = opts.to_hash
527
+ elsif opts.respond_to? :to_h
528
+ opts = opts.to_h
529
+ else
530
+ raise TypeError, "can't convert #{opts.class} into Hash"
531
+ end
532
+ end
533
+ options = options.merge(opts)
534
+ end
535
+
536
+ State.generate(obj, options, nil)
537
+ end
538
+
539
+ # Sets or returns default options for the JSON.unsafe_load method.
540
+ # Initially:
541
+ # opts = JSON.load_default_options
542
+ # opts # => {:max_nesting=>false, :allow_nan=>true, :allow_blank=>true, :create_additions=>true}
543
+ deprecated_singleton_attr_accessor :unsafe_load_default_options
544
+
545
+ @unsafe_load_default_options = {
546
+ :max_nesting => false,
547
+ :allow_nan => true,
548
+ :allow_blank => true,
549
+ :create_additions => true,
550
+ }
551
+
552
+ # Sets or returns default options for the JSON.load method.
553
+ # Initially:
554
+ # opts = JSON.load_default_options
555
+ # opts # => {:max_nesting=>false, :allow_nan=>true, :allow_blank=>true, :create_additions=>true}
556
+ deprecated_singleton_attr_accessor :load_default_options
557
+
558
+ @load_default_options = {
559
+ :allow_nan => true,
560
+ :allow_blank => true,
561
+ :create_additions => nil,
562
+ }
563
+ # :call-seq:
564
+ # JSON.unsafe_load(source, options = {}) -> object
565
+ # JSON.unsafe_load(source, proc = nil, options = {}) -> object
566
+ #
567
+ # Returns the Ruby objects created by parsing the given +source+.
568
+ #
569
+ # BEWARE: This method is meant to serialise data from trusted user input,
570
+ # like from your own database server or clients under your control, it could
571
+ # be dangerous to allow untrusted users to pass JSON sources into it.
572
+ #
573
+ # - Argument +source+ must be, or be convertible to, a \String:
574
+ # - If +source+ responds to instance method +to_str+,
575
+ # <tt>source.to_str</tt> becomes the source.
576
+ # - If +source+ responds to instance method +to_io+,
577
+ # <tt>source.to_io.read</tt> becomes the source.
578
+ # - If +source+ responds to instance method +read+,
579
+ # <tt>source.read</tt> becomes the source.
580
+ # - If both of the following are true, source becomes the \String <tt>'null'</tt>:
581
+ # - Option +allow_blank+ specifies a truthy value.
582
+ # - The source, as defined above, is +nil+ or the empty \String <tt>''</tt>.
583
+ # - Otherwise, +source+ remains the source.
584
+ # - Argument +proc+, if given, must be a \Proc that accepts one argument.
585
+ # It will be called recursively with each result (depth-first order).
586
+ # See details below.
587
+ # - Argument +opts+, if given, contains a \Hash of options for the parsing.
588
+ # See {Parsing Options}[#module-JSON-label-Parsing+Options].
589
+ # The default options can be changed via method JSON.unsafe_load_default_options=.
590
+ #
591
+ # ---
592
+ #
593
+ # When no +proc+ is given, modifies +source+ as above and returns the result of
594
+ # <tt>parse(source, opts)</tt>; see #parse.
595
+ #
596
+ # Source for following examples:
597
+ # source = <<~JSON
598
+ # {
599
+ # "name": "Dave",
600
+ # "age" :40,
601
+ # "hats": [
602
+ # "Cattleman's",
603
+ # "Panama",
604
+ # "Tophat"
605
+ # ]
606
+ # }
607
+ # JSON
608
+ #
609
+ # Load a \String:
610
+ # ruby = JSON.unsafe_load(source)
611
+ # ruby # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]}
612
+ #
613
+ # Load an \IO object:
614
+ # require 'stringio'
615
+ # object = JSON.unsafe_load(StringIO.new(source))
616
+ # object # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]}
617
+ #
618
+ # Load a \File object:
619
+ # path = 't.json'
620
+ # File.write(path, source)
621
+ # File.open(path) do |file|
622
+ # JSON.unsafe_load(file)
623
+ # end # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]}
624
+ #
625
+ # ---
626
+ #
627
+ # When +proc+ is given:
628
+ # - Modifies +source+ as above.
629
+ # - Gets the +result+ from calling <tt>parse(source, opts)</tt>.
630
+ # - Recursively calls <tt>proc(result)</tt>.
631
+ # - Returns the final result.
632
+ #
633
+ # Example:
634
+ # require 'json'
635
+ #
636
+ # # Some classes for the example.
637
+ # class Base
638
+ # def initialize(attributes)
639
+ # @attributes = attributes
640
+ # end
641
+ # end
642
+ # class User < Base; end
643
+ # class Account < Base; end
644
+ # class Admin < Base; end
645
+ # # The JSON source.
646
+ # json = <<-EOF
647
+ # {
648
+ # "users": [
649
+ # {"type": "User", "username": "jane", "email": "jane@example.com"},
650
+ # {"type": "User", "username": "john", "email": "john@example.com"}
651
+ # ],
652
+ # "accounts": [
653
+ # {"account": {"type": "Account", "paid": true, "account_id": "1234"}},
654
+ # {"account": {"type": "Account", "paid": false, "account_id": "1235"}}
655
+ # ],
656
+ # "admins": {"type": "Admin", "password": "0wn3d"}
657
+ # }
658
+ # EOF
659
+ # # Deserializer method.
660
+ # def deserialize_obj(obj, safe_types = %w(User Account Admin))
661
+ # type = obj.is_a?(Hash) && obj["type"]
662
+ # safe_types.include?(type) ? Object.const_get(type).new(obj) : obj
663
+ # end
664
+ # # Call to JSON.unsafe_load
665
+ # ruby = JSON.unsafe_load(json, proc {|obj|
666
+ # case obj
667
+ # when Hash
668
+ # obj.each {|k, v| obj[k] = deserialize_obj v }
669
+ # when Array
670
+ # obj.map! {|v| deserialize_obj v }
671
+ # end
672
+ # obj
673
+ # })
674
+ # pp ruby
675
+ # Output:
676
+ # {"users"=>
677
+ # [#<User:0x00000000064c4c98
678
+ # @attributes=
679
+ # {"type"=>"User", "username"=>"jane", "email"=>"jane@example.com"}>,
680
+ # #<User:0x00000000064c4bd0
681
+ # @attributes=
682
+ # {"type"=>"User", "username"=>"john", "email"=>"john@example.com"}>],
683
+ # "accounts"=>
684
+ # [{"account"=>
685
+ # #<Account:0x00000000064c4928
686
+ # @attributes={"type"=>"Account", "paid"=>true, "account_id"=>"1234"}>},
687
+ # {"account"=>
688
+ # #<Account:0x00000000064c4680
689
+ # @attributes={"type"=>"Account", "paid"=>false, "account_id"=>"1235"}>}],
690
+ # "admins"=>
691
+ # #<Admin:0x00000000064c41f8
692
+ # @attributes={"type"=>"Admin", "password"=>"0wn3d"}>}
693
+ #
694
+ def unsafe_load(source, proc = nil, options = nil)
695
+ opts = if options.nil?
696
+ if proc && proc.is_a?(Hash)
697
+ options, proc = proc, nil
698
+ options
699
+ else
700
+ _unsafe_load_default_options
701
+ end
702
+ else
703
+ _unsafe_load_default_options.merge(options)
704
+ end
705
+
706
+ unless source.is_a?(String)
707
+ if source.respond_to? :to_str
708
+ source = source.to_str
709
+ elsif source.respond_to? :to_io
710
+ source = source.to_io.read
711
+ elsif source.respond_to?(:read)
712
+ source = source.read
713
+ end
714
+ end
715
+
716
+ if opts[:allow_blank] && (source.nil? || source.empty?)
717
+ source = 'null'
718
+ end
719
+
720
+ if proc
721
+ opts = opts.dup
722
+ opts[:on_load] = proc.to_proc
723
+ end
724
+
725
+ parse(source, opts)
726
+ end
727
+
728
+ # :call-seq:
729
+ # JSON.load(source, options = {}) -> object
730
+ # JSON.load(source, proc = nil, options = {}) -> object
731
+ #
732
+ # Returns the Ruby objects created by parsing the given +source+.
733
+ #
734
+ # BEWARE: This method is meant to serialise data from trusted user input,
735
+ # like from your own database server or clients under your control, it could
736
+ # be dangerous to allow untrusted users to pass JSON sources into it.
737
+ # If you must use it, use JSON.unsafe_load instead to make it clear.
738
+ #
739
+ # Since JSON version 2.8.0, `load` emits a deprecation warning when a
740
+ # non native type is deserialized, without `create_additions` being explicitly
741
+ # enabled, and in JSON version 3.0, `load` will have `create_additions` disabled
742
+ # by default.
743
+ #
744
+ # - Argument +source+ must be, or be convertible to, a \String:
745
+ # - If +source+ responds to instance method +to_str+,
746
+ # <tt>source.to_str</tt> becomes the source.
747
+ # - If +source+ responds to instance method +to_io+,
748
+ # <tt>source.to_io.read</tt> becomes the source.
749
+ # - If +source+ responds to instance method +read+,
750
+ # <tt>source.read</tt> becomes the source.
751
+ # - If both of the following are true, source becomes the \String <tt>'null'</tt>:
752
+ # - Option +allow_blank+ specifies a truthy value.
753
+ # - The source, as defined above, is +nil+ or the empty \String <tt>''</tt>.
754
+ # - Otherwise, +source+ remains the source.
755
+ # - Argument +proc+, if given, must be a \Proc that accepts one argument.
756
+ # It will be called recursively with each result (depth-first order).
757
+ # See details below.
758
+ # - Argument +opts+, if given, contains a \Hash of options for the parsing.
759
+ # See {Parsing Options}[#module-JSON-label-Parsing+Options].
760
+ # The default options can be changed via method JSON.load_default_options=.
761
+ #
762
+ # ---
763
+ #
764
+ # When no +proc+ is given, modifies +source+ as above and returns the result of
765
+ # <tt>parse(source, opts)</tt>; see #parse.
766
+ #
767
+ # Source for following examples:
768
+ # source = <<~JSON
769
+ # {
770
+ # "name": "Dave",
771
+ # "age" :40,
772
+ # "hats": [
773
+ # "Cattleman's",
774
+ # "Panama",
775
+ # "Tophat"
776
+ # ]
777
+ # }
778
+ # JSON
779
+ #
780
+ # Load a \String:
781
+ # ruby = JSON.load(source)
782
+ # ruby # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]}
783
+ #
784
+ # Load an \IO object:
785
+ # require 'stringio'
786
+ # object = JSON.load(StringIO.new(source))
787
+ # object # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]}
788
+ #
789
+ # Load a \File object:
790
+ # path = 't.json'
791
+ # File.write(path, source)
792
+ # File.open(path) do |file|
793
+ # JSON.load(file)
794
+ # end # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]}
795
+ #
796
+ # ---
797
+ #
798
+ # When +proc+ is given:
799
+ # - Modifies +source+ as above.
800
+ # - Gets the +result+ from calling <tt>parse(source, opts)</tt>.
801
+ # - Recursively calls <tt>proc(result)</tt>.
802
+ # - Returns the final result.
803
+ #
804
+ # Example:
805
+ # require 'json'
806
+ #
807
+ # # Some classes for the example.
808
+ # class Base
809
+ # def initialize(attributes)
810
+ # @attributes = attributes
811
+ # end
812
+ # end
813
+ # class User < Base; end
814
+ # class Account < Base; end
815
+ # class Admin < Base; end
816
+ # # The JSON source.
817
+ # json = <<-EOF
818
+ # {
819
+ # "users": [
820
+ # {"type": "User", "username": "jane", "email": "jane@example.com"},
821
+ # {"type": "User", "username": "john", "email": "john@example.com"}
822
+ # ],
823
+ # "accounts": [
824
+ # {"account": {"type": "Account", "paid": true, "account_id": "1234"}},
825
+ # {"account": {"type": "Account", "paid": false, "account_id": "1235"}}
826
+ # ],
827
+ # "admins": {"type": "Admin", "password": "0wn3d"}
828
+ # }
829
+ # EOF
830
+ # # Deserializer method.
831
+ # def deserialize_obj(obj, safe_types = %w(User Account Admin))
832
+ # type = obj.is_a?(Hash) && obj["type"]
833
+ # safe_types.include?(type) ? Object.const_get(type).new(obj) : obj
834
+ # end
835
+ # # Call to JSON.load
836
+ # ruby = JSON.load(json, proc {|obj|
837
+ # case obj
838
+ # when Hash
839
+ # obj.each {|k, v| obj[k] = deserialize_obj v }
840
+ # when Array
841
+ # obj.map! {|v| deserialize_obj v }
842
+ # end
843
+ # obj
844
+ # })
845
+ # pp ruby
846
+ # Output:
847
+ # {"users"=>
848
+ # [#<User:0x00000000064c4c98
849
+ # @attributes=
850
+ # {"type"=>"User", "username"=>"jane", "email"=>"jane@example.com"}>,
851
+ # #<User:0x00000000064c4bd0
852
+ # @attributes=
853
+ # {"type"=>"User", "username"=>"john", "email"=>"john@example.com"}>],
854
+ # "accounts"=>
855
+ # [{"account"=>
856
+ # #<Account:0x00000000064c4928
857
+ # @attributes={"type"=>"Account", "paid"=>true, "account_id"=>"1234"}>},
858
+ # {"account"=>
859
+ # #<Account:0x00000000064c4680
860
+ # @attributes={"type"=>"Account", "paid"=>false, "account_id"=>"1235"}>}],
861
+ # "admins"=>
862
+ # #<Admin:0x00000000064c41f8
863
+ # @attributes={"type"=>"Admin", "password"=>"0wn3d"}>}
864
+ #
865
+ def load(source, proc = nil, options = nil)
866
+ if proc && options.nil? && proc.is_a?(Hash)
867
+ options = proc
868
+ proc = nil
869
+ end
870
+
871
+ opts = if options.nil?
872
+ if proc && proc.is_a?(Hash)
873
+ options, proc = proc, nil
874
+ options
875
+ else
876
+ _load_default_options
877
+ end
878
+ else
879
+ _load_default_options.merge(options)
880
+ end
881
+
882
+ unless source.is_a?(String)
883
+ if source.respond_to? :to_str
884
+ source = source.to_str
885
+ elsif source.respond_to? :to_io
886
+ source = source.to_io.read
887
+ elsif source.respond_to?(:read)
888
+ source = source.read
889
+ end
890
+ end
891
+
892
+ if opts[:allow_blank] && (source.nil? || (String === source && source.empty?))
893
+ source = 'null'
894
+ end
895
+
896
+ if proc
897
+ opts = opts.dup
898
+ opts[:on_load] = proc.to_proc
899
+ end
900
+
901
+ parse(source, opts)
902
+ end
903
+
904
+ # Sets or returns the default options for the JSON.dump method.
905
+ # Initially:
906
+ # opts = JSON.dump_default_options
907
+ # opts # => {:max_nesting=>false, :allow_nan=>true}
908
+ deprecated_singleton_attr_accessor :dump_default_options
909
+ @dump_default_options = {
910
+ :max_nesting => false,
911
+ :allow_nan => true,
912
+ }
913
+
914
+ # :call-seq:
915
+ # JSON.dump(obj, io = nil, limit = nil)
916
+ #
917
+ # Dumps +obj+ as a \JSON string, i.e. calls generate on the object and returns the result.
918
+ #
919
+ # The default options can be changed via method JSON.dump_default_options.
920
+ #
921
+ # - Argument +io+, if given, should respond to method +write+;
922
+ # the \JSON \String is written to +io+, and +io+ is returned.
923
+ # If +io+ is not given, the \JSON \String is returned.
924
+ # - Argument +limit+, if given, is passed to JSON.generate as option +max_nesting+.
925
+ #
926
+ # ---
927
+ #
928
+ # When argument +io+ is not given, returns the \JSON \String generated from +obj+:
929
+ # obj = {foo: [0, 1], bar: {baz: 2, bat: 3}, bam: :bad}
930
+ # json = JSON.dump(obj)
931
+ # json # => "{\"foo\":[0,1],\"bar\":{\"baz\":2,\"bat\":3},\"bam\":\"bad\"}"
932
+ #
933
+ # When argument +io+ is given, writes the \JSON \String to +io+ and returns +io+:
934
+ # path = 't.json'
935
+ # File.open(path, 'w') do |file|
936
+ # JSON.dump(obj, file)
937
+ # end # => #<File:t.json (closed)>
938
+ # puts File.read(path)
939
+ # Output:
940
+ # {"foo":[0,1],"bar":{"baz":2,"bat":3},"bam":"bad"}
941
+ def dump(obj, anIO = nil, limit = nil, kwargs = nil)
942
+ if kwargs.nil?
943
+ if limit.nil?
944
+ if anIO.is_a?(Hash)
945
+ kwargs = anIO
946
+ anIO = nil
947
+ end
948
+ elsif limit.is_a?(Hash)
949
+ kwargs = limit
950
+ limit = nil
951
+ end
952
+ end
953
+
954
+ unless anIO.nil?
955
+ if anIO.respond_to?(:to_io)
956
+ anIO = anIO.to_io
957
+ elsif limit.nil? && !anIO.respond_to?(:write)
958
+ anIO, limit = nil, anIO
959
+ end
960
+ end
961
+
962
+ opts = JSON._dump_default_options
963
+ opts = opts.merge(:max_nesting => limit) if limit
964
+ opts = opts.merge(kwargs) if kwargs
965
+
966
+ begin
967
+ State.generate(obj, opts, anIO)
968
+ rescue JSON::NestingError
969
+ raise ArgumentError, "exceed depth limit"
970
+ end
971
+ end
972
+
973
+ # :stopdoc:
974
+ # All these were meant to be deprecated circa 2009, but were just set as undocumented
975
+ # so usage still exist in the wild.
976
+ def unparse(...)
977
+ if RUBY_VERSION >= "3.0"
978
+ warn "JSON.unparse is deprecated and will be removed in json 3.0.0, just use JSON.generate", uplevel: 1, category: :deprecated
979
+ else
980
+ warn "JSON.unparse is deprecated and will be removed in json 3.0.0, just use JSON.generate", uplevel: 1
981
+ end
982
+ generate(...)
983
+ end
984
+ module_function :unparse
985
+
986
+ def fast_unparse(...)
987
+ if RUBY_VERSION >= "3.0"
988
+ warn "JSON.fast_unparse is deprecated and will be removed in json 3.0.0, just use JSON.generate", uplevel: 1, category: :deprecated
989
+ else
990
+ warn "JSON.fast_unparse is deprecated and will be removed in json 3.0.0, just use JSON.generate", uplevel: 1
991
+ end
992
+ generate(...)
993
+ end
994
+ module_function :fast_unparse
995
+
996
+ def pretty_unparse(...)
997
+ if RUBY_VERSION >= "3.0"
998
+ warn "JSON.pretty_unparse is deprecated and will be removed in json 3.0.0, just use JSON.pretty_generate", uplevel: 1, category: :deprecated
999
+ else
1000
+ warn "JSON.pretty_unparse is deprecated and will be removed in json 3.0.0, just use JSON.pretty_generate", uplevel: 1
1001
+ end
1002
+ pretty_generate(...)
1003
+ end
1004
+ module_function :fast_unparse
1005
+
1006
+ def restore(...)
1007
+ if RUBY_VERSION >= "3.0"
1008
+ warn "JSON.restore is deprecated and will be removed in json 3.0.0, just use JSON.load", uplevel: 1, category: :deprecated
1009
+ else
1010
+ warn "JSON.restore is deprecated and will be removed in json 3.0.0, just use JSON.load", uplevel: 1
1011
+ end
1012
+ load(...)
1013
+ end
1014
+ module_function :restore
1015
+
1016
+ class << self
1017
+ private
1018
+
1019
+ def const_missing(const_name)
1020
+ case const_name
1021
+ when :PRETTY_STATE_PROTOTYPE
1022
+ if RUBY_VERSION >= "3.0"
1023
+ warn "JSON::PRETTY_STATE_PROTOTYPE is deprecated and will be removed in json 3.0.0, just use JSON.pretty_generate", uplevel: 1, category: :deprecated
1024
+ else
1025
+ warn "JSON::PRETTY_STATE_PROTOTYPE is deprecated and will be removed in json 3.0.0, just use JSON.pretty_generate", uplevel: 1
1026
+ end
1027
+ state.new(PRETTY_GENERATE_OPTIONS)
1028
+ else
1029
+ super
1030
+ end
1031
+ end
1032
+ end
1033
+ # :startdoc:
1034
+
1035
+ # JSON::Coder holds a parser and generator configuration.
1036
+ #
1037
+ # module MyApp
1038
+ # JSONC_CODER = JSON::Coder.new(
1039
+ # allow_trailing_comma: true
1040
+ # )
1041
+ # end
1042
+ #
1043
+ # MyApp::JSONC_CODER.load(document)
1044
+ #
1045
+ class Coder
1046
+ # :call-seq:
1047
+ # JSON.new(options = nil, &block)
1048
+ #
1049
+ # Argument +options+, if given, contains a \Hash of options for both parsing and generating.
1050
+ # See {Parsing Options}[rdoc-ref:JSON@Parsing+Options],
1051
+ # and {Generating Options}[rdoc-ref:JSON@Generating+Options].
1052
+ #
1053
+ # For generation, the <tt>strict: true</tt> option is always set. When a Ruby object with no native \JSON counterpart is
1054
+ # encountered, the block provided to the initialize method is invoked, and must return a Ruby object that has a native
1055
+ # \JSON counterpart:
1056
+ #
1057
+ # module MyApp
1058
+ # API_JSON_CODER = JSON::Coder.new do |object|
1059
+ # case object
1060
+ # when Time
1061
+ # object.iso8601(3)
1062
+ # else
1063
+ # object # Unknown type, will raise
1064
+ # end
1065
+ # end
1066
+ # end
1067
+ #
1068
+ # puts MyApp::API_JSON_CODER.dump(Time.now.utc) # => "2025-01-21T08:41:44.286Z"
1069
+ #
1070
+ def initialize(options = nil, &as_json)
1071
+ if options.nil?
1072
+ options = { strict: true }
1073
+ else
1074
+ options = options.dup
1075
+ options[:strict] = true
1076
+ end
1077
+ options[:as_json] = as_json if as_json
1078
+
1079
+ @state = State.new(options).freeze
1080
+ @parser_config = Ext::Parser::Config.new(ParserOptions.prepare(options)).freeze
1081
+ end
1082
+
1083
+ # call-seq:
1084
+ # dump(object) -> String
1085
+ # dump(object, io) -> io
1086
+ #
1087
+ # Serialize the given object into a \JSON document.
1088
+ def dump(object, io = nil)
1089
+ @state.generate(object, io)
1090
+ end
1091
+ alias_method :generate, :dump
1092
+
1093
+ # call-seq:
1094
+ # load(string) -> Object
1095
+ #
1096
+ # Parse the given \JSON document and return an equivalent Ruby object.
1097
+ def load(source)
1098
+ @parser_config.parse(source)
1099
+ end
1100
+ alias_method :parse, :load
1101
+
1102
+ # call-seq:
1103
+ # load(path) -> Object
1104
+ #
1105
+ # Parse the given \JSON document and return an equivalent Ruby object.
1106
+ def load_file(path)
1107
+ load(File.read(path, encoding: Encoding::UTF_8))
1108
+ end
1109
+ end
1110
+
1111
+ module GeneratorMethods
1112
+ # call-seq: to_json(*)
1113
+ #
1114
+ # Converts this object into a JSON string.
1115
+ # If this object doesn't directly maps to a JSON native type,
1116
+ # first convert it to a string (calling #to_s), then converts
1117
+ # it to a JSON string, and returns the result.
1118
+ # This is a fallback, if no special method #to_json was defined for some object.
1119
+ def to_json(state = nil, *)
1120
+ obj = case self
1121
+ when nil, false, true, Integer, Float, Array, Hash
1122
+ self
1123
+ else
1124
+ "#{self}"
1125
+ end
1126
+
1127
+ if state.nil?
1128
+ JSON::State._generate_no_fallback(obj, nil, nil)
1129
+ else
1130
+ JSON::State.from_state(state)._generate_no_fallback(obj)
1131
+ end
1132
+ end
1133
+ end
1134
+ end
1135
+
1136
+ module ::Kernel
1137
+ private
1138
+
1139
+ # Outputs _objs_ to STDOUT as JSON strings in the shortest form, that is in
1140
+ # one line.
1141
+ def j(*objs)
1142
+ if RUBY_VERSION >= "3.0"
1143
+ warn "Kernel#j is deprecated and will be removed in json 3.0.0", uplevel: 1, category: :deprecated
1144
+ else
1145
+ warn "Kernel#j is deprecated and will be removed in json 3.0.0", uplevel: 1
1146
+ end
1147
+
1148
+ objs.each do |obj|
1149
+ puts JSON.generate(obj, :allow_nan => true, :max_nesting => false)
1150
+ end
1151
+ nil
1152
+ end
1153
+
1154
+ # Outputs _objs_ to STDOUT as JSON strings in a pretty format, with
1155
+ # indentation and over many lines.
1156
+ def jj(*objs)
1157
+ if RUBY_VERSION >= "3.0"
1158
+ warn "Kernel#jj is deprecated and will be removed in json 3.0.0", uplevel: 1, category: :deprecated
1159
+ else
1160
+ warn "Kernel#jj is deprecated and will be removed in json 3.0.0", uplevel: 1
1161
+ end
1162
+
1163
+ objs.each do |obj|
1164
+ puts JSON.pretty_generate(obj, :allow_nan => true, :max_nesting => false)
1165
+ end
1166
+ nil
1167
+ end
1168
+
1169
+ # If _object_ is string-like, parse the string and return the parsed result as
1170
+ # a Ruby data structure. Otherwise, generate a JSON text from the Ruby data
1171
+ # structure object and return it.
1172
+ #
1173
+ # The _opts_ argument is passed through to generate/parse respectively. See
1174
+ # generate and parse for their documentation.
1175
+ def JSON(object, opts = nil)
1176
+ JSON[object, opts]
1177
+ end
1178
+ end
1179
+
1180
+ class Object
1181
+ include JSON::GeneratorMethods
1182
+ end