json 2.7.1 → 2.7.3.rc1

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,8 +1,11 @@
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
5
- require 'ostruct'
5
+ begin
6
+ require 'ostruct'
7
+ rescue LoadError
8
+ end
6
9
 
7
10
  class OpenStruct
8
11
 
@@ -48,4 +51,4 @@ class OpenStruct
48
51
  def to_json(*args)
49
52
  as_json.to_json(*args)
50
53
  end
51
- end
54
+ end if defined?(::OpenStruct)
@@ -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,8 +1,9 @@
1
- #frozen_string_literal: false
1
+ #frozen_string_literal: true
2
2
  require 'json/version'
3
- require 'json/generic_object'
4
3
 
5
4
  module JSON
5
+ autoload :GenericObject, 'json/generic_object'
6
+
6
7
  NOT_SET = Object.new.freeze
7
8
  private_constant :NOT_SET
8
9
 
@@ -19,11 +20,16 @@ module JSON
19
20
  # ruby = [0, 1, nil]
20
21
  # JSON[ruby] # => '[0,1,null]'
21
22
  def [](object, opts = {})
22
- if object.respond_to? :to_str
23
- JSON.parse(object.to_str, opts)
24
- else
25
- 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
26
30
  end
31
+
32
+ JSON.generate(object, opts)
27
33
  end
28
34
 
29
35
  # Returns the JSON parser class that is used by JSON. This is either
@@ -111,23 +117,17 @@ module JSON
111
117
  attr_accessor :state
112
118
  end
113
119
 
114
- DEFAULT_CREATE_ID = 'json_class'.freeze
115
- private_constant :DEFAULT_CREATE_ID
116
-
117
- CREATE_ID_TLS_KEY = "JSON.create_id".freeze
118
- private_constant :CREATE_ID_TLS_KEY
119
-
120
120
  # Sets create identifier, which is used to decide if the _json_create_
121
121
  # hook of a class should be called; initial value is +json_class+:
122
122
  # JSON.create_id # => 'json_class'
123
123
  def self.create_id=(new_value)
124
- Thread.current[CREATE_ID_TLS_KEY] = new_value.dup.freeze
124
+ Thread.current[:"JSON.create_id"] = new_value.dup.freeze
125
125
  end
126
126
 
127
127
  # Returns the current create identifier.
128
128
  # See also JSON.create_id=.
129
129
  def self.create_id
130
- Thread.current[CREATE_ID_TLS_KEY] || DEFAULT_CREATE_ID
130
+ Thread.current[:"JSON.create_id"] || 'json_class'
131
131
  end
132
132
 
133
133
  NaN = 0.0/0
@@ -215,8 +215,12 @@ module JSON
215
215
  # # Raises JSON::ParserError (783: unexpected token at ''):
216
216
  # JSON.parse('')
217
217
  #
218
- def parse(source, opts = {})
219
- Parser.new(source, **(opts||{})).parse
218
+ def parse(source, opts = nil)
219
+ if opts.nil?
220
+ Parser.new(source).parse
221
+ else
222
+ Parser.new(source, opts).parse
223
+ end
220
224
  end
221
225
 
222
226
  # :call-seq:
@@ -405,7 +409,7 @@ module JSON
405
409
  self.load_default_options = {
406
410
  :max_nesting => false,
407
411
  :allow_nan => true,
408
- :allow_blank => true,
412
+ :allow_blank => true,
409
413
  :create_additions => true,
410
414
  }
411
415
 
@@ -537,15 +541,23 @@ module JSON
537
541
  # #<Admin:0x00000000064c41f8
538
542
  # @attributes={"type"=>"Admin", "password"=>"0wn3d"}>}
539
543
  #
540
- def load(source, proc = nil, options = {})
541
- opts = load_default_options.merge options
542
- if source.respond_to? :to_str
543
- source = source.to_str
544
- elsif source.respond_to? :to_io
545
- source = source.to_io.read
546
- elsif source.respond_to?(:read)
547
- source = source.read
544
+ def load(source, proc = nil, options = nil)
545
+ opts = if options.nil?
546
+ load_default_options
547
+ else
548
+ load_default_options.merge(options)
548
549
  end
550
+
551
+ unless source.is_a?(String)
552
+ if source.respond_to? :to_str
553
+ source = source.to_str
554
+ elsif source.respond_to? :to_io
555
+ source = source.to_io.read
556
+ elsif source.respond_to?(:read)
557
+ source = source.read
558
+ end
559
+ end
560
+
549
561
  if opts[:allow_blank] && (source.nil? || source.empty?)
550
562
  source = 'null'
551
563
  end
