json_pure 2.7.5 → 2.8.0

Sign up to get free protection for your applications and to get access to all the features.
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