json_pure 2.7.6 → 2.8.1

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,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