json_pure 2.6.3 → 2.7.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 47480495892b93950cd4e9e2a1cb7bdc9979b0c407265c562b07924adf33e5a3
4
- data.tar.gz: d7a139c397c9d1999f1a447f8c54900a7b4ee221393a3aaa2cf7af4c03f98d09
3
+ metadata.gz: 77e458393f6a12f043ff7acf7aca6f70409158bf1ebe613f009f88551da32295
4
+ data.tar.gz: cabc5299a4f77bf82eb7077d3048433bbb1a3bffbd2d3c1b95385712614423ef
5
5
  SHA512:
6
- metadata.gz: 1ab8582b0634745b2981725141ddf1893604e66bcf787339438d1cf3ff9ec988e1b575c4e01dd888c69c35df2193b6376db068b37ce6331e224e45593f08118d
7
- data.tar.gz: a8eb764c94a11f9e6d0e95296635dff0bf409816f19cca71f90fb9ba8d0c8edacb97ac1804b57107f4fe385cdde8d0864808b148a66dca9ba4e541e938a080b9
6
+ metadata.gz: 8ab9bf253868c6a6f637b85bc1ef432c289b733e0f41086e4a9a4a9a27fb63ebef4f7b15adb1a8792f7486f010080e9c2f902d8efaeedbb0fd2575e744e5b167
7
+ data.tar.gz: a1e77e1df8e8d219a7a88fc62160d1748f19ff4cc29120cba136114370920021216ae9e9b761391c90158566d4601d70005c4df18ae145a00b47f6803e6dca5d
data/CHANGES.md CHANGED
@@ -1,5 +1,31 @@
1
1
  # Changes
2
2
 
3
+ ### 2023-12-01 (2.7.0)
4
+
5
+ * Add a strict option to Generator #519
6
+ * `escape_slash` option was renamed as `script_safe` and now also escape U+2028 and U+2029. `escape_slash` is now an alias of `script_safe` #525
7
+ * Remove unnecessary initialization of create_id in JSON.parse() #454
8
+ * Improvements to Hash#to_json in pure implementation generator #203
9
+ * Use ruby_xfree to free buffers #518
10
+ * Fix "unexpected token" offset for Infinity #507
11
+ * Avoid using deprecated BigDecimal.new on JRuby #546
12
+ * Removed code for Ruby 1.8 #540
13
+ * Rename JSON::ParseError to JSON:ParserError #530
14
+ * Call super in included hook #486
15
+ * JRuby requires a minimum of Java 8 #516
16
+ * Always indent even if empty #517
17
+
18
+ ### 2022-11-30 (2.6.3)
19
+
20
+ * bugfix json/pure mixing escaped with literal unicode raises Encoding::CompatibilityError #483
21
+ * Stop including the parser source __LINE__ in exceptions #470
22
+
23
+ ### 2022-11-17 (2.6.2)
24
+
25
+ * Remove unknown keyword arg from DateTime.parse #488
26
+ * Ignore java artifacts by @hsbt #489
27
+ * Fix parser bug for empty string allocation #496
28
+
3
29
  ### 2021-10-24 (2.6.1)
4
30
 
5
31
  * Restore version.rb with 2.6.1
@@ -105,6 +131,19 @@
105
131
  I changed these mentions to be consistent with the Ruby license setting in
106
132
  the gemspec files which were already correct now.
107
133
 
134
+ ## 2017-01-13 (1.8.6)
135
+ * Be compatible with ancient ruby 1.8 (maybe?)
136
+
137
+ ## 2015-09-11 (1.8.5)
138
+ * Be compatible with ruby 2.4.0
139
+ * There were still some mentions of dual GPL licensing in the source, but JSON
140
+ has just the Ruby license that itself includes an explicit dual-licensing
141
+ clause that allows covered software to be distributed under the terms of
142
+ the Simplified BSD License instead for all ruby versions >= 1.9.3. This is
143
+ however a GPL compatible license according to the Free Software Foundation.
144
+ I changed these mentions to be consistent with the Ruby license setting in
145
+ the gemspec files which were already correct now.
146
+
108
147
  ## 2015-06-01 (1.8.3)
