json 2.7.2 → 2.7.5

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/json.gemspec CHANGED
@@ -2,67 +2,60 @@ version = File.foreach(File.join(__dir__, "lib/json/version.rb")) do |line|
2
2
  /^\s*VERSION\s*=\s*'(.*)'/ =~ line and break $1
3
3
  end rescue nil
4
4
 
5
- Gem::Specification.new do |s|
5
+ spec = Gem::Specification.new do |s|
6
+ java_ext = Gem::Platform === s.platform && s.platform =~ 'java' || RUBY_ENGINE == 'jruby'
7
+
6
8
  s.name = "json"
7
9
  s.version = version
8
10
 
9
11
  s.summary = "JSON Implementation for Ruby"
10
- s.description = "This is a JSON implementation as a Ruby extension in C."
12
+ s.homepage = "https://ruby.github.io/json"
13
+ s.metadata = {
14
+ 'bug_tracker_uri' => 'https://github.com/ruby/json/issues',
15
+ 'changelog_uri' => 'https://github.com/ruby/json/blob/master/CHANGES.md',
16
+ 'documentation_uri' => 'https://ruby.github.io/json/doc/index.html',
17
+ 'homepage_uri' => s.homepage,
18
+ 'source_code_uri' => 'https://github.com/ruby/json',
19
+ 'wiki_uri' => 'https://github.com/ruby/json/wiki'
20
+ }
21
+
22
+ s.required_ruby_version = Gem::Requirement.new(">= 2.3")
23
+
24
+ if java_ext
25
+ s.description = "A JSON implementation as a JRuby extension."
26
+ s.author = "Daniel Luz"
27
+ s.email = "dev+ruby@mernen.com"
28
+ else
29
+ s.description = "This is a JSON implementation as a Ruby extension in C."
30
+ s.authors = ["Florian Frank"]
31
+ s.email = "flori@ping.de"
32
+ end
33
+
11
34
  s.licenses = ["Ruby"]
12
- s.authors = ["Florian Frank"]
13
- s.email = "flori@ping.de"
14
35
 
15
- s.extensions = ["ext/json/ext/generator/extconf.rb", "ext/json/ext/parser/extconf.rb", "ext/json/extconf.rb"]
16
36
  s.extra_rdoc_files = ["README.md"]
17
37
  s.rdoc_options = ["--title", "JSON implementation for Ruby", "--main", "README.md"]
38
+
18
39
  s.files = [
19
40
  "CHANGES.md",
20
- "LICENSE",
41
+ "COPYING",
42
+ "BSDL",
43
+ "LEGAL",
21
44
  "README.md",
22
- "ext/json/ext/fbuffer/fbuffer.h",
23
- "ext/json/ext/generator/depend",
24
- "ext/json/ext/generator/extconf.rb",
25
- "ext/json/ext/generator/generator.c",
26
- "ext/json/ext/generator/generator.h",
27
- "ext/json/ext/parser/depend",
28
- "ext/json/ext/parser/extconf.rb",
29
- "ext/json/ext/parser/parser.c",
30
- "ext/json/ext/parser/parser.h",
31
- "ext/json/ext/parser/parser.rl",
32
- "ext/json/extconf.rb",
33
45
  "json.gemspec",
34
- "lib/json.rb",
35
- "lib/json/add/bigdecimal.rb",
36
- "lib/json/add/complex.rb",
37
- "lib/json/add/core.rb",
38
- "lib/json/add/date.rb",
39
- "lib/json/add/date_time.rb",
40
- "lib/json/add/exception.rb",
41
- "lib/json/add/ostruct.rb",
42
- "lib/json/add/range.rb",
43
- "lib/json/add/rational.rb",
44
- "lib/json/add/regexp.rb",
45
- "lib/json/add/set.rb",
46
- "lib/json/add/struct.rb",
47
- "lib/json/add/symbol.rb",
48
- "lib/json/add/time.rb",
49
- "lib/json/common.rb",
50
- "lib/json/ext.rb",
51
- "lib/json/generic_object.rb",
52
- "lib/json/pure.rb",
53
- "lib/json/pure/generator.rb",
54
- "lib/json/pure/parser.rb",
55
- "lib/json/version.rb",
46
+ *Dir["lib/**/*.rb"],
56
47
  ]
57
- s.homepage = "https://flori.github.io/json"
58
- s.metadata = {
59
- 'bug_tracker_uri' => 'https://github.com/flori/json/issues',
60
- 'changelog_uri' => 'https://github.com/flori/json/blob/master/CHANGES.md',
61
- 'documentation_uri' => 'https://flori.github.io/json/doc/index.html',
62
- 'homepage_uri' => s.homepage,
63
- 'source_code_uri' => 'https://github.com/flori/json',
64
- 'wiki_uri' => 'https://github.com/flori/json/wiki'
65
- }
66
48
 