@@ -575,13 +587,12 @@ module JSON
575
587
  # Sets or returns the default options for the JSON.dump method.
576
588
  # Initially:
577
589
  # opts = JSON.dump_default_options
578
- # opts # => {:max_nesting=>false, :allow_nan=>true, :script_safe=>false}
590
+ # opts # => {:max_nesting=>false, :allow_nan=>true}
579
591
  attr_accessor :dump_default_options
580
592
  end
581
593
  self.dump_default_options = {
582
594
  :max_nesting => false,
583
595
  :allow_nan => true,
584
- :script_safe => false,
585
596
  }
586
597
 
587
598
  # :call-seq:
@@ -612,26 +623,42 @@ module JSON
612
623
  # Output:
613
624
  # {"foo":[0,1],"bar":{"baz":2,"bat":3},"bam":"bad"}
614
625
  def dump(obj, anIO = nil, limit = nil, kwargs = nil)
615
- io_limit_opt = [anIO, limit, kwargs].compact
616
- kwargs = io_limit_opt.pop if io_limit_opt.last.is_a?(Hash)
617
- anIO, limit = io_limit_opt
618
- if anIO.respond_to?(:to_io)
619
- anIO = anIO.to_io
620
- elsif limit.nil? && !anIO.respond_to?(:write)
621
- anIO, limit = nil, anIO
626
+ if kwargs.nil?
627
+ if limit.nil?
628
+ if anIO.is_a?(Hash)
629
+ kwargs = anIO
630
+ anIO = nil
631
+ end
632
+ elsif limit.is_a?(Hash)
633
+ kwargs = limit
634
+ limit = nil
635
+ end
636
+ end
637
+
638
+ unless anIO.nil?
639
+ if anIO.respond_to?(:to_io)
640
+ anIO = anIO.to_io
641
+ elsif limit.nil? && !anIO.respond_to?(:write)
642
+ anIO, limit = nil, anIO
643
+ end
622
644
  end
645
+
623
646
  opts = JSON.dump_default_options
624
647
  opts = opts.merge(:max_nesting => limit) if limit
625
648
  opts = merge_dump_options(opts, **kwargs) if kwargs
626
- result = generate(obj, opts)
627
- if anIO
649
+
650
+ result = begin
651
+ generate(obj, opts)
652
+ rescue JSON::NestingError
653
+ raise ArgumentError, "exceed depth limit"
654
+ end
655
+
656
+ if anIO.nil?
657
+ result
658
+ else
628
659
  anIO.write result
629
660
  anIO
630
- else
631
- result
632
661
  end
633
- rescue JSON::NestingError
634
- raise ArgumentError, "exceed depth limit"
635
662
  end
636
663
 
637
664
  # Encodes string using String.encode.
@@ -677,11 +704,16 @@ module ::Kernel
677
704
  # The _opts_ argument is passed through to generate/parse respectively. See
678
705
  # generate and parse for their documentation.
679
706
  def JSON(object, *args)
680
- if object.respond_to? :to_str
681
- JSON.parse(object.to_str, args.first)
682
- else
683
- JSON.generate(object, args.first)
707
+ if object.is_a?(String)
708
+ return JSON.parse(object, args.first)
709
+ elsif object.respond_to?(:to_str)
710
+ str = object.to_str
711
+ if str.is_a?(String)
712
+ return JSON.parse(object.to_str, args.first)
713
+ end
684
714
  end
715
+
716
+ JSON.generate(object, args.first)
685
717
  end
686
718
  end
687
719
 
@@ -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,27 @@
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
+ unless RUBY_ENGINE == 'jruby'
19
+ require 'json/ext/generator/state'
20
+ end
21
+ $DEBUG and warn "Using Ext extension for JSON."
22
+ JSON.parser = Parser
23
+ JSON.generator = Generator
24
+ end
12
25
  end
13
26
 
14
27
  JSON_LOADED = true unless defined?(::JSON::JSON_LOADED)
@@ -1,5 +1,9 @@
1
- #frozen_string_literal: false
2
- require 'ostruct'
1
+ # frozen_string_literal: true
2
+ begin
3
+ require 'ostruct'
4
+ rescue LoadError
5
+ warn "JSON::GenericObject requires 'ostruct'. Please install it with `gem install ostruct`."
6
+ end
3
7
 
4
8
  module JSON
5
9
  class GenericObject < OpenStruct
@@ -67,5 +71,5 @@ module JSON
67
71
  def to_json(*a)
68
72
  as_json.to_json(*a)
69
73
  end
70
- end
74
+ end if defined?(::OpenStruct)
71
75
  end