psych 3.0.3 → 3.3.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.
- checksums.yaml +4 -4
- data/Gemfile +6 -0
- data/LICENSE +21 -0
- data/README.md +3 -6
- data/Rakefile +2 -16
- data/ext/psych/depend +2 -0
- data/ext/psych/extconf.rb +6 -2
- data/ext/psych/psych.c +6 -3
- data/ext/psych/psych_parser.c +20 -33
- data/ext/psych/psych_yaml_tree.c +0 -12
- data/ext/psych/yaml/api.c +48 -47
- data/ext/psych/yaml/config.h +77 -7
- data/ext/psych/yaml/dumper.c +3 -3
- data/ext/psych/yaml/emitter.c +48 -19
- data/ext/psych/yaml/loader.c +210 -110
- data/ext/psych/yaml/parser.c +11 -6
- data/ext/psych/yaml/reader.c +3 -3
- data/ext/psych/yaml/scanner.c +52 -28
- data/ext/psych/yaml/yaml.h +42 -28
- data/ext/psych/yaml/yaml_private.h +46 -20
- data/lib/psych.rb +171 -77
- data/lib/psych/class_loader.rb +6 -4
- data/lib/psych/handler.rb +1 -1
- data/lib/psych/nodes/node.rb +2 -2
- data/lib/psych/scalar_scanner.rb +23 -36
- data/lib/psych/versions.rb +4 -3
- data/lib/psych/visitors/to_ruby.rb +50 -17
- data/lib/psych/visitors/visitor.rb +17 -3
- data/lib/psych/visitors/yaml_tree.rb +30 -42
- data/psych.gemspec +18 -14
- metadata +10 -55
- data/.travis.yml +0 -20
- data/CHANGELOG.rdoc +0 -576
data/lib/psych/class_loader.rb
CHANGED
@@ -35,9 +35,11 @@ module Psych
|
|
35
35
|
|
36
36
|
constants.each do |const|
|
37
37
|
konst = const_get const
|
38
|
-
|
39
|
-
|
40
|
-
|
38
|
+
class_eval <<~RUBY
|
39
|
+
def #{const.to_s.downcase}
|
40
|
+
load #{konst.inspect}
|
41
|
+
end
|
42
|
+
RUBY
|
41
43
|
end
|
42
44
|
|
43
45
|
private
|
@@ -69,7 +71,7 @@ module Psych
|
|
69
71
|
rescue
|
70
72
|
nil
|
71
73
|
end
|
72
|
-
}.compact]
|
74
|
+
}.compact].freeze
|
73
75
|
|
74
76
|
class Restricted < ClassLoader
|
75
77
|
def initialize classes, symbols
|
data/lib/psych/handler.rb
CHANGED
@@ -105,7 +105,7 @@ module Psych
|
|
105
105
|
# - first element
|
106
106
|
# - *ponies
|
107
107
|
#
|
108
|
-
# &ponies is the
|
108
|
+
# &ponies is the anchor, *ponies is the alias. In this case, alias is
|
109
109
|
# called with "ponies".
|
110
110
|
def alias anchor
|
111
111
|
end
|
data/lib/psych/nodes/node.rb
CHANGED
@@ -46,8 +46,8 @@ module Psych
|
|
46
46
|
# Convert this node to Ruby.
|
47
47
|
#
|
48
48
|
# See also Psych::Visitors::ToRuby
|
49
|
-
def to_ruby
|
50
|
-
Visitors::ToRuby.create.accept(self)
|
49
|
+
def to_ruby(symbolize_names: false, freeze: false)
|
50
|
+
Visitors::ToRuby.create(symbolize_names: symbolize_names, freeze: freeze).accept(self)
|
51
51
|
end
|
52
52
|
alias :transform :to_ruby
|
53
53
|
|
data/lib/psych/scalar_scanner.rb
CHANGED
@@ -14,16 +14,15 @@ module Psych
|
|
14
14
|
|\.(nan|NaN|NAN)(?# not a number))$/x
|
15
15
|
|
16
16
|
# Taken from http://yaml.org/type/int.html
|
17
|
-
INTEGER = /^(?:[-+]?0b[0-1_]+ (?# base 2)
|
18
|
-
|[-+]?0[0-7_]+ (?# base 8)
|
19
|
-
|[-+]?(?:0|[1-9][0-9_]*) (?# base 10)
|
20
|
-
|[-+]?0x[0-9a-fA-F_]+ (?# base 16))$/x
|
17
|
+
INTEGER = /^(?:[-+]?0b[0-1_,]+ (?# base 2)
|
18
|
+
|[-+]?0[0-7_,]+ (?# base 8)
|
19
|
+
|[-+]?(?:0|[1-9][0-9_,]*) (?# base 10)
|
20
|
+
|[-+]?0x[0-9a-fA-F_,]+ (?# base 16))$/x
|
21
21
|
|
22
22
|
attr_reader :class_loader
|
23
23
|
|
24
24
|
# Create a new scanner
|
25
25
|
def initialize class_loader
|
26
|
-
@string_cache = {}
|
27
26
|
@symbol_cache = {}
|
28
27
|
@class_loader = class_loader
|
29
28
|
end
|
@@ -31,81 +30,70 @@ module Psych
|
|
31
30
|
# Tokenize +string+ returning the Ruby object
|
32
31
|
def tokenize string
|
33
32
|
return nil if string.empty?
|
34
|
-
return string if @string_cache.key?(string)
|
35
33
|
return @symbol_cache[string] if @symbol_cache.key?(string)
|
36
34
|
|
37
|
-
case string
|
38
35
|
# Check for a String type, being careful not to get caught by hash keys, hex values, and
|
39
36
|
# special floats (e.g., -.inf).
|
40
|
-
|
41
|
-
if string.length > 5
|
42
|
-
@string_cache[string] = true
|
43
|
-
return string
|
44
|
-
end
|
37
|
+
if string.match?(/^[^\d\.:-]?[A-Za-z_\s!@#\$%\^&\*\(\)\{\}\<\>\|\/\\~;=]+/) || string.match?(/\n/)
|
38
|
+
return string if string.length > 5
|
45
39
|
|
46
|
-
|
47
|
-
when /^[^ytonf~]/i
|
48
|
-
@string_cache[string] = true
|
40
|
+
if string.match?(/^[^ytonf~]/i)
|
49
41
|
string
|
50
|
-
|
42
|
+
elsif string == '~' || string.match?(/^null$/i)
|
51
43
|
nil
|
52
|
-
|
44
|
+
elsif string.match?(/^(yes|true|on)$/i)
|
53
45
|
true
|
54
|
-
|
46
|
+
elsif string.match?(/^(no|false|off)$/i)
|
55
47
|
false
|
56
48
|
else
|
57
|
-
@string_cache[string] = true
|
58
49
|
string
|
59
50
|
end
|
60
|
-
|
51
|
+
elsif string.match?(TIME)
|
61
52
|
begin
|
62
53
|
parse_time string
|
63
54
|
rescue ArgumentError
|
64
55
|
string
|
65
56
|
end
|
66
|
-
|
57
|
+
elsif string.match?(/^\d{4}-(?:1[012]|0\d|\d)-(?:[12]\d|3[01]|0\d|\d)$/)
|
67
58
|
require 'date'
|
68
59
|
begin
|
69
60
|
class_loader.date.strptime(string, '%Y-%m-%d')
|
70
61
|
rescue ArgumentError
|
71
62
|
string
|
72
63
|
end
|
73
|
-
|
64
|
+
elsif string.match?(/^\.inf$/i)
|
74
65
|
Float::INFINITY
|
75
|
-
|
66
|
+
elsif string.match?(/^-\.inf$/i)
|
76
67
|
-Float::INFINITY
|
77
|
-
|
68
|
+
elsif string.match?(/^\.nan$/i)
|
78
69
|
Float::NAN
|
79
|
-
|
70
|
+
elsif string.match?(/^:./)
|
80
71
|
if string =~ /^:(["'])(.*)\1/
|
81
72
|
@symbol_cache[string] = class_loader.symbolize($2.sub(/^:/, ''))
|
82
73
|
else
|
83
74
|
@symbol_cache[string] = class_loader.symbolize(string.sub(/^:/, ''))
|
84
75
|
end
|
85
|
-
|
76
|
+
elsif string.match?(/^[-+]?[0-9][0-9_]*(:[0-5]?[0-9]){1,2}$/)
|
86
77
|
i = 0
|
87
78
|
string.split(':').each_with_index do |n,e|
|
88
79
|
i += (n.to_i * 60 ** (e - 2).abs)
|
89
80
|
end
|
90
81
|
i
|
91
|
-
|
82
|
+
elsif string.match?(/^[-+]?[0-9][0-9_]*(:[0-5]?[0-9]){1,2}\.[0-9_]*$/)
|
92
83
|
i = 0
|
93
84
|
string.split(':').each_with_index do |n,e|
|
94
85
|
i += (n.to_f * 60 ** (e - 2).abs)
|
95
86
|
end
|
96
87
|
i
|
97
|
-
|
98
|
-
if string
|
99
|
-
@string_cache[string] = true
|
88
|
+
elsif string.match?(FLOAT)
|
89
|
+
if string.match?(/\A[-+]?\.\Z/)
|
100
90
|
string
|
101
91
|
else
|
102
92
|
Float(string.gsub(/[,_]|\.([Ee]|$)/, '\1'))
|
103
93
|
end
|
94
|
+
elsif string.match?(INTEGER)
|
95
|
+
parse_int string
|
104
96
|
else
|
105
|
-
int = parse_int string.gsub(/[,_]/, '')
|
106
|
-
return int if int
|
107
|
-
|
108
|
-
@string_cache[string] = true
|
109
97
|
string
|
110
98
|
end
|
111
99
|
end
|
@@ -113,8 +101,7 @@ module Psych
|
|
113
101
|
###
|
114
102
|
# Parse and return an int from +string+
|
115
103
|
def parse_int string
|
116
|
-
|
117
|
-
Integer(string)
|
104
|
+
Integer(string.gsub(/[,_]/, ''))
|
118
105
|
end
|
119
106
|
|
120
107
|
###
|
data/lib/psych/versions.rb
CHANGED
@@ -1,9 +1,10 @@
|
|
1
|
+
|
1
2
|
# frozen_string_literal: true
|
2
3
|
module Psych
|
3
|
-
# The version
|
4
|
-
VERSION = '3.
|
4
|
+
# The version of Psych you are using
|
5
|
+
VERSION = '3.3.1'
|
5
6
|
|
6
7
|
if RUBY_ENGINE == 'jruby'
|
7
|
-
DEFAULT_SNAKEYAML_VERSION = '1.
|
8
|
+
DEFAULT_SNAKEYAML_VERSION = '1.28'.freeze
|
8
9
|
end
|
9
10
|
end
|
@@ -12,39 +12,44 @@ module Psych
|
|
12
12
|
###
|
13
13
|
# This class walks a YAML AST, converting each node to Ruby
|
14
14
|
class ToRuby < Psych::Visitors::Visitor
|
15
|
-
def self.create
|
15
|
+
def self.create(symbolize_names: false, freeze: false)
|
16
16
|
class_loader = ClassLoader.new
|
17
17
|
scanner = ScalarScanner.new class_loader
|
18
|
-
new(scanner, class_loader)
|
18
|
+
new(scanner, class_loader, symbolize_names: symbolize_names, freeze: freeze)
|
19
19
|
end
|
20
20
|
|
21
21
|
attr_reader :class_loader
|
22
22
|
|
23
|
-
def initialize ss, class_loader
|
23
|
+
def initialize ss, class_loader, symbolize_names: false, freeze: false
|
24
24
|
super()
|
25
25
|
@st = {}
|
26
26
|
@ss = ss
|
27
|
+
@load_tags = Psych.load_tags
|
27
28
|
@domain_types = Psych.domain_types
|
28
29
|
@class_loader = class_loader
|
30
|
+
@symbolize_names = symbolize_names
|
31
|
+
@freeze = freeze
|
29
32
|
end
|
30
33
|
|
31
34
|
def accept target
|
32
35
|
result = super
|
33
|
-
return result if @domain_types.empty? || !target.tag
|
34
36
|
|
35
|
-
|
36
|
-
|
37
|
+
unless @domain_types.empty? || !target.tag
|
38
|
+
key = target.tag.sub(/^[!\/]*/, '').sub(/(,\d+)\//, '\1:')
|
39
|
+
key = "tag:#{key}" unless key =~ /^(?:tag:|x-private)/
|
37
40
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
+
if @domain_types.key? key
|
42
|
+
value, block = @domain_types[key]
|
43
|
+
result = block.call value, result
|
44
|
+
end
|
41
45
|
end
|
42
46
|
|
47
|
+
result = deduplicate(result).freeze if @freeze
|
43
48
|
result
|
44
49
|
end
|
45
50
|
|
46
51
|
def deserialize o
|
47
|
-
if klass = resolve_class(
|
52
|
+
if klass = resolve_class(@load_tags[o.tag])
|
48
53
|
instance = klass.allocate
|
49
54
|
|
50
55
|
if instance.respond_to?(:init_with)
|
@@ -124,7 +129,7 @@ module Psych
|
|
124
129
|
end
|
125
130
|
|
126
131
|
def visit_Psych_Nodes_Sequence o
|
127
|
-
if klass = resolve_class(
|
132
|
+
if klass = resolve_class(@load_tags[o.tag])
|
128
133
|
instance = klass.allocate
|
129
134
|
|
130
135
|
if instance.respond_to?(:init_with)
|
@@ -156,8 +161,8 @@ module Psych
|
|
156
161
|
end
|
157
162
|
|
158
163
|
def visit_Psych_Nodes_Mapping o
|
159
|
-
if
|
160
|
-
return revive(resolve_class(
|
164
|
+
if @load_tags[o.tag]
|
165
|
+
return revive(resolve_class(@load_tags[o.tag]), o)
|
161
166
|
end
|
162
167
|
return revive_hash(register(o, {}), o) unless o.tag
|
163
168
|
|
@@ -252,6 +257,8 @@ module Psych
|
|
252
257
|
|
253
258
|
e = build_exception((resolve_class($1) || class_loader.exception),
|
254
259
|
h.delete('message'))
|
260
|
+
|
261
|
+
e.set_backtrace h.delete('backtrace') if h.key? 'backtrace'
|
255
262
|
init_with(e, h, o)
|
256
263
|
|
257
264
|
when '!set', 'tag:yaml.org,2002:set'
|
@@ -320,6 +327,7 @@ module Psych
|
|
320
327
|
end
|
321
328
|
|
322
329
|
private
|
330
|
+
|
323
331
|
def register node, object
|
324
332
|
@st[node.anchor] = object if node.anchor
|
325
333
|
object
|
@@ -331,13 +339,12 @@ module Psych
|
|
331
339
|
list
|
332
340
|
end
|
333
341
|
|
334
|
-
|
335
|
-
def revive_hash hash, o
|
342
|
+
def revive_hash hash, o, tagged= false
|
336
343
|
o.children.each_slice(2) { |k,v|
|
337
344
|
key = accept(k)
|
338
345
|
val = accept(v)
|
339
346
|
|
340
|
-
if key ==
|
347
|
+
if key == '<<' && k.tag != "tag:yaml.org,2002:str"
|
341
348
|
case v
|
342
349
|
when Nodes::Alias, Nodes::Mapping
|
343
350
|
begin
|
@@ -359,6 +366,12 @@ module Psych
|
|
359
366
|
hash[key] = val
|
360
367
|
end
|
361
368
|
else
|
369
|
+
if !tagged && @symbolize_names
|
370
|
+
key = key.to_sym
|
371
|
+
elsif !@freeze
|
372
|
+
key = deduplicate(key)
|
373
|
+
end
|
374
|
+
|
362
375
|
hash[key] = val
|
363
376
|
end
|
364
377
|
|
@@ -366,12 +379,32 @@ module Psych
|
|
366
379
|
hash
|
367
380
|
end
|
368
381
|
|
382
|
+
if RUBY_VERSION < '2.7'
|
383
|
+
def deduplicate key
|
384
|
+
if key.is_a?(String)
|
385
|
+
# It is important to untaint the string, otherwise it won't
|
386
|
+
# be deduplicated into an fstring, but simply frozen.
|
387
|
+
-(key.untaint)
|
388
|
+
else
|
389
|
+
key
|
390
|
+
end
|
391
|
+
end
|
392
|
+
else
|
393
|
+
def deduplicate key
|
394
|
+
if key.is_a?(String)
|
395
|
+
-key
|
396
|
+
else
|
397
|
+
key
|
398
|
+
end
|
399
|
+
end
|
400
|
+
end
|
401
|
+
|
369
402
|
def merge_key hash, key, val
|
370
403
|
end
|
371
404
|
|
372
405
|
def revive klass, node
|
373
406
|
s = register(node, klass.allocate)
|
374
|
-
init_with(s, revive_hash({}, node), node)
|
407
|
+
init_with(s, revive_hash({}, node, true), node)
|
375
408
|
end
|
376
409
|
|
377
410
|
def init_with o, h, node
|
@@ -8,12 +8,26 @@ module Psych
|
|
8
8
|
|
9
9
|
private
|
10
10
|
|
11
|
-
|
12
|
-
|
11
|
+
# @api private
|
12
|
+
def self.dispatch_cache
|
13
|
+
Hash.new do |hash, klass|
|
14
|
+
hash[klass] = :"visit_#{klass.name.gsub('::', '_')}"
|
15
|
+
end.compare_by_identity
|
16
|
+
end
|
17
|
+
|
18
|
+
if defined?(Ractor)
|
19
|
+
def dispatch
|
20
|
+
@dispatch_cache ||= (Ractor.current[:Psych_Visitors_Visitor] ||= Visitor.dispatch_cache)
|
21
|
+
end
|
22
|
+
else
|
23
|
+
DISPATCH = dispatch_cache
|
24
|
+
def dispatch
|
25
|
+
DISPATCH
|
26
|
+
end
|
13
27
|
end
|
14
28
|
|
15
29
|
def visit target
|
16
|
-
send
|
30
|
+
send dispatch[target.class], target
|
17
31
|
end
|
18
32
|
end
|
19
33
|
end
|
@@ -80,7 +80,7 @@ module Psych
|
|
80
80
|
raise(TypeError, "Can't dump #{target.class}") unless method
|
81
81
|
|
82
82
|
h[klass] = method
|
83
|
-
end
|
83
|
+
end.compare_by_identity
|
84
84
|
end
|
85
85
|
|
86
86
|
def start encoding = Nodes::Stream::UTF8
|
@@ -181,41 +181,11 @@ module Psych
|
|
181
181
|
end
|
182
182
|
|
183
183
|
def visit_Exception o
|
184
|
-
|
185
|
-
|
186
|
-
@emitter.start_mapping nil, tag, false, Nodes::Mapping::BLOCK
|
187
|
-
|
188
|
-
{
|
189
|
-
'message' => private_iv_get(o, 'mesg'),
|
190
|
-
'backtrace' => private_iv_get(o, 'backtrace'),
|
191
|
-
}.each do |k,v|
|
192
|
-
next unless v
|
193
|
-
@emitter.scalar k, nil, nil, true, false, Nodes::Scalar::ANY
|
194
|
-
accept v
|
195
|
-
end
|
196
|
-
|
197
|
-
dump_ivars o
|
198
|
-
|
199
|
-
@emitter.end_mapping
|
184
|
+
dump_exception o, o.message.to_s
|
200
185
|
end
|
201
186
|
|
202
187
|
def visit_NameError o
|
203
|
-
|
204
|
-
|
205
|
-
@emitter.start_mapping nil, tag, false, Nodes::Mapping::BLOCK
|
206
|
-
|
207
|
-
{
|
208
|
-
'message' => o.message.to_s,
|
209
|
-
'backtrace' => private_iv_get(o, 'backtrace'),
|
210
|
-
}.each do |k,v|
|
211
|
-
next unless v
|
212
|
-
@emitter.scalar k, nil, nil, true, false, Nodes::Scalar::ANY
|
213
|
-
accept v
|
214
|
-
end
|
215
|
-
|
216
|
-
dump_ivars o
|
217
|
-
|
218
|
-
@emitter.end_mapping
|
188
|
+
dump_exception o, o.message.to_s
|
219
189
|
end
|
220
190
|
|
221
191
|
def visit_Regexp o
|
@@ -458,15 +428,6 @@ module Psych
|
|
458
428
|
node = @emitter.start_mapping(nil, tag, false, Psych::Nodes::Mapping::BLOCK)
|
459
429
|
register(o, node)
|
460
430
|
|
461
|
-
# Dump the elements
|
462
|
-
accept 'elements'
|
463
|
-
@emitter.start_mapping nil, nil, true, Nodes::Mapping::BLOCK
|
464
|
-
o.each do |k,v|
|
465
|
-
accept k
|
466
|
-
accept v
|
467
|
-
end
|
468
|
-
@emitter.end_mapping
|
469
|
-
|
470
431
|
# Dump the ivars
|
471
432
|
accept 'ivars'
|
472
433
|
@emitter.start_mapping nil, nil, true, Nodes::Mapping::BLOCK
|
@@ -476,6 +437,15 @@ module Psych
|
|
476
437
|
end
|
477
438
|
@emitter.end_mapping
|
478
439
|
|
440
|
+
# Dump the elements
|
441
|
+
accept 'elements'
|
442
|
+
@emitter.start_mapping nil, nil, true, Nodes::Mapping::BLOCK
|
443
|
+
o.each do |k,v|
|
444
|
+
accept k
|
445
|
+
accept v
|
446
|
+
end
|
447
|
+
@emitter.end_mapping
|
448
|
+
|
479
449
|
@emitter.end_mapping
|
480
450
|
else
|
481
451
|
tag = "!ruby/hash:#{o.class}"
|
@@ -492,6 +462,24 @@ module Psych
|
|
492
462
|
def dump_list o
|
493
463
|
end
|
494
464
|
|
465
|
+
def dump_exception o, msg
|
466
|
+
tag = ['!ruby/exception', o.class.name].join ':'
|
467
|
+
|
468
|
+
@emitter.start_mapping nil, tag, false, Nodes::Mapping::BLOCK
|
469
|
+
|
470
|
+
if msg
|
471
|
+
@emitter.scalar 'message', nil, nil, true, false, Nodes::Scalar::ANY
|
472
|
+
accept msg
|
473
|
+
end
|
474
|
+
|
475
|
+
@emitter.scalar 'backtrace', nil, nil, true, false, Nodes::Scalar::ANY
|
476
|
+
accept o.backtrace
|
477
|
+
|
478
|
+
dump_ivars o
|
479
|
+
|
480
|
+
@emitter.end_mapping
|
481
|
+
end
|
482
|
+
|
495
483
|
def format_time time
|
496
484
|
if time.utc?
|
497
485
|
time.strftime("%Y-%m-%d %H:%M:%S.%9N Z")
|