67
- s.required_ruby_version = Gem::Requirement.new(">= 2.3")
49
+ if java_ext
50
+ s.platform = 'java'
51
+ else
52
+ s.extensions = Dir["ext/json/**/extconf.rb"]
53
+ s.files += Dir["ext/json/**/*.{c,h,rl}"]
54
+ end
55
+ end
56
+
57
+ if RUBY_ENGINE == 'jruby' && $0 == __FILE__
58
+ Gem::Builder.new(spec).build
59
+ else
60
+ spec
68
61
  end
@@ -1,4 +1,4 @@
1
- #frozen_string_literal: false
1
+ # frozen_string_literal: true
2
2
  unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED
3
3
  require 'json'
4
4
  end
@@ -1,4 +1,4 @@
1
- #frozen_string_literal: false
1
+ # frozen_string_literal: true
2
2
  unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED
3
3
  require 'json'
4
4
  end
data/lib/json/add/core.rb CHANGED
@@ -1,4 +1,4 @@
1
- #frozen_string_literal: false
1
+ # frozen_string_literal: true
2
2
  # This file requires the implementations of ruby core's custom objects for
3
3
  # serialisation/deserialisation.
4
4
 
data/lib/json/add/date.rb CHANGED
@@ -1,4 +1,4 @@
1
- #frozen_string_literal: false
1
+ # frozen_string_literal: true
2
2
  unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED
3
3
  require 'json'
4
4
  end
@@ -1,4 +1,4 @@
1
- #frozen_string_literal: false
1
+ # frozen_string_literal: true
2
2
  unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED
3
3
  require 'json'
4
4
  end
@@ -1,4 +1,4 @@
1
- #frozen_string_literal: false
1
+ # frozen_string_literal: true
2
2
  unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED
3
3
  require 'json'
4
4
  end
@@ -1,4 +1,4 @@
1
- #frozen_string_literal: false
1
+ # frozen_string_literal: true
2
2
  unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED
3
3
  require 'json'
4
4
  end
@@ -1,4 +1,4 @@
1
- #frozen_string_literal: false
1
+ # frozen_string_literal: true
2
2
  unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED
3
3
  require 'json'
4
4
  end
@@ -1,4 +1,4 @@
1
- #frozen_string_literal: false
1
+ # frozen_string_literal: true
2
2
  unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED
3
3
  require 'json'
4
4
  end
@@ -1,4 +1,4 @@
1
- #frozen_string_literal: false
1
+ # frozen_string_literal: true
2
2
  unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED
3
3
  require 'json'
4
4
  end
@@ -1,4 +1,4 @@
1
- #frozen_string_literal: false
1
+ # frozen_string_literal: true
2
2
  unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED
3
3
  require 'json'
4
4
  end
@@ -1,5 +1,4 @@
1
-
2
- #frozen_string_literal: false
1
+ # frozen_string_literal: true
3
2
  unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED
4
3
  require 'json'
5
4
  end
data/lib/json/add/time.rb CHANGED
@@ -1,4 +1,4 @@
1
- #frozen_string_literal: false
1
+ # frozen_string_literal: true
2
2
  unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED
3
3
  require 'json'
4
4
  end
@@ -10,11 +10,7 @@ class Time
10
10
  if usec = object.delete('u') # used to be tv_usec -> tv_nsec
11
11
  object['n'] = usec * 1000
12
12
  end
13
- if method_defined?(:tv_nsec)
14
- at(object['s'], Rational(object['n'], 1000))
15
- else
16
- at(object['s'], object['n'] / 1000)
17
- end
13
+ at(object['s'], Rational(object['n'], 1000))
18
14
  end
19
15
 
20
16
  # Methods <tt>Time#as_json</tt> and +Time.json_create+ may be used
@@ -34,13 +30,10 @@ class Time
34
30
  # # => 2023-11-25 11:00:56.472846644 -0600
35
31
  #
36
32
  def as_json(*)
37
- nanoseconds = [ tv_usec * 1000 ]
38
- respond_to?(:tv_nsec) and nanoseconds << tv_nsec
39
- nanoseconds = nanoseconds.max
40
33
  {
41
34
  JSON.create_id => self.class.name,
42
35
  's' => tv_sec,
43
- 'n' => nanoseconds,
36
+ 'n' => tv_nsec,
44
37
  }
