json 2.18.1 → 3.0.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.
@@ -9,7 +9,7 @@ module JSON
9
9
  # Instantiates a new State object, configured by _opts_.
10
10
  #
11
11
  # Argument +opts+, if given, contains a \Hash of options for the generation.
12
- # See {Generating Options}[#module-JSON-label-Generating+Options].
12
+ # See {Generating Options}[rdoc-ref:JSON@Generating+Options].
13
13
  def initialize(opts = nil)
14
14
  if opts && !opts.empty?
15
15
  configure(opts)
@@ -54,6 +54,7 @@ module JSON
54
54
  strict: strict?,
55
55
  depth: depth,
56
56
  buffer_initial_length: buffer_initial_length,
57
+ sort_keys: sort_keys
57
58
  }
58
59
 
59
60
  allow_duplicate_key = allow_duplicate_key?
@@ -70,33 +71,6 @@ module JSON
70
71
  end
71
72
 
72
73
  alias_method :to_hash, :to_h
73
-
74
- # call-seq: [](name)
75
- #
76
- # Returns the value returned by method +name+.
77
- def [](name)
78
- ::JSON.deprecation_warning("JSON::State#[] is deprecated and will be removed in json 3.0.0")
79
-
80
- if respond_to?(name)
81
- __send__(name)
82
- else
83
- instance_variable_get("@#{name}") if
84
- instance_variables.include?("@#{name}".to_sym) # avoid warning
85
- end
86
- end
87
-
88
- # call-seq: []=(name, value)
89
- #
90
- # Sets the attribute name to value.
91
- def []=(name, value)
92
- ::JSON.deprecation_warning("JSON::State#[]= is deprecated and will be removed in json 3.0.0")
93
-
94
- if respond_to?(name_writer = "#{name}=")
95
- __send__ name_writer, value
96
- else
97
- instance_variable_set "@#{name}", value
98
- end
99
- end
100
74
  end
101
75
  end
102
76
  end
data/lib/json/ext.rb CHANGED
@@ -41,5 +41,29 @@ module JSON
41
41
  end
42
42
  end
43
43
 
44
- JSON_LOADED = true unless defined?(JSON::JSON_LOADED)
44
+ if defined?(ResumableParser) # Not yet available on JRuby
45
+ class ResumableParser
46
+ # Returns whether the parser is entirely done: no unconsumed bytes in
47
+ # the buffer, no document under construction and no parsed value
48
+ # awaiting retrieval.
49
+ #
50
+ # The main use case is detecting a truncated stream once the input is
51
+ # exhausted:
52
+ #
53
+ # loop do
54
+ # begin
55
+ # parser << socket.readpartial(4096)
56
+ # rescue EOFError
57
+ # break
58
+ # end
59
+ # while parser.parse
60
+ # process(parser.value)
61
+ # end
62
+ # end
63
+ # warn "stream was truncated" unless parser.empty?
64
+ def empty?
65
+ eos? && !partial_value? && !value?
66
+ end
67
+ end
68
+ end
45
69
  end
