json 2.7.4 → 2.10.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.
data/lib/json/ext.rb CHANGED
@@ -6,17 +6,37 @@ module JSON
6
6
  # This module holds all the modules/classes that implement JSON's
7
7
  # functionality as C extensions.
8
8
  module Ext
9
+ class Parser
10
+ class << self
11
+ def parse(...)
12
+ new(...).parse
13
+ end
14
+ alias_method :parse, :parse # Allow redefinition by extensions
15
+ end
16
+
17
+ def initialize(source, opts = nil)
18
+ @source = source
19
+ @config = Config.new(opts)
20
+ end
21
+
22
+ def source
23
+ @source.dup
24
+ end
25
+
26
+ def parse
27
+ @config.parse(@source)
28
+ end
29
+ end
30
+
31
+ require 'json/ext/parser'
32
+ Ext::Parser::Config = Ext::ParserConfig
33
+ JSON.parser = Ext::Parser
34
+
9
35
  if RUBY_ENGINE == 'truffleruby'
10
- require 'json/ext/parser'
11
- require 'json/pure'
12
- $DEBUG and warn "Using Ext extension for JSON parser and Pure library for JSON generator."
13
- JSON.parser = Parser
14
- JSON.generator = JSON::Pure::Generator
36
+ require 'json/truffle_ruby/generator'
37
+ JSON.generator = ::JSON::TruffleRuby::Generator
15
38
  else
16
- require 'json/ext/parser'
17
39
  require 'json/ext/generator'
18
- $DEBUG and warn "Using Ext extension for JSON."
19
- JSON.parser = Parser
20
40
  JSON.generator = Generator
21
41
  end
22
42
  end
@@ -1,116 +1,123 @@
1
1
  # frozen_string_literal: true
2
2
  module JSON