45
38
  end
46
39
 
data/lib/json/common.rb CHANGED
@@ -1,4 +1,4 @@
1
- #frozen_string_literal: false
1
+ #frozen_string_literal: true
2
2
  require 'json/version'
3
3
 
4
4
  module JSON
@@ -20,11 +20,16 @@ module JSON
20
20
  # ruby = [0, 1, nil]
21
21
  # JSON[ruby] # => '[0,1,null]'
22
22
  def [](object, opts = {})
23
- if object.respond_to? :to_str
24
- JSON.parse(object.to_str, opts)
25
- else
26
- JSON.generate(object, opts)
23
+ if object.is_a?(String)
24
+ return JSON.parse(object, opts)
25
+ elsif object.respond_to?(:to_str)
26
+ str = object.to_str
27
+ if str.is_a?(String)
28
+ return JSON.parse(object.to_str, opts)
29
+ end
27
30
  end
31
+
32
+ JSON.generate(object, opts)
28
33
  end
29
34
 
30
35
  # Returns the JSON parser class that is used by JSON. This is either
@@ -112,23 +117,17 @@ module JSON
112
117
  attr_accessor :state
113
118
  end
114
119
 
115
- DEFAULT_CREATE_ID = 'json_class'.freeze
116
- private_constant :DEFAULT_CREATE_ID
117
-
118
- CREATE_ID_TLS_KEY = "JSON.create_id".freeze
119
- private_constant :CREATE_ID_TLS_KEY
120
-
121
120
  # Sets create identifier, which is used to decide if the _json_create_
122
121
  # hook of a class should be called; initial value is +json_class+:
123
122
  # JSON.create_id # => 'json_class'
124
123
  def self.create_id=(new_value)
125
- Thread.current[CREATE_ID_TLS_KEY] = new_value.dup.freeze
124
+ Thread.current[:"JSON.create_id"] = new_value.dup.freeze
126
125
  end
127
126
 
128
127
  # Returns the current create identifier.
129
128
  # See also JSON.create_id=.
130
129
  def self.create_id
131
- Thread.current[CREATE_ID_TLS_KEY] || DEFAULT_CREATE_ID
130
+ Thread.current[:"JSON.create_id"] || 'json_class'
132
131
  end
133
132
 
134
133
  NaN = 0.0/0
@@ -216,8 +215,17 @@ module JSON
216
215
  # # Raises JSON::ParserError (783: unexpected token at ''):
217
216
  # JSON.parse('')
218
217
  #
219
- def parse(source, opts = {})
220
- Parser.new(source, **(opts||{})).parse
218
+ def parse(source, opts = nil)
219
+ if opts.nil?
220
+ Parser.new(source).parse
221
+ else
222
+ # NB: The ** shouldn't be required, but we have to deal with
223
+ # different versions of the `json` and `json_pure` gems being
224
+ # loaded concurrently.
225
+ # Prior to 2.7.3, `JSON::Ext::Parser` would only take kwargs.
226
+ # Ref: https://github.com/ruby/json/issues/650
227
+ Parser.new(source, **opts).parse
228
+ end
221
229
  end
222
230
 
223
231
  # :call-seq:
@@ -406,7 +414,7 @@ module JSON
406
414
  self.load_default_options = {
407
415
  :max_nesting => false,
408
416
  :allow_nan => true,
409
- :allow_blank => true,
417
+ :allow_blank => true,
410
418
  :create_additions => true,
411
419
  }
412
420
 
@@ -538,15 +546,23 @@ module JSON
538
546
  # #<Admin:0x00000000064c41f8
539
547
  # @attributes={"type"=>"Admin", "password"=>"0wn3d"}>}
540
548
  #
541
- def load(source, proc = nil, options = {})
542
- opts = load_default_options.merge options
543
- if source.respond_to? :to_str
544
- source = source.to_str
545
- elsif source.respond_to? :to_io
546
- source = source.to_io.read
547
- elsif source.respond_to?(:read)
548
- source = source.read
549
+ def load(source, proc = nil, options = nil)
550
+ opts = if options.nil?
551
+ load_default_options
552
+ else
553
+ load_default_options.merge(options)
554
+ end
555
+
556
+ unless source.is_a?(String)
557
+ if source.respond_to? :to_str
558
+ source = source.to_str
559
+ elsif source.respond_to? :to_io
560
+ source = source.to_io.read
561
+ elsif source.respond_to?(:read)
562
+ source = source.read
563
+ end
549
564
  end