@@ -48,7 +48,7 @@ module JSON
48
48
  SCRIPT_SAFE_ESCAPE_PATTERN = /[\/"\\\x0-\x1f\u2028-\u2029]/
49
49
 
50
50
  def self.native_type?(value) # :nodoc:
51
- (false == value || true == value || nil == value || String === value || Array === value || Hash === value || Integer === value || Float === value || Fragment === value)
51
+ (false == value || true == value || nil == value || String === value || Symbol === value || Array === value || Hash === value || Integer === value || Float === value || Fragment === value)
52
52
  end
53
53
 
54
54
  def self.native_key?(key) # :nodoc:
@@ -111,6 +111,8 @@ module JSON
111
111
  # This class is used to create State instances, that are use to hold data
112
112
  # while generating a JSON text from a Ruby data structure.
113
113
  class State
114
+ singleton_class.attr_accessor :default_sort_keys_proc # :nodoc:
115
+
114
116
  def self.generate(obj, opts = nil, io = nil)
115
117
  new(opts).generate(obj, io)
116
118
  end
@@ -164,7 +166,9 @@ module JSON
164
166
  @script_safe = false
165
167
  @strict = false
166
168
  @max_nesting = 100
167
- configure(opts) if opts
169
+ @sort_keys = false
170
+ @allow_duplicate_key = false
171
+ _configure(**opts) if opts
168
172
  end
169
173
 
170
174
  # This string is used to indent levels in the JSON text.
@@ -199,6 +203,33 @@ module JSON
199
203
  # supported by the JSON spec will raise a JSON::GeneratorError
200
204
  attr_accessor :strict
201
205
 
206
+ # Controls key sorting in the generated JSON. If set to +true+, object
207
+ # keys are sorted by key lexicographically. If set to a Proc, it
208
+ # receives the entire Hash and must return a Hash with its pairs in the
209
+ # desired order.
210
+ attr_reader :sort_keys
211
+
212
+ def sort_keys=(value) # :nodoc:
213
+ type_error = false
214
+ @sort_keys = case value
215
+ when Proc
216
+ value
217
+ when true
218
+ State.default_sort_keys_proc
219
+ when nil, false
220
+ false
221
+ else
222
+ type_error = true
223
+ false
224
+ end
225
+
226
+ if type_error
227
+ raise TypeError, "The `sort_keys` argument must be a boolean or a Proc"
228
+ end
229
+
230
+ @sort_keys
231
+ end
232
+
202
233
  # :stopdoc:
203
234
  attr_reader :buffer_initial_length
204
235
 
@@ -211,7 +242,14 @@ module JSON
211
242
 
212
243
  # This integer returns the current depth data structure nesting in the
213
244
  # generated JSON.
214
- attr_accessor :depth
245
+ attr_reader :depth
246
+
247
+ def depth=(depth)
248
+ if depth.negative?
249
+ raise ArgumentError, "depth must be >= 0 (got #{depth})"
250
+ end
251
+ @depth = depth
252
+ end
215
253
 
216
254
  def check_max_nesting # :nodoc:
217
255
  return if @max_nesting.zero?
@@ -252,56 +290,48 @@ module JSON
252
290
 
253
291
  # Configure this State instance with the Hash _opts_, and return
254
292
  # itself.
255
- def configure(opts)
256
- if opts.respond_to?(:to_hash)
257
- opts = opts.to_hash
258
- elsif opts.respond_to?(:to_h)
259
- opts = opts.to_h
260
- else
261
- raise TypeError, "can't convert #{opts.class} into Hash"
262
- end
263
- opts.each do |key, value|
264
- instance_variable_set "@#{key}", value
293
+ def configure(options)
294
+ unless Hash == options
295
+ if options.respond_to?(:to_hash)
296
+ options = options.to_hash
297
+ elsif options.respond_to?(:to_h)
298
+ options = options.to_h
299
+ end
265
300
  end
301
+ _configure(**options)
302
+ end
303
+ alias merge configure
266
304
 
267
- # NOTE: If adding new instance variables here, check whether #generate should check them for #generate_json
268
- @indent = opts[:indent] || '' if opts.key?(:indent)
269
- @space = opts[:space] || '' if opts.key?(:space)
270
- @space_before = opts[:space_before] || '' if opts.key?(:space_before)
271
- @object_nl = opts[:object_nl] || '' if opts.key?(:object_nl)
272
- @array_nl = opts[:array_nl] || '' if opts.key?(:array_nl)
273
- @allow_nan = !!opts[:allow_nan] if opts.key?(:allow_nan)
274
- @as_json = opts[:as_json].to_proc if opts[:as_json]
275
- @ascii_only = opts[:ascii_only] if opts.key?(:ascii_only)
276
- @depth = opts[:depth] || 0
277
- @buffer_initial_length ||= opts[:buffer_initial_length]
278
-
279
- @script_safe = if opts.key?(:script_safe)
280
- !!opts[:script_safe]
281
- elsif opts.key?(:escape_slash)
282
- !!opts[:escape_slash]
283
- else
284
- false
305
+ private def _configure(
306
+ indent: '', space: '', space_before: '', object_nl: '', array_nl: '', allow_nan: false,
307
+ as_json: false, ascii_only: false, sort_keys: false, depth: 0, buffer_initial_length: 1024,
308
+ allow_duplicate_key: false, script_safe: false, strict: false, max_nesting: 100
309
+ )
310
+ if depth.negative?
311
+ raise ArgumentError, "depth must be >= 0 (got #{depth})"
285
312
  end
286
313
 
287
- if opts.key?(:allow_duplicate_key)
288
- @allow_duplicate_key = !!opts[:allow_duplicate_key]
289
- else
290
- @allow_duplicate_key = nil # nil is deprecation
314
+ if max_nesting && !(Integer === max_nesting)
315
+ raise TypeError, ":max_nesting must be `false` or an Integer, got: #{max_nesting.class}"
291
316
  end
292
317
 
293
- @strict = !!opts[:strict] if opts.key?(:strict)
294
-
295
- if !opts.key?(:max_nesting) # defaults to 100
296
- @max_nesting = 100
297
- elsif opts[:max_nesting]
298
- @max_nesting = opts[:max_nesting]
299
- else
300
- @max_nesting = 0
301
- end
318
+ @indent = indent || ''
319
+ @space = space || ''
320
+ @space_before = space_before || ''
321
+ @object_nl = object_nl || ''
322
+ @array_nl = array_nl || ''
323
+ @allow_nan = allow_nan || false
324
+ @as_json = as_json || false
325
+ @ascii_only = ascii_only || false
326
+ self.sort_keys = sort_keys
327
+ @depth = depth
328
+ @buffer_initial_length = buffer_initial_length
329
+ @allow_duplicate_key = allow_duplicate_key
330
+ @script_safe = script_safe
331
+ @strict = strict
332
+ @max_nesting = max_nesting || 0
302
333
  self
303
334
  end
304
- alias merge configure
305
335
 
306
336
  def allow_duplicate_key? # :nodoc:
307
337
  @allow_duplicate_key
@@ -316,10 +346,6 @@ module JSON
316
346
  result[key.to_sym] = instance_variable_get(iv)
317
347
  end
318
348
 
319
- if result[:allow_duplicate_key].nil?
320
- result.delete(:allow_duplicate_key)
321
- end
322
-
323
349
  result
324
350
  end
325
351
 
@@ -334,9 +360,13 @@ module JSON
334
360
 
335
361
  depth = @depth
336
362
  if @indent.empty? and @space.empty? and @space_before.empty? and @object_nl.empty? and @array_nl.empty? and
337
- !@ascii_only and !@script_safe and @max_nesting == 0 and (!@strict || Symbol === obj)
363
+ !@ascii_only and !@script_safe and @max_nesting == 0 and (!@strict || Symbol === obj) and !@sort_keys
338
364
  result = generate_json(obj, ''.dup)
339
365
  else
366
+ if @sort_keys
367
+ obj = @sort_keys.call(obj)
368
+ end
369
+
340
370
  result = obj.to_json(self)
341
371
  end
342
372
  JSON::TruffleRuby::Generator.valid_utf8?(result) or raise GeneratorError.new(
@@ -366,7 +396,7 @@ module JSON
366
396
  else
367
397
  if key_type && !@allow_duplicate_key && key_type != k.class
368
398
  key_type = nil # stop checking
369
- JSON.send(:on_mixed_keys_hash, obj, !@allow_duplicate_key.nil?)
399
+ JSON.send(:on_mixed_keys_hash, obj)
370
400
  end
371
401
  buf << ','
372
402
  end
@@ -433,28 +463,6 @@ module JSON
433
463
  end
434
464
  buf << '"'
435
465
  end
436
-
437
- # Return the value returned by method +name+.
438
- def [](name)
439
- ::JSON.deprecation_warning("JSON::State#[] is deprecated and will be removed in json 3.0.0")
440
-
441
- if respond_to?(name)
442
- __send__(name)
443
- else
444
- instance_variable_get("@#{name}") if
445
- instance_variables.include?("@#{name}".to_sym) # avoid warning
446
- end
447
- end
448
-
449
- def []=(name, value)
450
- ::JSON.deprecation_warning("JSON::State#[]= is deprecated and will be removed in json 3.0.0")
451
-
452
- if respond_to?(name_writer = "#{name}=")
453
- __send__ name_writer, value
454
- else
455
- instance_variable_set "@#{name}", value
456
- end
457
- end
458
466
  end
459
467
 
460
468
  module GeneratorMethods
@@ -505,11 +513,11 @@ module JSON
505
513
 
506
514
  if empty?
507
515
  state.depth -= 1
508
- return '{}'
516
+ return +'{}'
509
517
  end
510
518
 
511
519
  delim = ",#{state.object_nl}"
512
- result = +"{#{state.object_nl}"
520
+ result = "{#{state.object_nl}"
513
521
  first = true
514
522
  key_type = nil
515
523
  indent = !state.object_nl.empty?
@@ -519,7 +527,7 @@ module JSON
519
527
  else
520
528
  if key_type && !state.allow_duplicate_key? && key_type != key.class
521
529
  key_type = nil # stop checking
522
- JSON.send(:on_mixed_keys_hash, self, state.allow_duplicate_key? == false)
530
+ JSON.send(:on_mixed_keys_hash, self)
523
531
  end
524
532
  result << delim
525
533
  end
@@ -546,7 +554,7 @@ module JSON
546
554
  raise TypeError, "#{key.class}#to_s returns an instance of #{key_str.class}, expected a String"
547
555
  end
548
556
 
549
- result = +"#{result}#{key_json}#{state.space_before}:#{state.space}"
557
+ result = "#{result}#{key_json}#{state.space_before}:#{state.space}"
550
558
  if state.strict? && !Generator.native_type?(value)
551
559
  if state.as_json
552
560
  value = state.as_json.call(value, false)
@@ -597,7 +605,7 @@ module JSON
597
605
 
598
606
  if empty?
599
607
  state.depth -= 1
600
- return '[]'
608
+ return +'[]'
601
609
  end
602
610
 
603
611
  result = '['.dup
@@ -722,17 +730,17 @@ module JSON
722
730
 
723
731
  module TrueClass
724
732
  # Returns a JSON string for true: 'true'.
725
- def to_json(*) 'true' end
733
+ def to_json(*) +'true' end
726
734
  end
727
735
 
728
736
  module FalseClass
729
737
  # Returns a JSON string for false: 'false'.
730
- def to_json(*) 'false' end
738
+ def to_json(*) +'false' end
731
739
  end
732
740
 
733
741
  module NilClass
734
742
  # Returns a JSON string for nil: 'null'.
735
- def to_json(*) 'null' end
743
+ def to_json(*) +'null' end
736
744
  end
737
745
  end
738
746
  end
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.18.1'
4
+ VERSION = '3.0.0'
5
5
  end