json-clone 2.20.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.
@@ -0,0 +1,755 @@
1
+ # frozen_string_literal: true
2
+ module JSON
3
+ module TruffleRuby
4
+ module Generator
5
+ MAP = {
6
+ "\x0" => '\u0000',
7
+ "\x1" => '\u0001',
8
+ "\x2" => '\u0002',
9
+ "\x3" => '\u0003',
10
+ "\x4" => '\u0004',
11
+ "\x5" => '\u0005',
12
+ "\x6" => '\u0006',
13
+ "\x7" => '\u0007',
14
+ "\b" => '\b',
15
+ "\t" => '\t',
16
+ "\n" => '\n',
17
+ "\xb" => '\u000b',
18
+ "\f" => '\f',
19
+ "\r" => '\r',
20
+ "\xe" => '\u000e',
21
+ "\xf" => '\u000f',
22
+ "\x10" => '\u0010',
23
+ "\x11" => '\u0011',
24
+ "\x12" => '\u0012',
25
+ "\x13" => '\u0013',
26
+ "\x14" => '\u0014',
27
+ "\x15" => '\u0015',
28
+ "\x16" => '\u0016',
29
+ "\x17" => '\u0017',
30
+ "\x18" => '\u0018',
31
+ "\x19" => '\u0019',
32
+ "\x1a" => '\u001a',
33
+ "\x1b" => '\u001b',
34
+ "\x1c" => '\u001c',
35
+ "\x1d" => '\u001d',
36
+ "\x1e" => '\u001e',
37
+ "\x1f" => '\u001f',
38
+ '"' => '\"',
39
+ '\\' => '\\\\',
40
+ }.freeze # :nodoc:
41
+
42
+ SCRIPT_SAFE_MAP = MAP.merge(
43
+ '/' => '\\/',
44
+ "\u2028" => '\u2028',
45
+ "\u2029" => '\u2029',
46
+ ).freeze
47
+
48
+ SCRIPT_SAFE_ESCAPE_PATTERN = /[\/"\\\x0-\x1f\u2028-\u2029]/
49
+
50
+ def self.native_type?(value) # :nodoc:
51
+ (false == value || true == value || nil == value || String === value || Symbol === value || Array === value || Hash === value || Integer === value || Float === value || Fragment === value)
52
+ end
53
+
54
+ def self.native_key?(key) # :nodoc:
55
+ (Symbol === key || String === key)
56
+ end
57
+
58
+ def self.valid_encoding?(string) # :nodoc:
59
+ return false unless string.encoding == ::Encoding::UTF_8 || string.encoding == ::Encoding::US_ASCII
60
+ string.is_a?(Symbol) || string.valid_encoding?
61
+ end
62
+
63
+ # Convert a UTF8 encoded Ruby string _string_ to a JSON string, encoded with
64
+ # UTF16 big endian characters as \u????, and return it.
65
+ def self.utf8_to_json(string, script_safe = false) # :nodoc:
66
+ if script_safe
67
+ if SCRIPT_SAFE_ESCAPE_PATTERN.match?(string)
68
+ string.gsub(SCRIPT_SAFE_ESCAPE_PATTERN, SCRIPT_SAFE_MAP)
69
+ else
70
+ string
71
+ end
72
+ else
73
+ if /["\\\x0-\x1f]/.match?(string)
74
+ string.gsub(/["\\\x0-\x1f]/, MAP)
75
+ else
76
+ string
77
+ end
78
+ end
79
+ end
80
+
81
+ def self.utf8_to_json_ascii(original_string, script_safe = false) # :nodoc:
82
+ string = original_string.b
83
+ map = script_safe ? SCRIPT_SAFE_MAP : MAP
84
+ string.gsub!(/[\/"\\\x0-\x1f]/n) { map[$&] || $& }
85
+ string.gsub!(/(
86
+ (?:
87
+ [\xc2-\xdf][\x80-\xbf] |
88
+ [\xe0-\xef][\x80-\xbf]{2} |
89
+ [\xf0-\xf4][\x80-\xbf]{3}
90
+ )+ |
91
+ [\x80-\xc1\xf5-\xff] # invalid
92
+ )/nx) { |c|
93
+ c.size == 1 and raise GeneratorError.new("invalid utf8 byte: '#{c}'", original_string)
94
+ s = c.encode(::Encoding::UTF_16BE, ::Encoding::UTF_8).unpack('H*')[0]
95
+ s.force_encoding(::Encoding::BINARY)
96
+ s.gsub!(/.{4}/n, '\\\\u\&')
97
+ s.force_encoding(::Encoding::UTF_8)
98
+ }
99
+ string.force_encoding(::Encoding::UTF_8)
100
+ string
101
+ rescue => e
102
+ raise GeneratorError.new(e.message, original_string)
103
+ end
104
+
105
+ def self.valid_utf8?(string)
106
+ encoding = string.encoding
107
+ (encoding == Encoding::UTF_8 || encoding == Encoding::ASCII) &&
108
+ string.valid_encoding?
109
+ end
110
+
111
+ # This class is used to create State instances, that are use to hold data
112
+ # while generating a JSON text from a Ruby data structure.
113
+ class State
114
+ def self.generate(obj, opts = nil, io = nil)
115
+ new(opts).generate(obj, io)
116
+ end
117
+
118
+ # Creates a State object from _opts_, which ought to be Hash to create
119
+ # a new State instance configured by _opts_, something else to create
120
+ # an unconfigured instance. If _opts_ is a State object, it is just
121
+ # returned.
122
+ def self.from_state(opts)
123
+ if opts
124
+ case
125
+ when self === opts
126
+ return opts
127
+ when opts.respond_to?(:to_hash)
128
+ return new(opts.to_hash)
129
+ when opts.respond_to?(:to_h)
130
+ return new(opts.to_h)
131
+ end
132
+ end
133
+ new
134
+ end
135
+
136
+ # Instantiates a new State object, configured by _opts_.
137
+ #
138
+ # _opts_ can have the following keys:
139
+ #
140
+ # * *indent*: a string used to indent levels (default: ''),
141
+ # * *space*: a string that is put after, a : or , delimiter (default: ''),
142
+ # * *space_before*: a string that is put before a : pair delimiter (default: ''),
143
+ # * *object_nl*: a string that is put at the end of a JSON object (default: ''),
144
+ # * *array_nl*: a string that is put at the end of a JSON array (default: ''),
145
+ # * *script_safe*: true if U+2028, U+2029 and forward slash (/) should be escaped
146
+ # as to make the JSON object safe to interpolate in a script tag (default: false).
147
+ # * *check_circular*: is deprecated now, use the :max_nesting option instead,
148
+ # * *max_nesting*: sets the maximum level of data structure nesting in
149
+ # the generated JSON, max_nesting = 0 if no maximum should be checked.
150
+ # * *allow_nan*: true if NaN, Infinity, and -Infinity should be
151
+ # generated, otherwise an exception is thrown, if these values are
152
+ # encountered. This options defaults to false.
153
+ def initialize(opts = nil)
154
+ @indent = ''
155
+ @space = ''
156
+ @space_before = ''
157
+ @object_nl = ''
158
+ @array_nl = ''
159
+ @allow_nan = false
160
+ @ascii_only = false
161
+ @as_json = false
162
+ @depth = 0
163
+ @buffer_initial_length = 1024
164
+ @script_safe = false
165
+ @strict = false
166
+ @max_nesting = 100
167
+ configure(opts) if opts
168
+ end
169
+
170
+ # This string is used to indent levels in the JSON text.
171
+ attr_accessor :indent
172
+
173
+ # This string is used to insert a space between the tokens in a JSON
174
+ # string.
175
+ attr_accessor :space
176
+
177
+ # This string is used to insert a space before the ':' in JSON objects.
178
+ attr_accessor :space_before
179
+
180
+ # This string is put at the end of a line that holds a JSON object (or
181
+ # Hash).
182
+ attr_accessor :object_nl
183
+
184
+ # This string is put at the end of a line that holds a JSON array.
185
+ attr_accessor :array_nl
186
+
187
+ # This proc converts unsupported types into native JSON types.
188
+ attr_accessor :as_json
189
+
190
+ # This integer returns the maximum level of data structure nesting in
191
+ # the generated JSON, max_nesting = 0 if no maximum is checked.
192
+ attr_accessor :max_nesting
193
+
194
+ # If this attribute is set to true, forward slashes will be escaped in
195
+ # all json strings.
196
+ attr_accessor :script_safe
197
+
198
+ # If this attribute is set to true, attempting to serialize types not
199
+ # supported by the JSON spec will raise a JSON::GeneratorError
200
+ attr_accessor :strict
201
+
202
+ # :stopdoc:
203
+ attr_reader :buffer_initial_length
204
+
205
+ def buffer_initial_length=(length)
206
+ if length > 0
207
+ @buffer_initial_length = length
208
+ end
209
+ end
210
+ # :startdoc:
211
+
212
+ # This integer returns the current depth data structure nesting in the
213
+ # generated JSON.
214
+ attr_reader :depth
215
+
216
+ def depth=(depth)
217
+ if depth.negative?
218
+ raise ArgumentError, "depth must be >= 0 (got #{depth})"
219
+ end
220
+ @depth = depth
221
+ end
222
+
223
+ def check_max_nesting # :nodoc:
224
+ return if @max_nesting.zero?
225
+ current_nesting = depth + 1
226
+ current_nesting > @max_nesting and
227
+ raise NestingError, "nesting of #{current_nesting} is too deep. Did you try to serialize objects with circular references?"
228
+ end
229
+
230
+ # Returns true, if circular data structures are checked,
231
+ # otherwise returns false.
232
+ def check_circular?
233
+ !@max_nesting.zero?
234
+ end
235
+
236
+ # Returns true if NaN, Infinity, and -Infinity should be considered as
237
+ # valid JSON and output.
238
+ def allow_nan?
239
+ @allow_nan
240
+ end
241
+
242
+ # Returns true, if only ASCII characters should be generated. Otherwise
243
+ # returns false.
244
+ def ascii_only?
245
+ @ascii_only
246
+ end
247
+
248
+ # Returns true, if forward slashes are escaped. Otherwise returns false.
249
+ def script_safe?
250
+ @script_safe
251
+ end
252
+
253
+ # Returns true, if strict mode is enabled. Otherwise returns false.
254
+ # Strict mode only allow serializing JSON native types: Hash, Array,
255
+ # String, Integer, Float, true, false and nil.
256
+ def strict?
257
+ @strict
258
+ end
259
+
260
+ # Configure this State instance with the Hash _opts_, and return
261
+ # itself.
262
+ def configure(opts)
263
+ if opts.respond_to?(:to_hash)
264
+ opts = opts.to_hash
265
+ elsif opts.respond_to?(:to_h)
266
+ opts = opts.to_h
267
+ else
268
+ raise TypeError, "can't convert #{opts.class} into Hash"
269
+ end
270
+
271
+ if opts[:depth]&.negative?
272
+ raise ArgumentError, "depth must be >= 0 (got #{opts[:depth]})"
273
+ end
274
+
275
+ opts.each do |key, value|
276
+ instance_variable_set "@#{key}", value
277
+ end
278
+
279
+ # NOTE: If adding new instance variables here, check whether #generate should check them for #generate_json
280
+ @indent = opts[:indent] || '' if opts.key?(:indent)
281
+ @space = opts[:space] || '' if opts.key?(:space)
282
+ @space_before = opts[:space_before] || '' if opts.key?(:space_before)
283
+ @object_nl = opts[:object_nl] || '' if opts.key?(:object_nl)
284
+ @array_nl = opts[:array_nl] || '' if opts.key?(:array_nl)
285
+ @allow_nan = !!opts[:allow_nan] if opts.key?(:allow_nan)
286
+ @as_json = opts[:as_json].to_proc if opts[:as_json]
287
+ @ascii_only = opts[:ascii_only] if opts.key?(:ascii_only)
288
+ @depth = opts[:depth] || 0
289
+ @buffer_initial_length ||= opts[:buffer_initial_length]
290
+
291
+ @script_safe = if opts.key?(:script_safe)
292
+ !!opts[:script_safe]
293
+ elsif opts.key?(:escape_slash)
294
+ !!opts[:escape_slash]
295
+ else
296
+ false
297
+ end
298
+
299
+ if opts.key?(:allow_duplicate_key)
300
+ @allow_duplicate_key = !!opts[:allow_duplicate_key]
301
+ else
302
+ @allow_duplicate_key = nil # nil is deprecation
303
+ end
304
+
305
+ @strict = !!opts[:strict] if opts.key?(:strict)
306
+
307
+ if !opts.key?(:max_nesting) # defaults to 100
308
+ @max_nesting = 100
309
+ elsif opts[:max_nesting]
310
+ unless opts[:max_nesting].is_a?(Integer)
311
+ raise TypeError, ":max_nesting must be an Integer, got: #{opts[:max_nesting].class}"
312
+ end
313
+ @max_nesting = opts[:max_nesting]
314
+ else
315
+ @max_nesting = 0
316
+ end
317
+ self
318
+ end
319
+ alias merge configure
320
+
321
+ def allow_duplicate_key? # :nodoc:
322
+ @allow_duplicate_key
323
+ end
324
+
325
+ # Returns the configuration instance variables as a hash, that can be
326
+ # passed to the configure method.
327
+ def to_h
328
+ result = {}
329
+ instance_variables.each do |iv|
330
+ key = iv.to_s[1..-1]
331
+ result[key.to_sym] = instance_variable_get(iv)
332
+ end
333
+
334
+ if result[:allow_duplicate_key].nil?
335
+ result.delete(:allow_duplicate_key)
336
+ end
337
+
338
+ result
339
+ end
340
+
341
+ alias to_hash to_h
342
+
343
+ # Generates a valid JSON document from object +obj+ and
344
+ # returns the result. If no valid JSON document can be
345
+ # created this method raises a
346
+ # GeneratorError exception.
347
+ def generate(obj, anIO = nil)
348
+ return dup.generate(obj, anIO) if frozen?
349
+
350
+ depth = @depth
351
+ if @indent.empty? and @space.empty? and @space_before.empty? and @object_nl.empty? and @array_nl.empty? and
352
+ !@ascii_only and !@script_safe and @max_nesting == 0 and (!@strict || Symbol === obj)
353
+ result = generate_json(obj, ''.dup)
354
+ else
355
+ result = obj.to_json(self)
356
+ end
357
+ JSON::TruffleRuby::Generator.valid_utf8?(result) or raise GeneratorError.new(
358
+ "source sequence #{result.inspect} is illegal/malformed utf-8",
359
+ obj
360
+ )
361
+ if anIO
362
+ anIO.write(result)
363
+ anIO
364
+ else
365
+ result
366
+ end
367
+ ensure
368
+ @depth = depth unless frozen?
369
+ end
370
+
371
+ # Handles @allow_nan, @buffer_initial_length, other ivars must be the default value (see above)
372
+ private def generate_json(obj, buf)
373
+ case obj
374
+ when Hash
375
+ buf << '{'
376
+ first = true
377
+ key_type = nil
378
+ obj.each_pair do |k,v|
379
+ if first
380
+ key_type = k.class
381
+ else
382
+ if key_type && !@allow_duplicate_key && key_type != k.class
383
+ key_type = nil # stop checking
384
+ JSON.send(:on_mixed_keys_hash, obj, !@allow_duplicate_key.nil?)
385
+ end
386
+ buf << ','
387
+ end
388
+
389
+ key_str = k.to_s
390
+ if key_str.class == String
391
+ fast_serialize_string(key_str, buf)
392
+ elsif key_str.is_a?(String)
393
+ generate_json(key_str, buf)
394
+ else
395
+ raise TypeError, "#{k.class}#to_s returns an instance of #{key_str.class}, expected a String"
396
+ end
397
+
398
+ buf << ':'
399
+ generate_json(v, buf)
400
+ first = false
401
+ end
402
+ buf << '}'
403
+ when Array
404
+ buf << '['
405
+ first = true
406
+ obj.each do |e|
407
+ buf << ',' unless first
408
+ generate_json(e, buf)
409
+ first = false
410
+ end
411
+ buf << ']'
412
+ when String
413
+ if obj.class == String
414
+ fast_serialize_string(obj, buf)
415
+ else
416
+ buf << obj.to_json(self)
417
+ end
418
+ when Integer
419
+ buf << obj.to_s
420
+ when Symbol
421
+ if @strict
422
+ fast_serialize_string(obj.name, buf)
423
+ else
424
+ buf << obj.to_json(self)
425
+ end
426
+ else
427
+ # Note: Float is handled this way since Float#to_s is slow anyway
428
+ buf << obj.to_json(self)
429
+ end
430
+ end
431
+
432
+ # Assumes !@ascii_only, !@script_safe
433
+ private def fast_serialize_string(string, buf) # :nodoc:
434
+ buf << '"'
435
+ unless string.encoding == ::Encoding::UTF_8
436
+ begin
437
+ string = string.encode(::Encoding::UTF_8)
438
+ rescue Encoding::UndefinedConversionError => error
439
+ raise GeneratorError.new(error.message, string)
440
+ end
441
+ end
442
+ raise GeneratorError.new("source sequence is illegal/malformed utf-8", string) unless string.valid_encoding?
443
+
444
+ if /["\\\x0-\x1f]/.match?(string)
445
+ buf << string.gsub(/["\\\x0-\x1f]/, MAP)
446
+ else
447
+ buf << string
448
+ end
449
+ buf << '"'
450
+ end
451
+
452
+ # Return the value returned by method +name+.
453
+ def [](name)
454
+ ::JSON.deprecation_warning("JSON::State#[] is deprecated and will be removed in json 3.0.0")
455
+
456
+ if respond_to?(name)
457
+ __send__(name)
458
+ else
459
+ instance_variable_get("@#{name}") if
460
+ instance_variables.include?("@#{name}".to_sym) # avoid warning
461
+ end
462
+ end
463
+
464
+ def []=(name, value)
465
+ ::JSON.deprecation_warning("JSON::State#[]= is deprecated and will be removed in json 3.0.0")
466
+
467
+ if respond_to?(name_writer = "#{name}=")
468
+ __send__ name_writer, value
469
+ else
470
+ instance_variable_set "@#{name}", value
471
+ end
472
+ end
473
+ end
474
+
475
+ module GeneratorMethods
476
+ module Object
477
+ # Converts this object to a string (calling #to_s), converts
478
+ # it to a JSON string, and returns the result. This is a fallback, if no
479
+ # special method #to_json was defined for some object.
480
+ def to_json(state = nil, *)
481
+ state = State.from_state(state) if state
482
+ if state&.strict?
483
+ value = self
484
+ if state.strict? && !Generator.native_type?(value)
485
+ if state.as_json
486
+ value = state.as_json.call(value, false)
487
+ unless Generator.native_type?(value)
488
+ raise GeneratorError.new("#{value.class} returned by #{state.as_json} not allowed in JSON", value)
489
+ end
490
+ value.to_json(state)
491
+ else
492
+ raise GeneratorError.new("#{value.class} not allowed in JSON", value)
493
+ end
494
+ end
495
+ else
496
+ to_s.to_json
497
+ end
498
+ end
499
+ end
500
+
501
+ module Hash
502
+ # Returns a JSON string containing a JSON object, that is unparsed from
503
+ # this Hash instance.
504
+ # _state_ is a JSON::State object, that can also be used to configure the
505
+ # produced JSON string output further.
506
+ # _depth_ is used to find out nesting depth, to indent accordingly.
507
+ def to_json(state = nil, *)
508
+ state = State.from_state(state)
509
+ depth = state.depth
510
+ state.check_max_nesting
511
+ json_transform(state)
512
+ ensure
513
+ state.depth = depth
514
+ end
515
+
516
+ private
517
+
518
+ def json_transform(state)
519
+ depth = state.depth += 1
520
+
521
+ if empty?
522
+ state.depth -= 1
523
+ return +'{}'
524
+ end
525
+
526
+ delim = ",#{state.object_nl}"
527
+ result = "{#{state.object_nl}"
528
+ first = true
529
+ key_type = nil
530
+ indent = !state.object_nl.empty?
531
+ each { |key, value|
532
+ if first
533
+ key_type = key.class
534
+ else
535
+ if key_type && !state.allow_duplicate_key? && key_type != key.class
536
+ key_type = nil # stop checking
537
+ JSON.send(:on_mixed_keys_hash, self, state.allow_duplicate_key? == false)
538
+ end
539
+ result << delim
540
+ end
541
+ result << state.indent * depth if indent
542
+
543
+ if state.strict?
544
+ if state.as_json && (!Generator.native_key?(key) || !Generator.valid_encoding?(key))
545
+ key = state.as_json.call(key, true)
546
+ end
547
+
548
+ unless Generator.native_key?(key)
549
+ raise GeneratorError.new("#{key.class} not allowed as object key in JSON", key)
550
+ end
551
+
552
+ unless Generator.valid_encoding?(key)
553
+ raise GeneratorError.new("source sequence is illegal/malformed utf-8", key)
554
+ end
555
+ end
556
+
557
+ key_str = key.to_s
558
+ if key_str.is_a?(String)
559
+ key_json = key_str.to_json(state)
560
+ else
561
+ raise TypeError, "#{key.class}#to_s returns an instance of #{key_str.class}, expected a String"
562
+ end
563
+
564
+ result = "#{result}#{key_json}#{state.space_before}:#{state.space}"
565
+ if state.strict? && !Generator.native_type?(value)
566
+ if state.as_json
567
+ value = state.as_json.call(value, false)
568
+ unless Generator.native_type?(value)
569
+ raise GeneratorError.new("#{value.class} returned by #{state.as_json} not allowed in JSON", value)
570
+ end
571
+ result << value.to_json(state)
572
+ state.depth = depth
573
+ else
574
+ raise GeneratorError.new("#{value.class} not allowed in JSON", value)
575
+ end
576
+ elsif value.respond_to?(:to_json)
577
+ result << value.to_json(state)
578
+ state.depth = depth
579
+ else
580
+ result << %{"#{String(value)}"}
581
+ end
582
+ first = false
583
+ }
584
+ depth -= 1
585
+ unless first
586
+ result << state.object_nl
587
+ result << state.indent * depth if indent
588
+ end
589
+ result << '}'
590
+ result
591
+ end
592
+ end
593
+
594
+ module Array
595
+ # Returns a JSON string containing a JSON array, that is unparsed from
596
+ # this Array instance.
597
+ # _state_ is a JSON::State object, that can also be used to configure the
598
+ # produced JSON string output further.
599
+ def to_json(state = nil, *)
600
+ state = State.from_state(state)
601
+ depth = state.depth
602
+ state.check_max_nesting
603
+ json_transform(state)
604
+ ensure
605
+ state.depth = depth
606
+ end
607
+
608
+ private
609
+
610
+ def json_transform(state)
611
+ depth = state.depth += 1
612
+
613
+ if empty?
614
+ state.depth -= 1
615
+ return +'[]'
616
+ end
617
+
618
+ result = '['.dup
619
+ if state.array_nl.empty?
620
+ delim = ","
621
+ else
622
+ result << state.array_nl
623
+ delim = ",#{state.array_nl}"
624
+ end
625
+
626
+ first = true
627
+ indent = !state.array_nl.empty?
628
+ each { |value|
629
+ result << delim unless first
630
+ result << state.indent * depth if indent
631
+ if state.strict? && !Generator.native_type?(value)
632
+ if state.as_json
633
+ value = state.as_json.call(value, false)
634
+ unless Generator.native_type?(value)
635
+ raise GeneratorError.new("#{value.class} returned by #{state.as_json} not allowed in JSON", value)
636
+ end
637
+ result << value.to_json(state)
638
+ else
639
+ raise GeneratorError.new("#{value.class} not allowed in JSON", value)
640
+ end
641
+ elsif value.respond_to?(:to_json)
642
+ result << value.to_json(state)
643
+ state.depth = depth
644
+ else
645
+ result << %{"#{String(value)}"}
646
+ end
647
+ first = false
648
+ }
649
+ depth -= 1
650
+ result << state.array_nl
651
+ result << state.indent * depth if indent
652
+ result << ']'
653
+ end
654
+ end
655
+
656
+ module Integer
657
+ # Returns a JSON string representation for this Integer number.
658
+ def to_json(*) to_s end
659
+ end
660
+
661
+ module Float
662
+ # Returns a JSON string representation for this Float number.
663
+ def to_json(state = nil, *args)
664
+ state = State.from_state(state)
665
+ if infinite? || nan?
666
+ if state.allow_nan?
667
+ to_s
668
+ elsif state.strict? && state.as_json
669
+ casted_value = state.as_json.call(self, false)
670
+
671
+ if casted_value.equal?(self)
672
+ raise GeneratorError.new("#{self} not allowed in JSON", self)
673
+ end
674
+ unless Generator.native_type?(casted_value)
675
+ raise GeneratorError.new("#{casted_value.class} returned by #{state.as_json} not allowed in JSON", casted_value)
676
+ end
677
+
678
+ state.check_max_nesting
679
+ state.depth += 1
680
+ result = casted_value.to_json(state, *args)
681
+ state.depth -= 1
682
+ result
683
+ else
684
+ raise GeneratorError.new("#{self} not allowed in JSON", self)
685
+ end
686
+ else
687
+ to_s
688
+ end
689
+ end
690
+ end
691
+
692
+ module Symbol
693
+ def to_json(state = nil, *args)
694
+ state = State.from_state(state)
695
+ if state.strict?
696
+ name.to_json(state, *args)
697
+ else
698
+ super
699
+ end
700
+ end
701
+ end
702
+
703
+ module String
704
+ # This string should be encoded with UTF-8 A call to this method
705
+ # returns a JSON string encoded with UTF16 big endian characters as
706
+ # \u????.
707
+ def to_json(state = nil, *args)
708
+ state = State.from_state(state)
709
+ string = self
710
+
711
+ if state.strict? && state.as_json
712
+ unless Generator.valid_encoding?(string)
713
+ string = state.as_json.call(string, false)
714
+ unless string.is_a?(::String)
715
+ return string.to_json(state, *args)
716
+ end
717
+ end
718
+ end
719
+
720
+ if string.encoding == ::Encoding::UTF_8
721
+ unless string.valid_encoding?
722
+ raise GeneratorError.new("source sequence is illegal/malformed utf-8", self)
723
+ end
724
+ else
725
+ string = string.encode(::Encoding::UTF_8)
726
+ end
727
+
728
+ if state.ascii_only?
729
+ %("#{JSON::TruffleRuby::Generator.utf8_to_json_ascii(string, state.script_safe)}")
730
+ else
731
+ %("#{JSON::TruffleRuby::Generator.utf8_to_json(string, state.script_safe)}")
732
+ end
733
+ rescue Encoding::UndefinedConversionError => error
734
+ raise ::JSON::GeneratorError.new(error.message, self)
735
+ end
736
+ end
737
+
738
+ module TrueClass
739
+ # Returns a JSON string for true: 'true'.
740
+ def to_json(*) +'true' end
741
+ end
742
+
743
+ module FalseClass
744
+ # Returns a JSON string for false: 'false'.
745
+ def to_json(*) +'false' end
746
+ end
747
+
748
+ module NilClass
749
+ # Returns a JSON string for nil: 'null'.
750
+ def to_json(*) +'null' end
751
+ end
752
+ end
753
+ end
754
+ end
755
+ end