565
+
550
566
  if opts[:allow_blank] && (source.nil? || source.empty?)
551
567
  source = 'null'
552
568
  end
@@ -576,13 +592,12 @@ module JSON
576
592
  # Sets or returns the default options for the JSON.dump method.
577
593
  # Initially:
578
594
  # opts = JSON.dump_default_options
579
- # opts # => {:max_nesting=>false, :allow_nan=>true, :script_safe=>false}
595
+ # opts # => {:max_nesting=>false, :allow_nan=>true}
580
596
  attr_accessor :dump_default_options
581
597
  end
582
598
  self.dump_default_options = {
583
599
  :max_nesting => false,
584
600
  :allow_nan => true,
585
- :script_safe => false,
586
601
  }
587
602
 
588
603
  # :call-seq:
@@ -613,26 +628,42 @@ module JSON
613
628
  # Output:
614
629
  # {"foo":[0,1],"bar":{"baz":2,"bat":3},"bam":"bad"}
615
630
  def dump(obj, anIO = nil, limit = nil, kwargs = nil)
616
- io_limit_opt = [anIO, limit, kwargs].compact
617
- kwargs = io_limit_opt.pop if io_limit_opt.last.is_a?(Hash)
618
- anIO, limit = io_limit_opt
619
- if anIO.respond_to?(:to_io)
620
- anIO = anIO.to_io
621
- elsif limit.nil? && !anIO.respond_to?(:write)
622
- anIO, limit = nil, anIO
631
+ if kwargs.nil?
632
+ if limit.nil?
633
+ if anIO.is_a?(Hash)
634
+ kwargs = anIO
635
+ anIO = nil
636
+ end
637
+ elsif limit.is_a?(Hash)
638
+ kwargs = limit
639
+ limit = nil
640
+ end
623
641
  end
642
+
643
+ unless anIO.nil?
644
+ if anIO.respond_to?(:to_io)
645
+ anIO = anIO.to_io
646
+ elsif limit.nil? && !anIO.respond_to?(:write)
647
+ anIO, limit = nil, anIO
648
+ end
649
+ end
650
+
624
651
  opts = JSON.dump_default_options
625
652
  opts = opts.merge(:max_nesting => limit) if limit
626
653
  opts = merge_dump_options(opts, **kwargs) if kwargs
627
- result = generate(obj, opts)
628
- if anIO
654
+
655
+ result = begin
656
+ generate(obj, opts)
657
+ rescue JSON::NestingError
658
+ raise ArgumentError, "exceed depth limit"
659
+ end
660
+
661
+ if anIO.nil?
662
+ result
663
+ else
629
664
  anIO.write result
630
665
  anIO
631
- else
632
- result
633
666
  end
634
- rescue JSON::NestingError
635
- raise ArgumentError, "exceed depth limit"
636
667
  end
637
668
 
638
669
  # Encodes string using String.encode.
@@ -678,11 +709,16 @@ module ::Kernel
678
709
  # The _opts_ argument is passed through to generate/parse respectively. See
679
710
  # generate and parse for their documentation.
680
711
  def JSON(object, *args)
681
- if object.respond_to? :to_str
682
- JSON.parse(object.to_str, args.first)
683
- else
684
- JSON.generate(object, args.first)
712
+ if object.is_a?(String)
713
+ return JSON.parse(object, args.first)
714
+ elsif object.respond_to?(:to_str)
715
+ str = object.to_str
716
+ if str.is_a?(String)
717
+ return JSON.parse(object.to_str, args.first)
718
+ end
685
719
  end
720
+
721
+ JSON.generate(object, args.first)
686
722
  end
687
723
  end
688
724
 
