json_pure 2.7.4 → 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,580 +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
- case obj
305
- when Hash
306
- buf << '{'
307
- first = true
308
- obj.each_pair do |k,v|
309
- buf << ',' unless first
310
- fast_serialize_string(k.to_s, buf)
311
- buf << ':'
312
- generate_json(v, buf)
313
- first = false
314
- end
315
- buf << '}'
316
- when Array
317
- buf << '['
318
- first = true
319
- obj.each do |e|
320
- buf << ',' unless first
321
- generate_json(e, buf)
322
- first = false
323
- end
324
- buf << ']'
325
- when String
326
- fast_serialize_string(obj, buf)
327
- when Integer
328
- buf << obj.to_s
329
- else
330
- # Note: Float is handled this way since Float#to_s is slow anyway
331
- buf << obj.to_json(self)
332
- end
333
- end
334
-
335
- # Assumes !@ascii_only, !@script_safe
336
- if Regexp.method_defined?(:match?)
337
- private def fast_serialize_string(string, buf) # :nodoc:
338
- buf << '"'
339
- string = string.encode(::Encoding::UTF_8) unless string.encoding == ::Encoding::UTF_8
340
- raise GeneratorError, "source sequence is illegal/malformed utf-8" unless string.valid_encoding?
341
-
342
- if /["\\\x0-\x1f]/n.match?(string)
343
- buf << string.gsub(/["\\\x0-\x1f]/n, MAP)
344
- else
345
- buf << string
346
- end
347
- buf << '"'
348
- end
349
- else
350
- # Ruby 2.3 compatibility
351
- private def fast_serialize_string(string, buf) # :nodoc:
352
- buf << string.to_json(self)
353
- end
354
- end
355
-
356
- # Return the value returned by method +name+.
357
- def [](name)
358
- if respond_to?(name)
359
- __send__(name)
360
- else
361
- instance_variable_get("@#{name}") if
362
- instance_variables.include?("@#{name}".to_sym) # avoid warning
363
- end
364
- end
365
-
366
- def []=(name, value)
367
- if respond_to?(name_writer = "#{name}=")
368
- __send__ name_writer, value
369
- else
370
- instance_variable_set "@#{name}", value
371
- end
372
- end
373
- end
374
-
375
- module GeneratorMethods
376
- module Object
377
- # Converts this object to a string (calling #to_s), converts
378
- # it to a JSON string, and returns the result. This is a fallback, if no
379
- # special method #to_json was defined for some object.
380
- def to_json(state = nil, *)
381
- if state && State.from_state(state).strict?
382
- raise GeneratorError, "#{self.class} not allowed in JSON"
383
- else
384
- to_s.to_json
385
- end
386
- end
387
- end
388
-
389
- module Hash
390
- # Returns a JSON string containing a JSON object, that is unparsed from
391
- # this Hash instance.
392
- # _state_ is a JSON::State object, that can also be used to configure the
393
- # produced JSON string output further.
394
- # _depth_ is used to find out nesting depth, to indent accordingly.
395
- def to_json(state = nil, *)
396
- state = State.from_state(state)
397
- state.check_max_nesting
398
- json_transform(state)
399
- end
400
-
401
- private
402
-
403
- def json_shift(state)
404
- state.object_nl.empty? or return ''
405
- state.indent * state.depth
406
- end
407
-
408
- def json_transform(state)
409
- delim = ",#{state.object_nl}"
410
- result = +"{#{state.object_nl}"
411
- depth = state.depth += 1
412
- first = true
413
- indent = !state.object_nl.empty?
414
- each { |key, value|
415
- result << delim unless first
416
- result << state.indent * depth if indent
417
- result = +"#{result}#{key.to_s.to_json(state)}#{state.space_before}:#{state.space}"
418
- if state.strict? && !(false == value || true == value || nil == value || String === value || Array === value || Hash === value || Integer === value || Float === value)
419
- raise GeneratorError, "#{value.class} not allowed in JSON"
420
- elsif value.respond_to?(:to_json)
421
- result << value.to_json(state)
422
- else
423
- result << %{"#{String(value)}"}
424
- end
425
- first = false
426
- }
427
- depth = state.depth -= 1
428
- unless first
429
- result << state.object_nl
430
- result << state.indent * depth if indent
431
- end
432
- result << '}'
433
- result
434
- end
435
- end
436
-
437
- module Array
438
- # Returns a JSON string containing a JSON array, that is unparsed from
439
- # this Array instance.
440
- # _state_ is a JSON::State object, that can also be used to configure the
441
- # produced JSON string output further.
442
- def to_json(state = nil, *)
443
- state = State.from_state(state)
444
- state.check_max_nesting
445
- json_transform(state)
446
- end
447
-
448
- private
449
-
450
- def json_transform(state)
451
- result = '['.dup
452
- if state.array_nl.empty?
453
- delim = ","
454
- else
455
- result << state.array_nl
456
- delim = ",#{state.array_nl}"
457
- end
458
- depth = state.depth += 1
459
- first = true
460
- indent = !state.array_nl.empty?
461
- each { |value|
462
- result << delim unless first
463
- result << state.indent * depth if indent
464
- if state.strict? && !(false == value || true == value || nil == value || String === value || Array === value || Hash === value || Integer === value || Float === value)
465
- raise GeneratorError, "#{value.class} not allowed in JSON"
466
- elsif value.respond_to?(:to_json)
467
- result << value.to_json(state)
468
- else
469
- result << %{"#{String(value)}"}
470
- end
471
- first = false
472
- }
473
- depth = state.depth -= 1
474
- result << state.array_nl
475
- result << state.indent * depth if indent
476
- result << ']'
477
- end
478
- end
479
-
480
- module Integer
481
- # Returns a JSON string representation for this Integer number.
482
- def to_json(*) to_s end
483
- end
484
-
485
- module Float
486
- # Returns a JSON string representation for this Float number.
487
- def to_json(state = nil, *)
488
- state = State.from_state(state)
489
- case
490
- when infinite?
491
- if state.allow_nan?
492
- to_s
493
- else
494
- raise GeneratorError, "#{self} not allowed in JSON"
495
- end
496
- when nan?
497
- if state.allow_nan?
498
- to_s
499
- else
500
- raise GeneratorError, "#{self} not allowed in JSON"
501
- end
502
- else
503
- to_s
504
- end
505
- end
506
- end
507
-
508
- module String
509
- # This string should be encoded with UTF-8 A call to this method
510
- # returns a JSON string encoded with UTF16 big endian characters as
511
- # \u????.
512
- def to_json(state = nil, *args)
513
- state = State.from_state(state)
514
- if encoding == ::Encoding::UTF_8
515
- unless valid_encoding?
516
- raise GeneratorError, "source sequence is illegal/malformed utf-8"
517
- end
518
- string = self
519
- else
520
- string = encode(::Encoding::UTF_8)
521
- end
522
- if state.ascii_only?
523
- %("#{JSON.utf8_to_json_ascii(string, state.script_safe)}")
524
- else
525
- %("#{JSON.utf8_to_json(string, state.script_safe)}")
526
- end
527
- end
528
-
529
- # Module that holds the extending methods if, the String module is
530
- # included.
531
- module Extend
532
- # Raw Strings are JSON Objects (the raw bytes are stored in an
533
- # array for the key "raw"). The Ruby String can be created by this
534
- # module method.
535
- def json_create(o)
536
- o['raw'].pack('C*')
537
- end
538
- end
539
-
540
- # Extends _modul_ with the String::Extend module.
541
- def self.included(modul)
542
- modul.extend Extend
543
- end
544
-
545
- # This method creates a raw object hash, that can be nested into
546
- # other data structures and will be unparsed as a raw string. This
547
- # method should be used, if you want to convert raw strings to JSON
548
- # instead of UTF-8 strings, e. g. binary data.
549
- def to_json_raw_object
550
- {
551
- JSON.create_id => self.class.name,
552
- 'raw' => self.unpack('C*'),
553
- }
554
- end
555
-
556
- # This method creates a JSON text from the result of
557
- # a call to to_json_raw_object of this String.
558
- def to_json_raw(*args)
559
- to_json_raw_object.to_json(*args)
560
- end
561
- end
562
-
563
- module TrueClass
564
- # Returns a JSON string for true: 'true'.
565
- def to_json(*) 'true' end
566
- end
567
-
568
- module FalseClass
569
- # Returns a JSON string for false: 'false'.
570
- def to_json(*) 'false' end
571
- end
572
-
573
- module NilClass
574
- # Returns a JSON string for nil: 'null'.
575
- def to_json(*) 'null' end
576
- end
577
- end
578
- end
579
- end
580
- end