109
148
  * Fix potential memory leak, thx to nobu.
110
149
 
data/README.md CHANGED
@@ -12,8 +12,7 @@ will be two variants available:
12
12
  extensions, which are both part of the ruby standard library.
13
13
  * The quite a bit faster native extension variant, which is in parts
14
14
  implemented in C or Java and comes with its own unicode conversion
15
- functions and a parser generated by the ragel state machine compiler
16
- http://www.complang.org/ragel/ .
15
+ functions and a parser generated by the [Ragel] state machine compiler.
17
16
 
18
17
  Both variants of the JSON generator generate UTF-8 character sequences by
19
18
  default. If an :ascii\_only option with a true value is given, they escape all
@@ -71,8 +70,7 @@ with:
71
70
  ## Compiling the extensions yourself
72
71
 
73
72
  If you want to create the `parser.c` file from its `parser.rl` file or draw nice
74
- graphviz images of the state machines, you need ragel from:
75
- http://www.complang.org/ragel/
73
+ graphviz images of the state machines, you need [Ragel].
76
74
 
77
75
  ## Usage
78
76
 
@@ -423,3 +421,5 @@ The latest version of this library can be downloaded at
423
421
  Online Documentation should be located at
424
422
 
425
423
  * https://www.rubydoc.info/gems/json
424
+
425
+ [Ragel]: http://www.colm.net/open-source/ragel/
data/VERSION CHANGED
@@ -1 +1 @@
1
- 2.6.3
1
+ 2.7.0
data/json_pure.gemspec CHANGED
@@ -41,12 +41,12 @@ Gem::Specification.new do |s|
41
41
  "lib/json/pure/parser.rb".freeze,
42
42
  "lib/json/version.rb".freeze,
43
43
  ]
44
- s.homepage = "http://flori.github.com/json".freeze
44
+ s.homepage = "https://flori.github.io/json".freeze
45
45
  s.metadata = {
46
46
  'bug_tracker_uri' => 'https://github.com/flori/json/issues',
47
47
  'changelog_uri' => 'https://github.com/flori/json/blob/master/CHANGES.md',
48
- 'documentation_uri' => 'http://flori.github.io/json/doc/index.html',
49
- 'homepage_uri' => 'http://flori.github.io/json/',
48
+ 'documentation_uri' => 'https://flori.github.io/json/doc/index.html',
49
+ 'homepage_uri' => s.homepage,
50
50
  'source_code_uri' => 'https://github.com/flori/json',
51
51
  'wiki_uri' => 'https://github.com/flori/json/wiki'
52
52
  }
@@ -2,7 +2,10 @@
2
2
  unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED
3
3
  require 'json'
4
4
  end
5
- defined?(::BigDecimal) or require 'bigdecimal'
5
+ begin
6
+ require 'bigdecimal'
7
+ rescue LoadError
8
+ end
6
9
 
7
10
  class BigDecimal
8
11
  # Import a JSON Marshalled object.
@@ -26,4 +29,4 @@ class BigDecimal
26
29
  def to_json(*args)
27
30
  as_json.to_json(*args)
28
31
  end
29
- end
32
+ end if defined?(::BigDecimal)
@@ -5,14 +5,25 @@ end
5
5
 
6
6
  class Range
7
7
 
8
- # Deserializes JSON string by constructing new Range object with arguments
9
- # <tt>a</tt> serialized by <tt>to_json</tt>.
8
+ # Returns a new \Range object constructed from <tt>object['a']</tt>,
9
+ # which must be an array of values suitable for a call to Range.new:
10
+ #
11
+ # require 'json/add/range'
12
+ # Range.json_create({"a"=>[1, 4]}) # => 1..4
13
+ # Range.json_create({"a"=>[1, 4, true]}) # => 1...4
14
+ # Range.json_create({"a" => ['a', 'd']}) # => "a".."d"
15
+ #
10
16
  def self.json_create(object)
11
17
  new(*object['a'])
12
18
  end
13
19
 