@@ -0,0 +1,135 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JSON
4
+ module Ext
5
+ module Generator
6
+ class State
7
+ # call-seq: new(opts = {})
8
+ #
9
+ # Instantiates a new State object, configured by _opts_.
10
+ #
11
+ # _opts_ can have the following keys:
12
+ #
13
+ # * *indent*: a string used to indent levels (default: ''),
14
+ # * *space*: a string that is put after, a : or , delimiter (default: ''),
15
+ # * *space_before*: a string that is put before a : pair delimiter (default: ''),
16
+ # * *object_nl*: a string that is put at the end of a JSON object (default: ''),
17
+ # * *array_nl*: a string that is put at the end of a JSON array (default: ''),
18
+ # * *allow_nan*: true if NaN, Infinity, and -Infinity should be
19
+ # generated, otherwise an exception is thrown, if these values are
20
+ # encountered. This options defaults to false.
21
+ # * *ascii_only*: true if only ASCII characters should be generated. This
22
+ # option defaults to false.
23
+ # * *buffer_initial_length*: sets the initial length of the generator's
24
+ # internal buffer.
25
+ def initialize(opts = nil)
26
+ if opts && !opts.empty?
27
+ configure(opts)
28
+ end
29
+ end
30
+
31
+ # call-seq: configure(opts)
32
+ #
33
+ # Configure this State instance with the Hash _opts_, and return
34
+ # itself.
35
+ def configure(opts)
36
+ unless opts.is_a?(Hash)
37
+ if opts.respond_to?(:to_hash)
38
+ opts = opts.to_hash
39
+ elsif opts.respond_to?(:to_h)
40
+ opts = opts.to_h
41
+ else
42
+ raise TypeError, "can't convert #{opts.class} into Hash"
43
+ end
44
+ end
45
+
46
+ opts.each do |key, value|
47
+ case key
48
+ when :indent
49
+ self.indent = value || ''
50
+ when :space
51
+ self.space = value || ''
52
+ when :space_before
53
+ self.space_before = value || ''
54
+ when :array_nl
55
+ self.array_nl = value || ''
56
+ when :object_nl
57
+ self.object_nl = value || ''
58
+ when :max_nesting
59
+ self.max_nesting = value || 0
60
+ when :depth
61
+ self.depth = value
62
+ when :buffer_initial_length
63
+ self.buffer_initial_length = value
64
+ when :allow_nan
65
+ self.allow_nan = value
66
+ when :ascii_only
67
+ self.ascii_only = value
68
+ when :script_safe, :escape_slash
69
+ self.script_safe = value
70
+ when :strict
71
+ self.strict = value
72
+ end
73
+ end
74
+
75
+ self
76
+ end
77
+
78
+ alias_method :merge, :configure
79
+
80
+ # call-seq: to_h
81
+ #
82
+ # Returns the configuration instance variables as a hash, that can be
83
+ # passed to the configure method.
84
+ def to_h
85
+ result = {
86
+ indent: indent,
87
+ space: space,
88
+ space_before: space_before,
89
+ object_nl: object_nl,
90
+ array_nl: array_nl,
91
+ allow_nan: allow_nan?,
92
+ ascii_only: ascii_only?,
93
+ max_nesting: max_nesting,
94
+ script_safe: script_safe?,
95
+ strict: strict?,
96
+ depth: depth,
97
+ buffer_initial_length: buffer_initial_length,
98
+ }
99
+
100
+ instance_variables.each do |iv|
101
+ iv = iv.to_s[1..-1]
102
+ result[iv.to_sym] = self[iv]
103
+ end
104
+
105
+ result
106
+ end
107
+
108
+ alias_method :to_hash, :to_h
109
+
110
+ # call-seq: [](name)
111
+ #
112
+ # Returns the value returned by method +name+.
113
+ def [](name)
114
+ if respond_to?(name)
115
+ __send__(name)
116
+ else
117
+ instance_variable_get("@#{name}") if
118
+ instance_variables.include?("@#{name}".to_sym) # avoid warning
119
+ end
120
+ end
121
+
122
+ # call-seq: []=(name, value)
123
+ #
124
+ # Sets the attribute name to value.
125
+ def []=(name, value)
126
+ if respond_to?(name_writer = "#{name}=")
127
+ __send__ name_writer, value
128
+ else
129
+ instance_variable_set "@#{name}", value
130
+ end
131
+ end
132
+ end
133
+ end
134
+ end
135
+ end
data/lib/json/ext.rb CHANGED
@@ -1,14 +1,24 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'json/common'
2
4
 
3
5
  module JSON
4
6
  # This module holds all the modules/classes that implement JSON's
5
7
  # functionality as C extensions.
6
8
  module Ext
7
- require 'json/ext/parser'
8
- require 'json/ext/generator'
9
- $DEBUG and warn "Using Ext extension for JSON."
10
- JSON.parser = Parser
11
- JSON.generator = Generator
9
+ 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
15
+ else
16
+ require 'json/ext/parser'
17
+ require 'json/ext/generator'
18
+ $DEBUG and warn "Using Ext extension for JSON."
19
+ JSON.parser = Parser
20
+ JSON.generator = Generator
21
+ end
12
22
  end
13
23
 
14
24
  JSON_LOADED = true unless defined?(::JSON::JSON_LOADED)
@@ -1,4 +1,4 @@
1
- #frozen_string_literal: false
1
+ # frozen_string_literal: true
2
2
  begin
3
3
  require 'ostruct'
4
4
  rescue LoadError