json_pure 2.7.6 → 2.8.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 DELETED
@@ -1,25 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'json/common'
4
-
5
- module JSON
6
- # This module holds all the modules/classes that implement JSON's
7
- # functionality as C extensions.
8
- module Ext
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
22
- end
23
-
24
- JSON_LOADED = true unless defined?(::JSON::JSON_LOADED)
25
- end
@@ -1,75 +0,0 @@
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
7
-
8
- module JSON
9
- class GenericObject < OpenStruct
10
- class << self
11
- alias [] new
12
-
13
- def json_creatable?
14
- @json_creatable
15
- end
16
-
17
- attr_writer :json_creatable
18
-
19
- def json_create(data)
20
- data = data.dup
21
- data.delete JSON.create_id
22
- self[data]
23
- end
24
-
25
- def from_hash(object)
26
- case
27
- when object.respond_to?(:to_hash)
28
- result = new
29
- object.to_hash.each do |key, value|
30
- result[key] = from_hash(value)
31
- end
32
- result
33
- when object.respond_to?(:to_ary)
34
- object.to_ary.map { |a| from_hash(a) }
35
- else
36
- object
37
- end
38
- end
39
-
40
- def load(source, proc = nil, opts = {})
41
- result = ::JSON.load(source, proc, opts.merge(:object_class => self))
42
- result.nil? ? new : result
43
- end
44
-
45
- def dump(obj, *args)
46
- ::JSON.dump(obj, *args)
47
- end
48
- end
49
- self.json_creatable = false
50
-
51
- def to_hash
52
- table
53
- end
54
-
55
- def [](name)
56
- __send__(name)
57
- end unless method_defined?(:[])
58
-
59
- def []=(name, value)
60
- __send__("#{name}=", value)
61
- end unless method_defined?(:[]=)
62
-
63
- def |(other)
64
- self.class[other.to_hash.merge(to_hash)]
65
- end
66
-
67
- def as_json(*)
68
- { JSON.create_id => self.class.name }.merge to_hash
69
- end
70
-
71
- def to_json(*a)
72
- as_json.to_json(*a)
73
- end
74
- end if defined?(::OpenStruct)
75
- end
@@ -1,599 +0,0 @@
1
- # frozen_string_literal: true
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
62
-
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
86
-
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?
93
-
94
- module Pure
95
- module Generator
96
- # This class is used to create State instances, that are use to hold data
97
- # while generating a JSON text from a Ruby data structure.
98
- class State
99
- # Creates a State object from _opts_, which ought to be Hash to create
100
- # a new State instance configured by _opts_, something else to create
101
- # an unconfigured instance. If _opts_ is a State object, it is just
102
- # returned.
103
- 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
113
- end
114
- end
115
-
116
- # Instantiates a new State object, configured by _opts_.
117
- #
118
- # _opts_ can have the following keys:
119
- #
120
- # * *indent*: a string used to indent levels (default: ''),
121
- # * *space*: a string that is put after, a : or , delimiter (default: ''),
122
- # * *space_before*: a string that is put before a : pair delimiter (default: ''),
123
- # * *object_nl*: a string that is put at the end of a JSON object (default: ''),
124
- # * *array_nl*: a string that is put at the end of a JSON array (default: ''),
125
- # * *script_safe*: true if U+2028, U+2029 and forward slash (/) should be escaped
126
- # as to make the JSON object safe to interpolate in a script tag (default: false).
127
- # * *check_circular*: is deprecated now, use the :max_nesting option instead,
128
- # * *max_nesting*: sets the maximum level of data structure nesting in
129
- # the generated JSON, max_nesting = 0 if no maximum should be checked.
130
- # * *allow_nan*: true if NaN, Infinity, and -Infinity should be
131
- # generated, otherwise an exception is thrown, if these values are
132
- # encountered. This options defaults to false.
133
- def initialize(opts = {})
134
- @indent = ''
135
- @space = ''
136
- @space_before = ''
137
- @object_nl = ''
138
- @array_nl = ''
139
- @allow_nan = false
140
- @ascii_only = false
141
- @script_safe = false
142
- @strict = false
143
- @buffer_initial_length = 1024
144
- configure opts
145
- end
146
-
147
- # This string is used to indent levels in the JSON text.
148
- attr_accessor :indent
149
-
150
- # This string is used to insert a space between the tokens in a JSON
151
- # string.
152
- attr_accessor :space
153
-
154
- # This string is used to insert a space before the ':' in JSON objects.
155
- attr_accessor :space_before
156
-
157
- # This string is put at the end of a line that holds a JSON object (or
158
- # Hash).
159
- attr_accessor :object_nl
160
-
161
- # This string is put at the end of a line that holds a JSON array.
162
- attr_accessor :array_nl
163
-
164
- # This integer returns the maximum level of data structure nesting in
165
- # the generated JSON, max_nesting = 0 if no maximum is checked.
166
- attr_accessor :max_nesting
167
-
168
- # If this attribute is set to true, forward slashes will be escaped in
169
- # all json strings.
170
- attr_accessor :script_safe
171
-
172
- # If this attribute is set to true, attempting to serialize types not
173
- # supported by the JSON spec will raise a JSON::GeneratorError
174
- attr_accessor :strict
175
-
176
- # :stopdoc:
177
- attr_reader :buffer_initial_length
178
-
179
- def buffer_initial_length=(length)
180
- if length > 0
181
- @buffer_initial_length = length
182
- end
183
- end
184
- # :startdoc:
185
-
186
- # This integer returns the current depth data structure nesting in the
187
- # generated JSON.
188
- attr_accessor :depth
189
-
190
- def check_max_nesting # :nodoc:
191
- return if @max_nesting.zero?
192
- current_nesting = depth + 1
193
- current_nesting > @max_nesting and
194
- raise NestingError, "nesting of #{current_nesting} is too deep"
195
- end
196
-
197
- # Returns true, if circular data structures are checked,
198
- # otherwise returns false.
199
- def check_circular?
200
- !@max_nesting.zero?
201
- end
202
-
203
- # Returns true if NaN, Infinity, and -Infinity should be considered as
204
- # valid JSON and output.
205
- def allow_nan?
206
- @allow_nan
207
- end
208
-
209
- # Returns true, if only ASCII characters should be generated. Otherwise
210
- # returns false.
211
- def ascii_only?
212
- @ascii_only
213
- end
214
-
215
- # Returns true, if forward slashes are escaped. Otherwise returns false.
216
- def script_safe?
217
- @script_safe
218
- end
219
-
220
- # Returns true, if strict mode is enabled. Otherwise returns false.
221
- # Strict mode only allow serializing JSON native types: Hash, Array,
222
- # String, Integer, Float, true, false and nil.
223
- def strict?
224
- @strict
225
- end
226
-
227
- # Configure this State instance with the Hash _opts_, and return
228
- # itself.
229
- def configure(opts)
230
- if opts.respond_to?(:to_hash)
231
- opts = opts.to_hash
232
- elsif opts.respond_to?(:to_h)
233
- opts = opts.to_h
234
- else
235
- raise TypeError, "can't convert #{opts.class} into Hash"
236
- end
237
- opts.each do |key, value|
238
- instance_variable_set "@#{key}", value
239
- end
240
-
241
- # 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)
249
- @depth = opts[:depth] || 0
250
- @buffer_initial_length ||= opts[:buffer_initial_length]
251
-
252
- @script_safe = if opts.key?(:script_safe)
253
- !!opts[:script_safe]
254
- elsif opts.key?(:escape_slash)
255
- !!opts[:escape_slash]
256
- else
257
- false
258
- end
259
-
260
- @strict = !!opts[:strict] if opts.key?(:strict)
261
-
262
- if !opts.key?(:max_nesting) # defaults to 100
263
- @max_nesting = 100
264
- elsif opts[:max_nesting]
265
- @max_nesting = opts[:max_nesting]
266
- else
267
- @max_nesting = 0
268
- end
269
- self
270
- end
271
- alias merge configure
272
-
273
- # Returns the configuration instance variables as a hash, that can be
274
- # passed to the configure method.
275
- def to_h
276
- result = {}
277
- instance_variables.each do |iv|
278
- iv = iv.to_s[1..-1]
279
- result[iv.to_sym] = self[iv]
280
- end
281
- result
282
- end
283
-
284
- alias to_hash to_h
285
-
286
- # Generates a valid JSON document from object +obj+ and
287
- # returns the result. If no valid JSON document can be
288
- # created this method raises a
289
- # GeneratorError exception.
290
- def generate(obj)
291
- 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
293
- result = generate_json(obj, ''.dup)
294
- else
295
- result = obj.to_json(self)
296
- end
297
- JSON.valid_utf8?(result) or raise GeneratorError,
298
- "source sequence #{result.inspect} is illegal/malformed utf-8"
299
- result
300
- end
301
-
302
- # Handles @allow_nan, @buffer_initial_length, other ivars must be the default value (see above)
303
- private def generate_json(obj, buf)
304
- klass = obj.class
305
- if klass == Hash
306
- buf << '{'
307
- first = true
308
- obj.each_pair do |k,v|
309
- buf << ',' unless first
310
-
311
- key_str = k.to_s
312
- if key_str.is_a?(::String)
313
- if key_str.class == ::String
314
- fast_serialize_string(key_str, buf)
315
- else
316
- generate_json(key_str, buf)
317
- end
318
- else
319
- raise TypeError, "#{k.class}#to_s returns an instance of #{key_str.class}, expected a String"
320
- end
321
-
322
- buf << ':'
323
- generate_json(v, buf)
324
- first = false
325
- end
326
- buf << '}'
327
- elsif klass == Array
328
- buf << '['
329
- first = true
330
- obj.each do |e|
331
- buf << ',' unless first
332
- generate_json(e, buf)
333
- first = false
334
- end
335
- buf << ']'
336
- elsif klass == String
337
- fast_serialize_string(obj, buf)
338
- elsif klass == Integer
339
- buf << obj.to_s
340
- else
341
- # Note: Float is handled this way since Float#to_s is slow anyway
342
- buf << obj.to_json(self)
343
- end
344
- end
345
-
346
- # Assumes !@ascii_only, !@script_safe
347
- if Regexp.method_defined?(:match?)
348
- private def fast_serialize_string(string, buf) # :nodoc:
349
- buf << '"'
350
- string = string.encode(::Encoding::UTF_8) unless string.encoding == ::Encoding::UTF_8
351
- raise GeneratorError, "source sequence is illegal/malformed utf-8" unless string.valid_encoding?
352
-
353
- if /["\\\x0-\x1f]/n.match?(string)
354
- buf << string.gsub(/["\\\x0-\x1f]/n, MAP)
355
- else
356
- buf << string
357
- end
358
- buf << '"'
359
- end
360
- else
361
- # Ruby 2.3 compatibility
362
- private def fast_serialize_string(string, buf) # :nodoc:
363
- buf << string.to_json(self)
364
- end
365
- end
366
-
367
- # Return the value returned by method +name+.
368
- def [](name)
369
- if respond_to?(name)
370
- __send__(name)
371
- else
372
- instance_variable_get("@#{name}") if
373
- instance_variables.include?("@#{name}".to_sym) # avoid warning
374
- end
375
- end
376
-
377
- def []=(name, value)
378
- if respond_to?(name_writer = "#{name}=")
379
- __send__ name_writer, value
380
- else
381
- instance_variable_set "@#{name}", value
382
- end
383
- end
384
- end
385
-
386
- module GeneratorMethods
387
- module Object
388
- # Converts this object to a string (calling #to_s), converts
389
- # it to a JSON string, and returns the result. This is a fallback, if no
390
- # special method #to_json was defined for some object.
391
- def to_json(state = nil, *)
392
- if state && State.from_state(state).strict?
393
- raise GeneratorError, "#{self.class} not allowed in JSON"
394
- else
395
- to_s.to_json
396
- end
397
- end
398
- end
399
-
400
- module Hash
401
- # Returns a JSON string containing a JSON object, that is unparsed from
402
- # this Hash instance.
403
- # _state_ is a JSON::State object, that can also be used to configure the
404
- # produced JSON string output further.
405
- # _depth_ is used to find out nesting depth, to indent accordingly.
406
- def to_json(state = nil, *)
407
- state = State.from_state(state)
408
- state.check_max_nesting
409
- json_transform(state)
410
- end
411
-
412
- private
413
-
414
- def json_shift(state)
415
- state.object_nl.empty? or return ''
416
- state.indent * state.depth
417
- end
418
-
419
- def json_transform(state)
420
- delim = ",#{state.object_nl}"
421
- result = +"{#{state.object_nl}"
422
- depth = state.depth += 1
423
- first = true
424
- indent = !state.object_nl.empty?
425
- each { |key, value|
426
- result << delim unless first
427
- result << state.indent * depth if indent
428
-
429
- key_str = key.to_s
430
- key_json = if key_str.is_a?(::String)
431
- key_str = key_str.to_json(state)
432
- else
433
- raise TypeError, "#{key.class}#to_s returns an instance of #{key_str.class}, expected a String"
434
- end
435
-
436
- result = +"#{result}#{key_json}#{state.space_before}:#{state.space}"
437
- if state.strict? && !(false == value || true == value || nil == value || String === value || Array === value || Hash === value || Integer === value || Float === value)
438
- raise GeneratorError, "#{value.class} not allowed in JSON"
439
- elsif value.respond_to?(:to_json)
440
- result << value.to_json(state)
441
- else
442
- result << %{"#{String(value)}"}
443
- end
444
- first = false
445
- }
446
- depth = state.depth -= 1
447
- unless first
448
- result << state.object_nl
449
- result << state.indent * depth if indent
450
- end
451
- result << '}'
452
- result
453
- end
454
- end
455
-
456
- module Array
457
- # Returns a JSON string containing a JSON array, that is unparsed from
458
- # this Array instance.
459
- # _state_ is a JSON::State object, that can also be used to configure the
460
- # produced JSON string output further.
461
- def to_json(state = nil, *)
462
- state = State.from_state(state)
463
- state.check_max_nesting
464
- json_transform(state)
465
- end
466
-
467
- private
468
-
469
- def json_transform(state)
470
- result = '['.dup
471
- if state.array_nl.empty?
472
- delim = ","
473
- else
474
- result << state.array_nl
475
- delim = ",#{state.array_nl}"
476
- end
477
- depth = state.depth += 1
478
- first = true
479
- indent = !state.array_nl.empty?
480
- each { |value|
481
- result << delim unless first
482
- result << state.indent * depth if indent
483
- if state.strict? && !(false == value || true == value || nil == value || String === value || Array === value || Hash === value || Integer === value || Float === value)
484
- raise GeneratorError, "#{value.class} not allowed in JSON"
485
- elsif value.respond_to?(:to_json)
486
- result << value.to_json(state)
487
- else
488
- result << %{"#{String(value)}"}
489
- end
490
- first = false
491
- }
492
- depth = state.depth -= 1
493
- result << state.array_nl
494
- result << state.indent * depth if indent
495
- result << ']'
496
- end
497
- end
498
-
499
- module Integer
500
- # Returns a JSON string representation for this Integer number.
501
- def to_json(*) to_s end
502
- end
503
-
504
- module Float
505
- # Returns a JSON string representation for this Float number.
506
- def to_json(state = nil, *)
507
- state = State.from_state(state)
508
- case
509
- when infinite?
510
- if state.allow_nan?
511
- to_s
512
- else
513
- raise GeneratorError, "#{self} not allowed in JSON"
514
- end
515
- when nan?
516
- if state.allow_nan?
517
- to_s
518
- else
519
- raise GeneratorError, "#{self} not allowed in JSON"
520
- end
521
- else
522
- to_s
523
- end
524
- end
525
- end
526
-
527
- module String
528
- # This string should be encoded with UTF-8 A call to this method
529
- # returns a JSON string encoded with UTF16 big endian characters as
530
- # \u????.
531
- def to_json(state = nil, *args)
532
- state = State.from_state(state)
533
- if encoding == ::Encoding::UTF_8
534
- unless valid_encoding?
535
- raise GeneratorError, "source sequence is illegal/malformed utf-8"
536
- end
537
- string = self
538
- else
539
- string = encode(::Encoding::UTF_8)
540
- end
541
- if state.ascii_only?
542
- %("#{JSON.utf8_to_json_ascii(string, state.script_safe)}")
543
- else
544
- %("#{JSON.utf8_to_json(string, state.script_safe)}")
545
- end
546
- end
547
-
548
- # Module that holds the extending methods if, the String module is
549
- # included.
550
- module Extend
551
- # Raw Strings are JSON Objects (the raw bytes are stored in an
552
- # array for the key "raw"). The Ruby String can be created by this
553
- # module method.
554
- def json_create(o)
555
- o['raw'].pack('C*')
556
- end
557
- end
558
-
559
- # Extends _modul_ with the String::Extend module.
560
- def self.included(modul)
561
- modul.extend Extend
562
- end
563
-
564
- # This method creates a raw object hash, that can be nested into
565
- # other data structures and will be unparsed as a raw string. This
566
- # method should be used, if you want to convert raw strings to JSON
567
- # instead of UTF-8 strings, e. g. binary data.
568
- def to_json_raw_object
569
- {
570
- JSON.create_id => self.class.name,
571
- 'raw' => self.unpack('C*'),
572
- }
573
- end
574
-
575
- # This method creates a JSON text from the result of
576
- # a call to to_json_raw_object of this String.
577
- def to_json_raw(*args)
578
- to_json_raw_object.to_json(*args)
579
- end
580
- end
581
-
582
- module TrueClass
583
- # Returns a JSON string for true: 'true'.
584
- def to_json(*) 'true' end
585
- end
586
-
587
- module FalseClass
588
- # Returns a JSON string for false: 'false'.
589
- def to_json(*) 'false' end
590
- end
591
-
592
- module NilClass
593
- # Returns a JSON string for nil: 'null'.
594
- def to_json(*) 'null' end
595
- end
596
- end
597
- end
598
- end
599
- end