14
- # Returns a hash, that will be turned into a JSON object and represent this
15
- # object.
20
+ # Returns a 2-element hash representing +self+:
21
+ #
22
+ # require 'json/add/range'
23
+ # (1..4).as_json # => {"json_class"=>"Range", "a"=>[1, 4, false]}
24
+ # (1...4).as_json # => {"json_class"=>"Range", "a"=>[1, 4, true]}
25
+ # ('a'..'d').as_json # => {"json_class"=>"Range", "a"=>["a", "d", false]}
26
+ #
16
27
  def as_json(*)
17
28
  {
18
29
  JSON.create_id => self.class.name,
@@ -20,9 +31,13 @@ class Range
20
31
  }
21
32
  end
22
33
 
23
- # Stores class name (Range) with JSON array of arguments <tt>a</tt> which
24
- # include <tt>first</tt> (integer), <tt>last</tt> (integer), and
25
- # <tt>exclude_end?</tt> (boolean) as JSON string.
34
+ # Returns a JSON string representing +self+:
35
+ #
36
+ # require 'json/add/range'
37
+ # (1..4).to_json # => "{\"json_class\":\"Range\",\"a\":[1,4,false]}"
38
+ # (1...4).to_json # => "{\"json_class\":\"Range\",\"a\":[1,4,true]}"
39
+ # ('a'..'d').to_json # => "{\"json_class\":\"Range\",\"a\":[\"a\",\"d\",false]}"
40
+ #
26
41
  def to_json(*args)
27
42
  as_json.to_json(*args)
28
43
  end
data/lib/json/common.rb CHANGED
@@ -3,6 +3,9 @@ require 'json/version'
3
3
  require 'json/generic_object'
4
4
 
5
5
  module JSON
6
+ NOT_SET = Object.new.freeze
7
+ private_constant :NOT_SET
8
+
6
9
  class << self
7
10
  # :call-seq:
8
11
  # JSON[object] -> new_array or new_string
@@ -295,19 +298,9 @@ module JSON
295
298
  #
296
299
  def generate(obj, opts = nil)
297
300
  if State === opts
298
- state, opts = opts, nil
301
+ state = opts
299
302
  else
300
- state = State.new
301
- end
302
- if opts
303
- if opts.respond_to? :to_hash
304
- opts = opts.to_hash
305
- elsif opts.respond_to? :to_h
306
- opts = opts.to_h
307
- else
308
- raise TypeError, "can't convert #{opts.class} into Hash"
309
- end
310
- state = state.configure(opts)
303
+ state = State.new(opts)
311
304
  end
312
305
  state.generate(obj)
313
306
  end
@@ -334,19 +327,9 @@ module JSON
334
327
  # JSON.fast_generate(a)
335
328
  def fast_generate(obj, opts = nil)
336
329
  if State === opts
337
- state, opts = opts, nil
330
+ state = opts
338
331
  else
339
- state = JSON.create_fast_state
340
- end
341
- if opts
342
- if opts.respond_to? :to_hash
343
- opts = opts.to_hash
344
- elsif opts.respond_to? :to_h
345
- opts = opts.to_h
346
- else
347
- raise TypeError, "can't convert #{opts.class} into Hash"
348
- end
349
- state.configure(opts)
332
+ state = JSON.create_fast_state.configure(opts)
350
333
  end
351
334
  state.generate(obj)
352
335
  end
@@ -592,13 +575,13 @@ module JSON
592
575
  # Sets or returns the default options for the JSON.dump method.
593
576
  # Initially:
594
577
  # opts = JSON.dump_default_options
595
- # opts # => {:max_nesting=>false, :allow_nan=>true, :escape_slash=>false}
578
+ # opts # => {:max_nesting=>false, :allow_nan=>true, :script_safe=>false}
596
579
  attr_accessor :dump_default_options
597
580
  end
598
581
  self.dump_default_options = {
599
582
  :max_nesting => false,
600
583
  :allow_nan => true,
601
- :escape_slash => false,
584
+ :script_safe => false,
602
585
  }
603
586
 
604
587
  # :call-seq:
@@ -628,7 +611,7 @@ module JSON
628
611
  # puts File.read(path)
629
612
  # Output:
630
613
  # {"foo":[0,1],"bar":{"baz":2,"bat":3},"bam":"bad"}