3
- MAP = {
4
- "\x0" => '\u0000',
5
- "\x1" => '\u0001',
6
- "\x2" => '\u0002',
7
- "\x3" => '\u0003',
8
- "\x4" => '\u0004',
9
- "\x5" => '\u0005',
10
- "\x6" => '\u0006',
11
- "\x7" => '\u0007',
12
- "\b" => '\b',
13
- "\t" => '\t',
14
- "\n" => '\n',
15
- "\xb" => '\u000b',
16
- "\f" => '\f',
17
- "\r" => '\r',
18
- "\xe" => '\u000e',
19
- "\xf" => '\u000f',
20
- "\x10" => '\u0010',
21
- "\x11" => '\u0011',
22
- "\x12" => '\u0012',
23
- "\x13" => '\u0013',
24
- "\x14" => '\u0014',
25
- "\x15" => '\u0015',
26
- "\x16" => '\u0016',
27
- "\x17" => '\u0017',
28
- "\x18" => '\u0018',
29
- "\x19" => '\u0019',
30
- "\x1a" => '\u001a',
31
- "\x1b" => '\u001b',
32
- "\x1c" => '\u001c',
33
- "\x1d" => '\u001d',
34
- "\x1e" => '\u001e',
35
- "\x1f" => '\u001f',
36
- '"' => '\"',
37
- '\\' => '\\\\',
38
- }.freeze # :nodoc:
39
-
40
- ESCAPE_PATTERN = /[\/"\\\x0-\x1f]/n # :nodoc:
41
-
42
- SCRIPT_SAFE_MAP = MAP.merge(
43
- '/' => '\\/',
44
- "\u2028".b => '\u2028',
45
- "\u2029".b => '\u2029',
46
- ).freeze
47
-
48
- SCRIPT_SAFE_ESCAPE_PATTERN = Regexp.union(ESCAPE_PATTERN, "\u2028".b, "\u2029".b)
49
-
50
- # Convert a UTF8 encoded Ruby string _string_ to a JSON string, encoded with
51
- # UTF16 big endian characters as \u????, and return it.
52
- def utf8_to_json(string, script_safe = false) # :nodoc:
53
- string = string.b
54
- if script_safe
55
- string.gsub!(SCRIPT_SAFE_ESCAPE_PATTERN) { SCRIPT_SAFE_MAP[$&] || $& }
56
- else
57
- string.gsub!(ESCAPE_PATTERN) { MAP[$&] || $& }
58
- end
59
- string.force_encoding(::Encoding::UTF_8)
60
- string
61
- end
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
+ # Convert a UTF8 encoded Ruby string _string_ to a JSON string, encoded with
51
+ # UTF16 big endian characters as \u????, and return it.
52
+ def self.utf8_to_json(string, script_safe = false) # :nodoc:
53
+ if script_safe
54
+ if SCRIPT_SAFE_ESCAPE_PATTERN.match?(string)
55
+ string.gsub(SCRIPT_SAFE_ESCAPE_PATTERN, SCRIPT_SAFE_MAP)
56
+ else
57
+ string
58
+ end
59
+ else
60
+ if /["\\\x0-\x1f]/.match?(string)
61
+ string.gsub(/["\\\x0-\x1f]/, MAP)
62
+ else
63
+ string
64
+ end
65
+ end
66
+ end
62
67
 
63
- def utf8_to_json_ascii(string, script_safe = false) # :nodoc:
64
- string = string.b
65
- map = script_safe ? SCRIPT_SAFE_MAP : MAP
66
- string.gsub!(/[\/"\\\x0-\x1f]/n) { map[$&] || $& }
67
- string.gsub!(/(
68
- (?:
69
- [\xc2-\xdf][\x80-\xbf] |
70
- [\xe0-\xef][\x80-\xbf]{2} |
71
- [\xf0-\xf4][\x80-\xbf]{3}
72
- )+ |
73
- [\x80-\xc1\xf5-\xff] # invalid
74
- )/nx) { |c|
75
- c.size == 1 and raise GeneratorError, "invalid utf8 byte: '#{c}'"
76
- s = c.encode(::Encoding::UTF_16BE, ::Encoding::UTF_8).unpack('H*')[0]
77
- s.force_encoding(::Encoding::ASCII_8BIT)
78
- s.gsub!(/.{4}/n, '\\\\u\&')
79
- s.force_encoding(::Encoding::UTF_8)
80
- }
81
- string.force_encoding(::Encoding::UTF_8)
82
- string
83
- rescue => e
84
- raise GeneratorError.wrap(e)
85
- end
68
+ def self.utf8_to_json_ascii(original_string, script_safe = false) # :nodoc:
69
+ string = original_string.b
70
+ map = script_safe ? SCRIPT_SAFE_MAP : MAP
71
+ string.gsub!(/[\/"\\\x0-\x1f]/n) { map[$&] || $& }
72
+ string.gsub!(/(
73
+ (?:
74
+ [\xc2-\xdf][\x80-\xbf] |
75
+ [\xe0-\xef][\x80-\xbf]{2} |
76
+ [\xf0-\xf4][\x80-\xbf]{3}
77
+ )+ |
78
+ [\x80-\xc1\xf5-\xff] # invalid
79
+ )/nx) { |c|
80
+ c.size == 1 and raise GeneratorError.new("invalid utf8 byte: '#{c}'", original_string)
81
+ s = c.encode(::Encoding::UTF_16BE, ::Encoding::UTF_8).unpack('H*')[0]
82
+ s.force_encoding(::Encoding::BINARY)
83
+ s.gsub!(/.{4}/n, '\\\\u\&')
84
+ s.force_encoding(::Encoding::UTF_8)
85
+ }
86
+ string.force_encoding(::Encoding::UTF_8)
87
+ string
88
+ rescue => e
89
+ raise GeneratorError.new(e.message, original_string)
90
+ end
86
91
 
87
- def valid_utf8?(string)
88
- encoding = string.encoding
89
- (encoding == Encoding::UTF_8 || encoding == Encoding::ASCII) &&
90
- string.valid_encoding?
91
- end
92
- module_function :utf8_to_json, :utf8_to_json_ascii, :valid_utf8?
92
+ def self.valid_utf8?(string)
93
+ encoding = string.encoding
94
+ (encoding == Encoding::UTF_8 || encoding == Encoding::ASCII) &&
95
+ string.valid_encoding?
96
+ end
93
97
 
94
- module Pure
95
- module Generator
96
98
  # This class is used to create State instances, that are use to hold data
97
99
  # while generating a JSON text from a Ruby data structure.
98
100
  class State
101
+ def self.generate(obj, opts = nil, io = nil)
102
+ new(opts).generate(obj, io)
103
+ end
104
+
99
105
  # Creates a State object from _opts_, which ought to be Hash to create
100
106
  # a new State instance configured by _opts_, something else to create
101
107
  # an unconfigured instance. If _opts_ is a State object, it is just
102
108
  # returned.
103
109
  def self.from_state(opts)
104
- case
105
- when self === opts
106
- opts
107
- when opts.respond_to?(:to_hash)
108
- new(opts.to_hash)
109
- when opts.respond_to?(:to_h)
110
- new(opts.to_h)
111
- else
112
- SAFE_STATE_PROTOTYPE.dup
110
+ if opts
111
+ case
112
+ when self === opts
113
+ return opts
114
+ when opts.respond_to?(:to_hash)
115
+ return new(opts.to_hash)
116
+ when opts.respond_to?(:to_h)
117
+ return new(opts.to_h)
118
+ end
113
119
  end
120
+ SAFE_STATE_PROTOTYPE.dup
114
121
  end
115
122
 
116
123
  # Instantiates a new State object, configured by _opts_.
@@ -130,7 +137,7 @@ module JSON
130
137
  # * *allow_nan*: true if NaN, Infinity, and -Infinity should be
131
138
  # generated, otherwise an exception is thrown, if these values are
132
139
  # encountered. This options defaults to false.
133
- def initialize(opts = {})
140
+ def initialize(opts = nil)
134
141
  @indent = ''
135
142
  @space = ''
136
143
  @space_before = ''
@@ -138,10 +145,13 @@ module JSON
138
145
  @array_nl = ''
139
146
  @allow_nan = false
140
147
  @ascii_only = false
141
- @script_safe = false
142
- @strict = false
148
+ @as_json = false
149
+ @depth = 0
143
150
  @buffer_initial_length = 1024
144
- configure opts
151
+ @script_safe = false
152
+ @strict = false
153
+ @max_nesting = 100
154
+ configure(opts) if opts
145
155
  end
146
156
 
147
157
  # This string is used to indent levels in the JSON text.
@@ -161,6 +171,9 @@ module JSON
161
171
  # This string is put at the end of a line that holds a JSON array.
162
172
  attr_accessor :array_nl
163
173
 
174
+ # This proc converts unsupported types into native JSON types.
175
+ attr_accessor :as_json
176
+
164
177
  # This integer returns the maximum level of data structure nesting in
165
178
  # the generated JSON, max_nesting = 0 if no maximum is checked.
166
179
  attr_accessor :max_nesting
@@ -239,13 +252,14 @@ module JSON
239
252
  end
240
253
 
241
254
  # NOTE: If adding new instance variables here, check whether #generate should check them for #generate_json
242
- @indent = opts[:indent] if opts.key?(:indent)
243
- @space = opts[:space] if opts.key?(:space)
244
- @space_before = opts[:space_before] if opts.key?(:space_before)
245
- @object_nl = opts[:object_nl] if opts.key?(:object_nl)
246
- @array_nl = opts[:array_nl] if opts.key?(:array_nl)
247
- @allow_nan = !!opts[:allow_nan] if opts.key?(:allow_nan)
248
- @ascii_only = opts[:ascii_only] if opts.key?(:ascii_only)
255
+ @indent = opts[:indent] || '' if opts.key?(:indent)
256
+ @space = opts[:space] || '' if opts.key?(:space)
257
+ @space_before = opts[:space_before] || '' if opts.key?(:space_before)
258
+ @object_nl = opts[:object_nl] || '' if opts.key?(:object_nl)
259
+ @array_nl = opts[:array_nl] || '' if opts.key?(:array_nl)
260
+ @allow_nan = !!opts[:allow_nan] if opts.key?(:allow_nan)
261
+ @as_json = opts[:as_json].to_proc if opts[:as_json]
262
+ @ascii_only = opts[:ascii_only] if opts.key?(:ascii_only)
249
263
  @depth = opts[:depth] || 0
250
264
  @buffer_initial_length ||= opts[:buffer_initial_length]
251
265
 
@@ -287,16 +301,27 @@ module JSON
287
301
  # returns the result. If no valid JSON document can be
288
302
  # created this method raises a
289
303
  # GeneratorError exception.
290
- def generate(obj)
304
+ def generate(obj, anIO = nil)
291
305
  if @indent.empty? and @space.empty? and @space_before.empty? and @object_nl.empty? and @array_nl.empty? and
292
- !@ascii_only and !@script_safe and @max_nesting == 0 and !@strict
306
+ !@ascii_only and !@script_safe and @max_nesting == 0 and (!@strict || Symbol === obj)
293
307
  result = generate_json(obj, ''.dup)
294
308
  else
295
309
  result = obj.to_json(self)
296
310
  end
297
- JSON.valid_utf8?(result) or raise GeneratorError,
298
- "source sequence #{result.inspect} is illegal/malformed utf-8"
299
- result
311
+ JSON::TruffleRuby::Generator.valid_utf8?(result) or raise GeneratorError.new(
312
+ "source sequence #{result.inspect} is illegal/malformed utf-8",
313
+ obj
314
+ )
315
+ if anIO
316
+ anIO.write(result)
317
+ anIO
318
+ else
319
+ result
320
+ end
321
+ end
322
+
323
+ def generate_new(obj, anIO = nil) # :nodoc:
324
+ dup.generate(obj, anIO)
300
325
  end
301
326
 
302
327
  # Handles @allow_nan, @buffer_initial_length, other ivars must be the default value (see above)
@@ -307,7 +332,16 @@ module JSON
307
332
  first = true
308
333
  obj.each_pair do |k,v|
309
334
  buf << ',' unless first
310
- fast_serialize_string(k.to_s, buf)
335
+
336
+ key_str = k.to_s
337
+ if key_str.class == String
338
+ fast_serialize_string(key_str, buf)
339
+ elsif key_str.is_a?(String)
340
+ generate_json(key_str, buf)
341
+ else
342
+ raise TypeError, "#{k.class}#to_s returns an instance of #{key_str.class}, expected a String"
343
+ end
344
+
311
345
  buf << ':'
312
346
  generate_json(v, buf)
313
347
  first = false
@@ -323,9 +357,19 @@ module JSON
323
357
  end
324
358
  buf << ']'
325
359
  when String
326
- fast_serialize_string(obj, buf)
360
+ if obj.class == String
361
+ fast_serialize_string(obj, buf)
362
+ else
363
+ buf << obj.to_json(self)
364
+ end
327
365
  when Integer
328
366
  buf << obj.to_s
367
+ when Symbol
368
+ if @strict
369
+ fast_serialize_string(obj.name, buf)
370
+ else
371
+ buf << obj.to_json(self)
372
+ end
329
373
  else
330
374
  # Note: Float is handled this way since Float#to_s is slow anyway
331
375
  buf << obj.to_json(self)
@@ -333,24 +377,23 @@ module JSON
333
377
  end
334
378
 
335
379
  # Assumes !@ascii_only, !@script_safe
336
- if Regexp.method_defined?(:match?)
337
- private def fast_serialize_string(string, buf) # :nodoc:
338
- buf << '"'
339
- string = string.encode(::Encoding::UTF_8) unless string.encoding == ::Encoding::UTF_8
340
- raise GeneratorError, "source sequence is illegal/malformed utf-8" unless string.valid_encoding?
341
-
342
- if /["\\\x0-\x1f]/n.match?(string)
343
- buf << string.gsub(/["\\\x0-\x1f]/n, MAP)
344
- else
345
- buf << string
380
+ private def fast_serialize_string(string, buf) # :nodoc:
381
+ buf << '"'
382
+ unless string.encoding == ::Encoding::UTF_8
383
+ begin
384
+ string = string.encode(::Encoding::UTF_8)
385
+ rescue Encoding::UndefinedConversionError => error
386
+ raise GeneratorError.new(error.message, string)
346
387
  end
347
- buf << '"'
348
388
  end
349
- else
350
- # Ruby 2.3 compatibility
351
- private def fast_serialize_string(string, buf) # :nodoc:
352
- buf << string.to_json(self)
389
+ raise GeneratorError.new("source sequence is illegal/malformed utf-8", string) unless string.valid_encoding?
390
+
391
+ if /["\\\x0-\x1f]/.match?(string)
392
+ buf << string.gsub(/["\\\x0-\x1f]/, MAP)
393
+ else
394
+ buf << string
353
395
  end
396
+ buf << '"'
354
397
  end
355
398
 
356
399
  # Return the value returned by method +name+.
@@ -378,8 +421,20 @@ module JSON
378
421
  # it to a JSON string, and returns the result. This is a fallback, if no
379
422
  # special method #to_json was defined for some object.
380
423
  def to_json(state = nil, *)
381
- if state && State.from_state(state).strict?
382
- raise GeneratorError, "#{self.class} not allowed in JSON"
424
+ state = State.from_state(state) if state
425
+ if state&.strict?
426
+ value = self
427
+ if state.strict? && !(false == value || true == value || nil == value || String === value || Array === value || Hash === value || Integer === value || Float === value || Fragment === value)
428
+ if state.as_json
429
+ value = state.as_json.call(value)
430
+ unless false == value || true == value || nil == value || String === value || Array === value || Hash === value || Integer === value || Float === value || Fragment === value
431
+ raise GeneratorError.new("#{value.class} returned by #{state.as_json} not allowed in JSON", value)
432
+ end
433
+ value.to_json(state)
434
+ else
435
+ raise GeneratorError.new("#{value.class} not allowed in JSON", value)
436
+ end
437
+ end
383
438
  else
384
439
  to_s.to_json
385
440
  end
@@ -406,17 +461,39 @@ module JSON
406
461
  end
407
462
 
408
463
  def json_transform(state)
464
+ depth = state.depth += 1
465
+
466
+ if empty?
467
+ state.depth -= 1
468
+ return '{}'
469
+ end
470
+
409
471
  delim = ",#{state.object_nl}"
410
472
  result = +"{#{state.object_nl}"
411
- depth = state.depth += 1
412
473
  first = true
413
474
  indent = !state.object_nl.empty?
414
475
  each { |key, value|
415
476
  result << delim unless first
416
477
  result << state.indent * depth if indent
417
- result = +"#{result}#{key.to_s.to_json(state)}#{state.space_before}:#{state.space}"
418
- if state.strict? && !(false == value || true == value || nil == value || String === value || Array === value || Hash === value || Integer === value || Float === value)
419
- raise GeneratorError, "#{value.class} not allowed in JSON"
478
+
479
+ key_str = key.to_s
480
+ if key_str.is_a?(String)
481
+ key_json = key_str.to_json(state)
482
+ else
483
+ raise TypeError, "#{key.class}#to_s returns an instance of #{key_str.class}, expected a String"
484
+ end
485
+
486
+ result = +"#{result}#{key_json}#{state.space_before}:#{state.space}"
487
+ if state.strict? && !(false == value || true == value || nil == value || String === value || Array === value || Hash === value || Integer === value || Float === value || Fragment === value)
488
+ if state.as_json
489
+ value = state.as_json.call(value)
490
+ unless false == value || true == value || nil == value || String === value || Array === value || Hash === value || Integer === value || Float === value || Fragment === value
491
+ raise GeneratorError.new("#{value.class} returned by #{state.as_json} not allowed in JSON", value)
492
+ end
493
+ result << value.to_json(state)
494
+ else
495
+ raise GeneratorError.new("#{value.class} not allowed in JSON", value)
496
+ end
420
497
  elsif value.respond_to?(:to_json)
421
498
  result << value.to_json(state)
422
499
  else
@@ -448,6 +525,13 @@ module JSON
448
525
  private
449
526
 
450
527
  def json_transform(state)
528
+ depth = state.depth += 1
529
+
530
+ if empty?
531
+ state.depth -= 1
532
+ return '[]'
533
+ end
534
+
451
535
  result = '['.dup
452
536
  if state.array_nl.empty?
453
537
  delim = ","
@@ -455,14 +539,22 @@ module JSON
455
539
  result << state.array_nl
456
540
  delim = ",#{state.array_nl}"
457
541
  end
458
- depth = state.depth += 1
542
+
459
543
  first = true
460
544
  indent = !state.array_nl.empty?
461
545
  each { |value|
462
546
  result << delim unless first
463
547
  result << state.indent * depth if indent
464
- if state.strict? && !(false == value || true == value || nil == value || String === value || Array === value || Hash === value || Integer === value || Float === value)
465
- raise GeneratorError, "#{value.class} not allowed in JSON"
548
+ if state.strict? && !(false == value || true == value || nil == value || String === value || Array === value || Hash === value || Integer === value || Float === value || Fragment === value || Symbol == value)
549
+ if state.as_json
550
+ value = state.as_json.call(value)
551
+ unless false == value || true == value || nil == value || String === value || Array === value || Hash === value || Integer === value || Float === value || Fragment === value || Symbol === value
552
+ raise GeneratorError.new("#{value.class} returned by #{state.as_json} not allowed in JSON", value)
553
+ end
554
+ result << value.to_json(state)
555
+ else
556
+ raise GeneratorError.new("#{value.class} not allowed in JSON", value)
557
+ end
466
558
  elsif value.respond_to?(:to_json)
467
559
  result << value.to_json(state)
468
560
  else
@@ -484,20 +576,25 @@ module JSON
484
576
 
485
577
  module Float
486
578
  # Returns a JSON string representation for this Float number.
487
- def to_json(state = nil, *)
579
+ def to_json(state = nil, *args)
488
580
  state = State.from_state(state)
489
- case
490
- when infinite?
581
+ if infinite? || nan?
491
582
  if state.allow_nan?
492
583
  to_s
584
+ elsif state.strict? && state.as_json
585
+ casted_value = state.as_json.call(self)
586
+
587
+ if casted_value.equal?(self)
588
+ raise GeneratorError.new("#{self} not allowed in JSON", self)
589
+ end
590
+
591
+ state.check_max_nesting
592
+ state.depth += 1
593
+ result = casted_value.to_json(state, *args)
594
+ state.depth -= 1
595
+ result
493
596
  else
494
- raise GeneratorError, "#{self} not allowed in JSON"
495
- end
496
- when nan?
497
- if state.allow_nan?
498
- to_s
499
- else
500
- raise GeneratorError, "#{self} not allowed in JSON"
597
+ raise GeneratorError.new("#{self} not allowed in JSON", self)
501
598
  end
502
599
  else
503
600
  to_s
@@ -505,6 +602,17 @@ module JSON
505
602
  end
506
603
  end
507
604
 
605
+ module Symbol
606
+ def to_json(state = nil, *args)
607
+ state = State.from_state(state)
608
+ if state.strict?
609
+ name.to_json(state, *args)
610
+ else
611
+ super
612
+ end
613
+ end
614
+ end
615
+
508
616
  module String
509
617
  # This string should be encoded with UTF-8 A call to this method
510
618
  # returns a JSON string encoded with UTF16 big endian characters as
@@ -513,17 +621,19 @@ module JSON
513
621
  state = State.from_state(state)
514
622
  if encoding == ::Encoding::UTF_8
515
623
  unless valid_encoding?
516
- raise GeneratorError, "source sequence is illegal/malformed utf-8"
624
+ raise GeneratorError.new("source sequence is illegal/malformed utf-8", self)
517
625
  end
518
626
  string = self
519
627
  else
520
628
  string = encode(::Encoding::UTF_8)
521
629
  end
522
630
  if state.ascii_only?
523
- %("#{JSON.utf8_to_json_ascii(string, state.script_safe)}")
631
+ %("#{JSON::TruffleRuby::Generator.utf8_to_json_ascii(string, state.script_safe)}")
524
632
  else
525
- %("#{JSON.utf8_to_json(string, state.script_safe)}")
633
+ %("#{JSON::TruffleRuby::Generator.utf8_to_json(string, state.script_safe)}")
526
634
  end
635
+ rescue Encoding::UndefinedConversionError => error
636
+ raise ::JSON::GeneratorError.new(error.message, self)
527
637
  end
528
638
 
529
639
  # Module that holds the extending methods if, the String module is
data/lib/json/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module JSON
4
- VERSION = '2.7.4'
4
+ VERSION = '2.10.1'
5
5
  end