631
- def dump(obj, anIO = nil, limit = nil)
614
+ def dump(obj, anIO = nil, limit = nil, strict: NOT_SET)
632
615
  if anIO and limit.nil?
633
616
  anIO = anIO.to_io if anIO.respond_to?(:to_io)
634
617
  unless anIO.respond_to?(:write)
@@ -638,6 +621,7 @@ module JSON
638
621
  end
639
622
  opts = JSON.dump_default_options
640
623
  opts = opts.merge(:max_nesting => limit) if limit
624
+ opts[:strict] = strict if NOT_SET != strict
641
625
  result = generate(obj, opts)
642
626
  if anIO
643
627
  anIO.write result
@@ -37,25 +37,34 @@ module JSON
37
37
  '\\' => '\\\\',
38
38
  } # :nodoc:
39
39
 
40
- ESCAPE_SLASH_MAP = MAP.merge(
40
+ ESCAPE_PATTERN = /[\/"\\\x0-\x1f]/n # :nodoc:
41
+
42
+ SCRIPT_SAFE_MAP = MAP.merge(
41
43
  '/' => '\\/',
44
+ "\u2028".b => '\u2028',
45
+ "\u2029".b => '\u2029',
42
46
  )
43
47
 
48
+ SCRIPT_SAFE_ESCAPE_PATTERN = Regexp.union(ESCAPE_PATTERN, "\u2028".b, "\u2029".b)
49
+
44
50
  # Convert a UTF8 encoded Ruby string _string_ to a JSON string, encoded with
45
51
  # UTF16 big endian characters as \u????, and return it.
46
- def utf8_to_json(string, escape_slash = false) # :nodoc:
52
+ def utf8_to_json(string, script_safe = false) # :nodoc:
47
53
  string = string.dup
48
54
  string.force_encoding(::Encoding::ASCII_8BIT)
49
- map = escape_slash ? ESCAPE_SLASH_MAP : MAP
50
- string.gsub!(/[\/"\\\x0-\x1f]/) { map[$&] || $& }
55
+ if script_safe
56
+ string.gsub!(SCRIPT_SAFE_ESCAPE_PATTERN) { SCRIPT_SAFE_MAP[$&] || $& }
57
+ else
58
+ string.gsub!(ESCAPE_PATTERN) { MAP[$&] || $& }
59
+ end
51
60
  string.force_encoding(::Encoding::UTF_8)
52
61
  string
53
62
  end
54
63
 
55
- def utf8_to_json_ascii(string, escape_slash = false) # :nodoc:
64
+ def utf8_to_json_ascii(string, script_safe = false) # :nodoc:
56
65
  string = string.dup
57
66
  string.force_encoding(::Encoding::ASCII_8BIT)
58
- map = escape_slash ? ESCAPE_SLASH_MAP : MAP
67
+ map = script_safe ? SCRIPT_SAFE_MAP : MAP
59
68
  string.gsub!(/[\/"\\\x0-\x1f]/n) { map[$&] || $& }
60
69
  string.gsub!(/(
61
70
  (?:
@@ -115,7 +124,8 @@ module JSON
115
124
  # * *space_before*: a string that is put before a : pair delimiter (default: ''),
116
125
  # * *object_nl*: a string that is put at the end of a JSON object (default: ''),
117
126
  # * *array_nl*: a string that is put at the end of a JSON array (default: ''),
118
- # * *escape_slash*: true if forward slash (/) should be escaped (default: false)
127
+ # * *script_safe*: true if U+2028, U+2029 and forward slash (/) should be escaped
128
+ # as to make the JSON object safe to interpolate in a script tag (default: false).
119
129
  # * *check_circular*: is deprecated now, use the :max_nesting option instead,
120
130
  # * *max_nesting*: sets the maximum level of data structure nesting in
121
131
  # the generated JSON, max_nesting = 0 if no maximum should be checked.
@@ -130,7 +140,8 @@ module JSON
130
140
  @array_nl = ''
131
141
  @allow_nan = false
132
142
  @ascii_only = false
133
- @escape_slash = false
143
+ @script_safe = false
144
+ @strict = false
134
145
  @buffer_initial_length = 1024
135
146
  configure opts
136
147
  end
@@ -158,7 +169,11 @@ module JSON
158
169
 
159
170
  # If this attribute is set to true, forward slashes will be escaped in
160
171
  # all json strings.
161
- attr_accessor :escape_slash
172
+ attr_accessor :script_safe
173
+
174
+ # If this attribute is set to true, attempting to serialize types not
175
+ # supported by the JSON spec will raise a JSON::GeneratorError
176
+ attr_accessor :strict
162
177
 
163
178
  # :stopdoc:
164
179
  attr_reader :buffer_initial_length
@@ -200,8 +215,13 @@ module JSON
200
215
  end
201
216
 
202
217
  # Returns true, if forward slashes are escaped. Otherwise returns false.
203
- def escape_slash?
204
- @escape_slash
218
+ def script_safe?
219
+ @script_safe
220
+ end
221
+
222
+ # Returns true, if forward slashes are escaped. Otherwise returns false.
223
+ def strict?
224
+ @strict
205
225
  end
206
226
 
207
227
  # Configure this State instance with the Hash _opts_, and return
@@ -214,7 +234,7 @@ module JSON
214
234
  else
215
235
  raise TypeError, "can't convert #{opts.class} into Hash"
216
236
  end
217
- for key, value in opts
237
+ opts.each do |key, value|
218
238
  instance_variable_set "@#{key}", value
219
239
  end
220
240
  @indent = opts[:indent] if opts.key?(:indent)
@@ -226,7 +246,16 @@ module JSON
226
246
  @ascii_only = opts[:ascii_only] if opts.key?(:ascii_only)
227
247
  @depth = opts[:depth] || 0
228
248
  @buffer_initial_length ||= opts[:buffer_initial_length]
229
- @escape_slash = !!opts[:escape_slash] if opts.key?(:escape_slash)
249
+
250
+ @script_safe = if opts.key?(:script_safe)
251
+ !!opts[:script_safe]
252
+ elsif opts.key?(:escape_slash)
253
+ !!opts[:escape_slash]
254
+ else
255
+ false
256
+ end
257
+
258
+ @strict = !!opts[:strict] if opts.key?(:strict)
230
259
 
231
260
  if !opts.key?(:max_nesting) # defaults to 100
232
261
  @max_nesting = 100
@@ -243,7 +272,7 @@ module JSON
243
272
  # passed to the configure method.
244
273
  def to_h
245
274
  result = {}
246
- for iv in instance_variables
275
+ instance_variables.each do |iv|
247
276
  iv = iv.to_s[1..-1]
248
277
  result[iv.to_sym] = self[iv]
249
278
  end
@@ -287,7 +316,13 @@ module JSON
287
316
  # Converts this object to a string (calling #to_s), converts
288
317
  # it to a JSON string, and returns the result. This is a fallback, if no
289
318
  # special method #to_json was defined for some object.
290
- def to_json(*) to_s.to_json end
319
+ def to_json(generator_state)
320
+ if generator_state.strict?
321
+ raise GeneratorError, "#{self.class} not allowed in JSON"
322
+ else
323
+ to_s.to_json
324
+ end
325
+ end
291
326
  end
292
327
 
293
328
  module Hash
@@ -310,21 +345,18 @@ module JSON
310
345
  end
311
346
 
312
347
  def json_transform(state)
313
- delim = ','
314
- delim << state.object_nl
315
- result = '{'
316
- result << state.object_nl
348
+ delim = ",#{state.object_nl}"
349
+ result = "{#{state.object_nl}"
317
350
  depth = state.depth += 1
318
351
  first = true
319
352
  indent = !state.object_nl.empty?
320
- each { |key,value|
353
+ each { |key, value|
321
354
  result << delim unless first
322
355
  result << state.indent * depth if indent
323
- result << key.to_s.to_json(state)
324
- result << state.space_before
325
- result << ':'
326
- result << state.space
327
- if value.respond_to?(:to_json)
356
+ result = "#{result}#{key.to_s.to_json(state)}#{state.space_before}:#{state.space}"
357
+ if state.strict?
358
+ raise GeneratorError, "#{value.class} not allowed in JSON"
359
+ elsif value.respond_to?(:to_json)
328
360
  result << value.to_json(state)
329
361
  else
330
362
  result << %{"#{String(value)}"}
@@ -365,7 +397,9 @@ module JSON
365
397
  each { |value|
366
398
  result << delim unless first
367
399
  result << state.indent * depth if indent
368
- if value.respond_to?(:to_json)
400
+ if state.strict?
401
+ raise GeneratorError, "#{value.class} not allowed in JSON"
402
+ elsif value.respond_to?(:to_json)
369
403
  result << value.to_json(state)
370
404
  else
371
405
  result << %{"#{String(value)}"}
@@ -419,9 +453,9 @@ module JSON
419
453
  string = encode(::Encoding::UTF_8)
420
454
  end
421
455
  if state.ascii_only?
422
- '"' << JSON.utf8_to_json_ascii(string, state.escape_slash) << '"'
456
+ '"' << JSON.utf8_to_json_ascii(string, state.script_safe) << '"'
423
457
  else
424
- '"' << JSON.utf8_to_json(string, state.escape_slash) << '"'
458
+ '"' << JSON.utf8_to_json(string, state.script_safe) << '"'
425
459
  end
426
460
  end
427
461
 
data/lib/json/version.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: false
2
2
  module JSON
3
3
  # JSON version
4
- VERSION = '2.6.3'
4
+ VERSION = '2.7.0'
5
5
  VERSION_ARRAY = VERSION.split(/\./).map { |x| x.to_i } # :nodoc:
6
6
  VERSION_MAJOR = VERSION_ARRAY[0] # :nodoc:
7
7
  VERSION_MINOR = VERSION_ARRAY[1] # :nodoc:
data/lib/json.rb CHANGED
@@ -285,6 +285,15 @@ require 'json/common'
285
285
  # # Raises JSON::NestingError (nesting of 2 is too deep):
286
286
  # JSON.generate(obj, max_nesting: 2)
287
287
  #
288
+ # ====== Escaping Options
289
+ #
290
+ # Options +script_safe+ (boolean) specifies wether <tt>'\u2028'</tt>, <tt>'\u2029'</tt>
291
+ # and <tt>'/'</tt> should be escaped as to make the JSON object safe to interpolate in script
292
+ # tags.
293
+ #
294
+ # Options +ascii_only+ (boolean) specifies wether all characters outside the ASCII range
295
+ # should be escaped.
296
+ #
288
297
  # ====== Output Options
289
298
  #
290
299
  # The default formatting options generate the most compact
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: json_pure
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.6.3
4
+ version: 2.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Florian Frank
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-12-05 00:00:00.000000000 Z
11
+ date: 2023-12-01 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: This is a JSON implementation in pure Ruby.
14
14
  email: flori@ping.de
@@ -44,14 +44,14 @@ files:
44
44
  - lib/json/pure/generator.rb
45
45
  - lib/json/pure/parser.rb
46
46
  - lib/json/version.rb
47
- homepage: http://flori.github.com/json
47
+ homepage: https://flori.github.io/json
48
48
  licenses:
49
49
  - Ruby
50
50
  metadata:
51
51
  bug_tracker_uri: https://github.com/flori/json/issues
52
52
  changelog_uri: https://github.com/flori/json/blob/master/CHANGES.md
53
- documentation_uri: http://flori.github.io/json/doc/index.html
54
- homepage_uri: http://flori.github.io/json/
53
+ documentation_uri: https://flori.github.io/json/doc/index.html
54
+ homepage_uri: https://flori.github.io/json
55
55
  source_code_uri: https://github.com/flori/json
56
56
  wiki_uri: https://github.com/flori/json/wiki
57
57
  post_install_message:
@@ -73,7 +73,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
73
73
  - !ruby/object:Gem::Version
74
74
  version: '0'
75
75
  requirements: []
76
- rubygems_version: 3.4.0.dev
76
+ rubygems_version: 3.5.0.dev
77
77
  signing_key:
78
78
  specification_version: 4
79
79
  summary: JSON Implementation for Ruby