psych-pure 0.1.2 → 0.1.4
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/CHANGELOG.md +14 -1
- data/lib/psych/pure/version.rb +1 -1
- data/lib/psych/pure.rb +524 -122
- metadata +3 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f1767eb97091e21f83527221b9ef4f156d9db40998b9008422b3dc017ff4ada6
|
|
4
|
+
data.tar.gz: b7e1d3b11886a31fda7fd7aed9937e2c26eaafa6d5e242a65bb89c8a02b00be7
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7103d8ceae77bf15b2f21f9462f65fe495bf6e90206749fded264d192beb1caee6ae1a0585703ce914d7268a1e57f498f4cc1b824c21b3c5fe95edfb1dc1e320
|
|
7
|
+
data.tar.gz: 570ba899c74d5873ba243771ae3ff71605b59f81b1567f5f0712314aa2f8efbbdfab659c4e9bde63609ce2ef5ccce46352624c0f458ef6a8ddd31826edcfa9da
|
data/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,18 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.1.4] - 2025-11-10
|
|
10
|
+
|
|
11
|
+
- Fix up comment handling preceding sequence elements.
|
|
12
|
+
- Properly update hashes in mutation methods that are loaded through `Psych::Pure.load`.
|
|
13
|
+
- Properly raise syntax errors when the parser does not finish.
|
|
14
|
+
|
|
15
|
+
## [0.1.3] - 2025-10-24
|
|
16
|
+
|
|
17
|
+
- Fix up roundtripping when using `<<` inside mappings.
|
|
18
|
+
- Fix up roundtripping when using duplicate keys inside mappings.
|
|
19
|
+
- Fix up comment handling when using duplicate keys inside mappings.
|
|
20
|
+
|
|
9
21
|
## [0.1.2] - 2025-03-04
|
|
10
22
|
|
|
11
23
|
- Fix up comment dumping to not drift around objects.
|
|
@@ -25,7 +37,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a
|
|
|
25
37
|
|
|
26
38
|
- 🎉 Initial release. 🎉
|
|
27
39
|
|
|
28
|
-
[unreleased]: https://github.com/kddnewton/psych-pure/compare/v0.1.
|
|
40
|
+
[unreleased]: https://github.com/kddnewton/psych-pure/compare/v0.1.3...HEAD
|
|
41
|
+
[0.1.3]: https://github.com/kddnewton/psych-pure/compare/v0.1.2...v0.1.3
|
|
29
42
|
[0.1.2]: https://github.com/kddnewton/psych-pure/compare/v0.1.1...v0.1.2
|
|
30
43
|
[0.1.1]: https://github.com/kddnewton/psych-pure/compare/v0.1.0...v0.1.1
|
|
31
44
|
[0.1.0]: https://github.com/kddnewton/psych-pure/compare/24de62...v0.1.0
|
data/lib/psych/pure/version.rb
CHANGED
data/lib/psych/pure.rb
CHANGED
|
@@ -7,6 +7,14 @@ require "strscan"
|
|
|
7
7
|
require "stringio"
|
|
8
8
|
|
|
9
9
|
module Psych
|
|
10
|
+
module Nodes
|
|
11
|
+
class Scalar
|
|
12
|
+
# The source of the scalar, as it was found in the input. This may be set
|
|
13
|
+
# in order to be reused when dumping the object.
|
|
14
|
+
attr_accessor :source
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
10
18
|
# A YAML parser written in Ruby.
|
|
11
19
|
module Pure
|
|
12
20
|
# An internal exception is an exception that should not have occurred. It is
|
|
@@ -17,7 +25,7 @@ module Psych
|
|
|
17
25
|
end
|
|
18
26
|
end
|
|
19
27
|
|
|
20
|
-
# A source
|
|
28
|
+
# A source wraps the input string and provides methods to access line and
|
|
21
29
|
# column information from a byte offset.
|
|
22
30
|
class Source
|
|
23
31
|
def initialize(string)
|
|
@@ -27,7 +35,13 @@ module Psych
|
|
|
27
35
|
offset = 0
|
|
28
36
|
string.each_line do |line|
|
|
29
37
|
@line_offsets << offset
|
|
30
|
-
@trimmable_lines <<
|
|
38
|
+
@trimmable_lines <<
|
|
39
|
+
case line
|
|
40
|
+
when /\A *#.*\n\z/ then :comment
|
|
41
|
+
when /\A *\n\z/ then :blank
|
|
42
|
+
else false
|
|
43
|
+
end
|
|
44
|
+
|
|
31
45
|
offset += line.bytesize
|
|
32
46
|
end
|
|
33
47
|
|
|
@@ -43,6 +57,14 @@ module Psych
|
|
|
43
57
|
offset
|
|
44
58
|
end
|
|
45
59
|
|
|
60
|
+
def trim_comments(offset)
|
|
61
|
+
while (l = line(offset)) != 0 && (offset == @line_offsets[l]) && @trimmable_lines[l - 1] == :comment
|
|
62
|
+
offset = @line_offsets[l - 1]
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
offset
|
|
66
|
+
end
|
|
67
|
+
|
|
46
68
|
def line(offset)
|
|
47
69
|
index = @line_offsets.bsearch_index { |line_offset| line_offset > offset }
|
|
48
70
|
return @line_offsets.size - 1 if index.nil?
|
|
@@ -64,6 +86,10 @@ module Psych
|
|
|
64
86
|
@pos_end = pos_end
|
|
65
87
|
end
|
|
66
88
|
|
|
89
|
+
def range
|
|
90
|
+
@pos_start...@pos_end
|
|
91
|
+
end
|
|
92
|
+
|
|
67
93
|
def start_line
|
|
68
94
|
@source.line(@pos_start)
|
|
69
95
|
end
|
|
@@ -89,6 +115,11 @@ module Psych
|
|
|
89
115
|
Location.new(@source, @pos_start, @source.trim(@pos_end))
|
|
90
116
|
end
|
|
91
117
|
|
|
118
|
+
# Trim trailing comments from this location.
|
|
119
|
+
def trim_comments
|
|
120
|
+
Location.new(@source, @pos_start, @source.trim_comments(@pos_end))
|
|
121
|
+
end
|
|
122
|
+
|
|
92
123
|
def to_a
|
|
93
124
|
[start_line, start_column, end_line, end_column]
|
|
94
125
|
end
|
|
@@ -145,6 +176,20 @@ module Psych
|
|
|
145
176
|
def trailing_comment(comment)
|
|
146
177
|
@trailing << comment
|
|
147
178
|
end
|
|
179
|
+
|
|
180
|
+
# Execute the given block without the leading comments being visible. This
|
|
181
|
+
# is used when a node has already handled its child nodes' leading
|
|
182
|
+
# comments, so they should not be processed again.
|
|
183
|
+
def without_leading
|
|
184
|
+
leading = @leading
|
|
185
|
+
|
|
186
|
+
begin
|
|
187
|
+
@leading = []
|
|
188
|
+
yield
|
|
189
|
+
ensure
|
|
190
|
+
@leading = leading
|
|
191
|
+
end
|
|
192
|
+
end
|
|
148
193
|
end
|
|
149
194
|
|
|
150
195
|
# Wraps a Ruby object with its node from the source input.
|
|
@@ -161,32 +206,274 @@ module Psych
|
|
|
161
206
|
@psych_node = psych_node
|
|
162
207
|
@dirty = dirty
|
|
163
208
|
end
|
|
209
|
+
|
|
210
|
+
def replace(psych_node)
|
|
211
|
+
@psych_node = psych_node
|
|
212
|
+
@dirty = true
|
|
213
|
+
end
|
|
164
214
|
end
|
|
165
215
|
|
|
166
216
|
# Wraps a Ruby hash with its node from the source input.
|
|
167
217
|
class LoadedHash < SimpleDelegator
|
|
218
|
+
class PsychKey
|
|
219
|
+
attr_reader :key_node, :value_node
|
|
220
|
+
|
|
221
|
+
def initialize(key_node, value_node)
|
|
222
|
+
@key_node = key_node
|
|
223
|
+
@value_node = value_node
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
def replace_key(key_node)
|
|
227
|
+
@key_node = key_node
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
def replace_value(value_node)
|
|
231
|
+
@value_node = value_node
|
|
232
|
+
end
|
|
233
|
+
end
|
|
234
|
+
|
|
168
235
|
# The node associated with the hash.
|
|
169
236
|
attr_reader :psych_node
|
|
170
237
|
|
|
171
|
-
# The
|
|
172
|
-
attr_reader :
|
|
238
|
+
# The list of key/value pairs within the hash.
|
|
239
|
+
attr_reader :psych_keys
|
|
173
240
|
|
|
174
|
-
def initialize(object, psych_node
|
|
241
|
+
def initialize(object, psych_node)
|
|
175
242
|
super(object)
|
|
176
243
|
@psych_node = psych_node
|
|
177
|
-
@
|
|
244
|
+
@psych_keys = []
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
def set!(key_node, value_node)
|
|
248
|
+
@psych_keys << PsychKey.new(key_node, value_node)
|
|
249
|
+
__getobj__[key_node.__getobj__] = value_node
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
def join!(key_node, value_node)
|
|
253
|
+
@psych_keys << PsychKey.new(key_node, value_node)
|
|
254
|
+
merge!(value_node)
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
def psych_assocs
|
|
258
|
+
@psych_keys.map { |psych_key| [psych_key.key_node, psych_key.value_node] }
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
# Override Hash mutation methods to keep @psych_keys in sync.
|
|
262
|
+
|
|
263
|
+
def initialize_clone(obj, freeze: nil)
|
|
264
|
+
super
|
|
265
|
+
@psych_keys = obj.psych_keys.map(&:dup)
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
def initialize_dup(obj)
|
|
269
|
+
super
|
|
270
|
+
@psych_keys = obj.psych_keys.map(&:dup)
|
|
178
271
|
end
|
|
179
272
|
|
|
180
273
|
def []=(key, value)
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
274
|
+
super(key, value)
|
|
275
|
+
|
|
276
|
+
if (psych_key = @psych_keys.reverse_each.find { |psych_key| psych_compare?(psych_key.key_node, key) })
|
|
277
|
+
psych_key.replace_value(value)
|
|
278
|
+
else
|
|
279
|
+
@psych_keys << PsychKey.new(key, value)
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
value
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
alias store []=
|
|
286
|
+
|
|
287
|
+
def clear
|
|
288
|
+
super
|
|
289
|
+
@psych_keys.clear
|
|
290
|
+
|
|
291
|
+
self
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
def compact!
|
|
295
|
+
mutated = false
|
|
296
|
+
@psych_keys.each do |psych_key|
|
|
297
|
+
if psych_unwrap(psych_key.value_node).nil?
|
|
298
|
+
mutated = true
|
|
299
|
+
delete(psych_unwrap(psych_key.key_node))
|
|
186
300
|
end
|
|
187
301
|
end
|
|
188
302
|
|
|
189
|
-
|
|
303
|
+
self if mutated
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
def compact
|
|
307
|
+
dup.compact!
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
def delete(key)
|
|
311
|
+
result = super
|
|
312
|
+
psych_delete(key)
|
|
313
|
+
|
|
314
|
+
result
|
|
315
|
+
end
|
|
316
|
+
|
|
317
|
+
def delete_if(&block)
|
|
318
|
+
super do |key, value|
|
|
319
|
+
yield(key, psych_unwrap(value)).tap do |result|
|
|
320
|
+
psych_delete(key) if result
|
|
321
|
+
end
|
|
322
|
+
end
|
|
323
|
+
|
|
324
|
+
self
|
|
325
|
+
end
|
|
326
|
+
|
|
327
|
+
def except(*keys)
|
|
328
|
+
dup.delete_if { |key, _| keys.include?(key) }
|
|
329
|
+
end
|
|
330
|
+
|
|
331
|
+
def filter!(&block)
|
|
332
|
+
mutated = false
|
|
333
|
+
super do |key, value|
|
|
334
|
+
yield(key, psych_unwrap(value)).tap do |result|
|
|
335
|
+
unless result
|
|
336
|
+
psych_delete(key)
|
|
337
|
+
mutated = true
|
|
338
|
+
end
|
|
339
|
+
end
|
|
340
|
+
end
|
|
341
|
+
|
|
342
|
+
self if mutated
|
|
343
|
+
end
|
|
344
|
+
|
|
345
|
+
def filter(&block)
|
|
346
|
+
dup.filter!(&block)
|
|
347
|
+
end
|
|
348
|
+
|
|
349
|
+
def invert
|
|
350
|
+
result = LoadedHash.new({}, @psych_node)
|
|
351
|
+
each { |key, value| result[psych_unwrap(value)] = key }
|
|
352
|
+
result
|
|
353
|
+
end
|
|
354
|
+
|
|
355
|
+
def keep_if(&block)
|
|
356
|
+
super do |key, value|
|
|
357
|
+
yield(key, psych_unwrap(value)).tap do |result|
|
|
358
|
+
psych_delete(key) unless result
|
|
359
|
+
end
|
|
360
|
+
end
|
|
361
|
+
|
|
362
|
+
self
|
|
363
|
+
end
|
|
364
|
+
|
|
365
|
+
alias select! keep_if
|
|
366
|
+
|
|
367
|
+
def merge!(*others)
|
|
368
|
+
super
|
|
369
|
+
others.each do |other|
|
|
370
|
+
other.each do |key, value|
|
|
371
|
+
psych_delete(key)
|
|
372
|
+
@psych_keys << PsychKey.new(key, value)
|
|
373
|
+
end
|
|
374
|
+
end
|
|
375
|
+
|
|
376
|
+
self
|
|
377
|
+
end
|
|
378
|
+
|
|
379
|
+
alias update merge!
|
|
380
|
+
|
|
381
|
+
def merge(*others)
|
|
382
|
+
dup.merge!(*others)
|
|
383
|
+
end
|
|
384
|
+
|
|
385
|
+
def reject!(&block)
|
|
386
|
+
mutated = false
|
|
387
|
+
super do |key, value|
|
|
388
|
+
yield(key, psych_unwrap(value)).tap do |result|
|
|
389
|
+
if result
|
|
390
|
+
psych_delete(key)
|
|
391
|
+
mutated = true
|
|
392
|
+
end
|
|
393
|
+
end
|
|
394
|
+
end
|
|
395
|
+
|
|
396
|
+
self if mutated
|
|
397
|
+
end
|
|
398
|
+
|
|
399
|
+
def reject(&block)
|
|
400
|
+
dup.reject!(&block)
|
|
401
|
+
end
|
|
402
|
+
|
|
403
|
+
def replace(other)
|
|
404
|
+
super
|
|
405
|
+
|
|
406
|
+
@psych_keys.clear
|
|
407
|
+
other.each { |key, value| @psych_keys << PsychKey.new(key, value) }
|
|
408
|
+
|
|
409
|
+
self
|
|
410
|
+
end
|
|
411
|
+
|
|
412
|
+
def shift
|
|
413
|
+
unless empty?
|
|
414
|
+
key, value = super
|
|
415
|
+
psych_delete(key)
|
|
416
|
+
|
|
417
|
+
[key, value]
|
|
418
|
+
end
|
|
419
|
+
end
|
|
420
|
+
|
|
421
|
+
def slice(*keys)
|
|
422
|
+
dup.select! { |key, _| keys.include?(key) }
|
|
423
|
+
end
|
|
424
|
+
|
|
425
|
+
def transform_keys!(&block)
|
|
426
|
+
super do |key|
|
|
427
|
+
yield(key).tap do |result|
|
|
428
|
+
@psych_keys
|
|
429
|
+
.reverse_each
|
|
430
|
+
.find { |psych_key| psych_compare?(psych_key.key_node, key) }
|
|
431
|
+
&.replace_key(result)
|
|
432
|
+
end
|
|
433
|
+
end
|
|
434
|
+
|
|
435
|
+
self
|
|
436
|
+
end
|
|
437
|
+
|
|
438
|
+
def transform_keys(&block)
|
|
439
|
+
dup.transform_keys!(&block)
|
|
440
|
+
end
|
|
441
|
+
|
|
442
|
+
def transform_values!(&block)
|
|
443
|
+
super do |value|
|
|
444
|
+
yield(psych_unwrap(value)).tap do |result|
|
|
445
|
+
@psych_keys
|
|
446
|
+
.reverse_each
|
|
447
|
+
.find { |psych_key| psych_compare?(psych_key.value_node, value) }
|
|
448
|
+
&.replace_value(result)
|
|
449
|
+
end
|
|
450
|
+
end
|
|
451
|
+
end
|
|
452
|
+
|
|
453
|
+
def transform_values(&block)
|
|
454
|
+
dup.transform_values!(&block)
|
|
455
|
+
end
|
|
456
|
+
|
|
457
|
+
private
|
|
458
|
+
|
|
459
|
+
def psych_compare?(psych_node, value)
|
|
460
|
+
if compare_by_identity?
|
|
461
|
+
psych_unwrap(psych_node).equal?(value)
|
|
462
|
+
else
|
|
463
|
+
psych_unwrap(psych_node).eql?(value)
|
|
464
|
+
end
|
|
465
|
+
end
|
|
466
|
+
|
|
467
|
+
def psych_delete(key)
|
|
468
|
+
@psych_keys.reject! { |psych_key| psych_compare?(psych_key.key_node, key) }
|
|
469
|
+
end
|
|
470
|
+
|
|
471
|
+
def psych_unwrap(node)
|
|
472
|
+
if node.is_a?(LoadedHash) || node.is_a?(LoadedObject)
|
|
473
|
+
node.__getobj__
|
|
474
|
+
else
|
|
475
|
+
node
|
|
476
|
+
end
|
|
190
477
|
end
|
|
191
478
|
end
|
|
192
479
|
|
|
@@ -349,8 +636,6 @@ module Psych
|
|
|
349
636
|
def initialize(ss, class_loader, symbolize_names: false, freeze: false, comments: false)
|
|
350
637
|
super(ss, class_loader, symbolize_names: symbolize_names, freeze: freeze)
|
|
351
638
|
@comments = comments
|
|
352
|
-
@nodeless_objs = {}.compare_by_identity
|
|
353
|
-
@nodeless_keys = {}.compare_by_identity
|
|
354
639
|
end
|
|
355
640
|
|
|
356
641
|
def accept(node)
|
|
@@ -360,31 +645,66 @@ module Psych
|
|
|
360
645
|
case result
|
|
361
646
|
when LoadedObject, LoadedHash
|
|
362
647
|
# skip
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
648
|
+
else
|
|
649
|
+
result = LoadedObject.new(result, node)
|
|
650
|
+
end
|
|
651
|
+
end
|
|
652
|
+
|
|
653
|
+
result
|
|
654
|
+
end
|
|
655
|
+
|
|
656
|
+
private
|
|
657
|
+
|
|
658
|
+
def revive_hash(hash, node, tagged = false)
|
|
659
|
+
return super unless @comments
|
|
660
|
+
|
|
661
|
+
revived = LoadedHash.new(hash, node)
|
|
662
|
+
node.children.each_slice(2) do |key_node, value_node|
|
|
663
|
+
key = accept(key_node)
|
|
664
|
+
value = accept(value_node)
|
|
665
|
+
|
|
666
|
+
if key == "<<" && key_node.tag != "tag:yaml.org,2002:str"
|
|
667
|
+
case value_node
|
|
668
|
+
when Nodes::Alias, Nodes::Mapping
|
|
669
|
+
begin
|
|
670
|
+
# h1:
|
|
671
|
+
# <<: *h2
|
|
672
|
+
# <<: { k: v }
|
|
673
|
+
revived.join!(key, value)
|
|
674
|
+
rescue TypeError
|
|
675
|
+
# a: &a [1, 2, 3]
|
|
676
|
+
# h: { <<: *a }
|
|
677
|
+
revived.set!(key, value)
|
|
678
|
+
end
|
|
679
|
+
when Nodes::Sequence
|
|
680
|
+
# h1:
|
|
681
|
+
# <<: [*h2, *h3]
|
|
682
|
+
begin
|
|
683
|
+
temporary = {}
|
|
684
|
+
value.reverse_each { |value| temporary.merge!(value) }
|
|
685
|
+
rescue TypeError
|
|
686
|
+
revived.set!(key, value)
|
|
687
|
+
else
|
|
688
|
+
value_node.children.zip(value).reverse_each do |(child_value_node, child_value)|
|
|
689
|
+
revived.join!(key, child_value)
|
|
374
690
|
end
|
|
375
691
|
end
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
692
|
+
else
|
|
693
|
+
# k: v
|
|
694
|
+
revived.set!(key, value)
|
|
379
695
|
end
|
|
380
|
-
|
|
381
|
-
result = LoadedHash.new(@nodeless_objs.fetch(result), node, @nodeless_keys.fetch(result))
|
|
382
696
|
else
|
|
383
|
-
|
|
697
|
+
if !tagged && @symbolize_names && key.is_a?(String)
|
|
698
|
+
key = key.to_sym
|
|
699
|
+
elsif !@freeze
|
|
700
|
+
key = deduplicate(key)
|
|
701
|
+
end
|
|
702
|
+
|
|
703
|
+
revived.set!(key, value)
|
|
384
704
|
end
|
|
385
705
|
end
|
|
386
706
|
|
|
387
|
-
|
|
707
|
+
revived
|
|
388
708
|
end
|
|
389
709
|
end
|
|
390
710
|
|
|
@@ -493,11 +813,12 @@ module Psych
|
|
|
493
813
|
# A scalar event represents a single value in the YAML document. It can be
|
|
494
814
|
# many different types.
|
|
495
815
|
class Scalar
|
|
496
|
-
attr_reader :location, :value, :style
|
|
816
|
+
attr_reader :location, :source, :value, :style
|
|
497
817
|
attr_accessor :anchor, :tag
|
|
498
818
|
|
|
499
|
-
def initialize(location, value, style)
|
|
819
|
+
def initialize(location, source, value, style)
|
|
500
820
|
@location = location
|
|
821
|
+
@source = source
|
|
501
822
|
@value = value
|
|
502
823
|
@anchor = nil
|
|
503
824
|
@tag = nil
|
|
@@ -506,14 +827,19 @@ module Psych
|
|
|
506
827
|
|
|
507
828
|
def accept(handler)
|
|
508
829
|
handler.event_location(*@location.trim)
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
830
|
+
|
|
831
|
+
event =
|
|
832
|
+
handler.scalar(
|
|
833
|
+
@value,
|
|
834
|
+
@anchor,
|
|
835
|
+
@tag,
|
|
836
|
+
(!@tag || @tag == "!") && (@style == Nodes::Scalar::PLAIN),
|
|
837
|
+
(!@tag || @tag == "!") && (@style != Nodes::Scalar::PLAIN),
|
|
838
|
+
@style
|
|
839
|
+
)
|
|
840
|
+
|
|
841
|
+
event.source = source if event.is_a?(Nodes::Scalar)
|
|
842
|
+
event
|
|
517
843
|
end
|
|
518
844
|
end
|
|
519
845
|
|
|
@@ -650,9 +976,7 @@ module Psych
|
|
|
650
976
|
@source = Source.new(yaml)
|
|
651
977
|
@comments = {} if comments
|
|
652
978
|
|
|
653
|
-
|
|
654
|
-
raise_syntax_error("Parser finished before end of input") unless @scanner.eos?
|
|
655
|
-
|
|
979
|
+
parse_l_yaml_stream
|
|
656
980
|
@comments = nil if comments
|
|
657
981
|
true
|
|
658
982
|
end
|
|
@@ -1149,11 +1473,8 @@ module Psych
|
|
|
1149
1473
|
# b-comment
|
|
1150
1474
|
def parse_s_b_comment
|
|
1151
1475
|
try do
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
parse_c_nb_comment_text(true)
|
|
1155
|
-
true
|
|
1156
|
-
end
|
|
1476
|
+
if parse_s_separate_in_line
|
|
1477
|
+
parse_c_nb_comment_text(true)
|
|
1157
1478
|
end
|
|
1158
1479
|
|
|
1159
1480
|
parse_b_comment
|
|
@@ -1453,7 +1774,7 @@ module Psych
|
|
|
1453
1774
|
# e-scalar ::=
|
|
1454
1775
|
# <empty>
|
|
1455
1776
|
def parse_e_scalar
|
|
1456
|
-
events_push_flush_properties(Scalar.new(Location.point(@source, @scanner.pos), "", Nodes::Scalar::PLAIN))
|
|
1777
|
+
events_push_flush_properties(Scalar.new(Location.point(@source, @scanner.pos), "", "", Nodes::Scalar::PLAIN))
|
|
1457
1778
|
true
|
|
1458
1779
|
end
|
|
1459
1780
|
|
|
@@ -1557,7 +1878,7 @@ module Psych
|
|
|
1557
1878
|
end
|
|
1558
1879
|
end
|
|
1559
1880
|
|
|
1560
|
-
events_push_flush_properties(Scalar.new(Location.new(@source, pos_start, @scanner.pos), value, Nodes::Scalar::DOUBLE_QUOTED))
|
|
1881
|
+
events_push_flush_properties(Scalar.new(Location.new(@source, pos_start, @scanner.pos), from(pos_start), value, Nodes::Scalar::DOUBLE_QUOTED))
|
|
1561
1882
|
true
|
|
1562
1883
|
end
|
|
1563
1884
|
end
|
|
@@ -1701,7 +2022,7 @@ module Psych
|
|
|
1701
2022
|
value.gsub!(/(?:[\ \t]*\r?\n[\ \t]*)/, "\n")
|
|
1702
2023
|
value.gsub!(/\n(\n*)/) { $1.empty? ? " " : $1 }
|
|
1703
2024
|
value.gsub!("''", "'")
|
|
1704
|
-
events_push_flush_properties(Scalar.new(Location.new(@source, pos_start, @scanner.pos), value, Nodes::Scalar::SINGLE_QUOTED))
|
|
2025
|
+
events_push_flush_properties(Scalar.new(Location.new(@source, pos_start, @scanner.pos), from(pos_start), value, Nodes::Scalar::SINGLE_QUOTED))
|
|
1705
2026
|
true
|
|
1706
2027
|
end
|
|
1707
2028
|
end
|
|
@@ -1952,12 +2273,9 @@ module Psych
|
|
|
1952
2273
|
if parse_ns_flow_seq_entry(n, c)
|
|
1953
2274
|
parse_s_separate(n, c)
|
|
1954
2275
|
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
parse_ns_s_flow_seq_entries(n, c)
|
|
1959
|
-
true
|
|
1960
|
-
end
|
|
2276
|
+
if match(",")
|
|
2277
|
+
parse_s_separate(n, c)
|
|
2278
|
+
parse_ns_s_flow_seq_entries(n, c)
|
|
1961
2279
|
end
|
|
1962
2280
|
|
|
1963
2281
|
true
|
|
@@ -2241,10 +2559,13 @@ module Psych
|
|
|
2241
2559
|
end
|
|
2242
2560
|
|
|
2243
2561
|
if result
|
|
2244
|
-
|
|
2562
|
+
source = from(pos_start)
|
|
2563
|
+
|
|
2564
|
+
value = source.dup
|
|
2245
2565
|
value.gsub!(/(?:[\ \t]*\r?\n[\ \t]*)/, "\n")
|
|
2246
2566
|
value.gsub!(/\n(\n*)/) { $1.empty? ? " " : $1 }
|
|
2247
|
-
|
|
2567
|
+
|
|
2568
|
+
events_push_flush_properties(Scalar.new(Location.new(@source, pos_start, @scanner.pos), source, value, Nodes::Scalar::PLAIN))
|
|
2248
2569
|
end
|
|
2249
2570
|
|
|
2250
2571
|
result
|
|
@@ -2470,8 +2791,7 @@ module Psych
|
|
|
2470
2791
|
parse_l_literal_content(n + m, t)
|
|
2471
2792
|
} then
|
|
2472
2793
|
@in_scalar = false
|
|
2473
|
-
|
|
2474
|
-
value = lines.map { |line| "#{line}\n" }.join
|
|
2794
|
+
value = events_cache_pop.map { |line| "#{line}\n" }.join
|
|
2475
2795
|
|
|
2476
2796
|
case t
|
|
2477
2797
|
when :clip
|
|
@@ -2484,7 +2804,8 @@ module Psych
|
|
|
2484
2804
|
raise InternalException, t.inspect
|
|
2485
2805
|
end
|
|
2486
2806
|
|
|
2487
|
-
|
|
2807
|
+
location = Location.new(@source, pos_start, @scanner.pos).trim_comments
|
|
2808
|
+
events_push_flush_properties(Scalar.new(location, @scanner.string.byteslice(location.range).chomp, value, Nodes::Scalar::LITERAL))
|
|
2488
2809
|
true
|
|
2489
2810
|
else
|
|
2490
2811
|
@in_scalar = false
|
|
@@ -2582,7 +2903,8 @@ module Psych
|
|
|
2582
2903
|
raise InternalException, t.inspect
|
|
2583
2904
|
end
|
|
2584
2905
|
|
|
2585
|
-
|
|
2906
|
+
location = Location.new(@source, pos_start, @scanner.pos).trim_comments
|
|
2907
|
+
events_push_flush_properties(Scalar.new(location, @scanner.string.byteslice(location.range).chomp, value, Nodes::Scalar::FOLDED))
|
|
2586
2908
|
true
|
|
2587
2909
|
else
|
|
2588
2910
|
@in_scalar = false
|
|
@@ -3079,34 +3401,32 @@ module Psych
|
|
|
3079
3401
|
def parse_l_yaml_stream
|
|
3080
3402
|
events_push_flush_properties(StreamStart.new(Location.point(@source, @scanner.pos)))
|
|
3081
3403
|
|
|
3082
|
-
|
|
3083
|
-
|
|
3084
|
-
|
|
3085
|
-
|
|
3086
|
-
|
|
3404
|
+
star { parse_l_document_prefix }
|
|
3405
|
+
@document_start_event = DocumentStart.new(Location.point(@source, @scanner.pos))
|
|
3406
|
+
@tag_directives = @document_start_event.tag_directives
|
|
3407
|
+
@document_end_event = nil
|
|
3408
|
+
parse_l_any_document
|
|
3087
3409
|
|
|
3088
|
-
|
|
3089
|
-
|
|
3090
|
-
|
|
3091
|
-
|
|
3092
|
-
|
|
3093
|
-
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
|
|
3097
|
-
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
true
|
|
3101
|
-
end
|
|
3102
|
-
end
|
|
3410
|
+
star do
|
|
3411
|
+
try do
|
|
3412
|
+
if parse_l_document_suffix
|
|
3413
|
+
star { parse_l_document_prefix }
|
|
3414
|
+
parse_l_any_document
|
|
3415
|
+
true
|
|
3416
|
+
end
|
|
3417
|
+
end ||
|
|
3418
|
+
try do
|
|
3419
|
+
if parse_l_document_prefix
|
|
3420
|
+
parse_l_explicit_document
|
|
3421
|
+
true
|
|
3103
3422
|
end
|
|
3104
3423
|
end
|
|
3105
|
-
} then
|
|
3106
|
-
document_end_event_flush
|
|
3107
|
-
events_push_flush_properties(StreamEnd.new(Location.point(@source, @scanner.pos)))
|
|
3108
|
-
true
|
|
3109
3424
|
end
|
|
3425
|
+
|
|
3426
|
+
raise_syntax_error("Parser finished before end of input") unless @scanner.eos?
|
|
3427
|
+
document_end_event_flush
|
|
3428
|
+
events_push_flush_properties(StreamEnd.new(Location.point(@source, @scanner.pos)))
|
|
3429
|
+
true
|
|
3110
3430
|
end
|
|
3111
3431
|
|
|
3112
3432
|
# ------------------------------------------------------------------------
|
|
@@ -3182,6 +3502,9 @@ module Psych
|
|
|
3182
3502
|
|
|
3183
3503
|
# Represents the nil value.
|
|
3184
3504
|
class NilNode < Node
|
|
3505
|
+
def accept(visitor)
|
|
3506
|
+
raise "Visiting NilNode is not supported"
|
|
3507
|
+
end
|
|
3185
3508
|
end
|
|
3186
3509
|
|
|
3187
3510
|
# Represents a generic object that is not matched by any of the other node
|
|
@@ -3220,8 +3543,14 @@ module Psych
|
|
|
3220
3543
|
|
|
3221
3544
|
# Represents a string object.
|
|
3222
3545
|
class StringNode < Node
|
|
3546
|
+
# The explicit tag associated with the object.
|
|
3223
3547
|
attr_accessor :tag
|
|
3224
3548
|
|
|
3549
|
+
# Whether or not this object was modified after being loaded. In this
|
|
3550
|
+
# case we cannot rely on the source formatting, and need to instead
|
|
3551
|
+
# format the value ourselves.
|
|
3552
|
+
attr_accessor :dirty
|
|
3553
|
+
|
|
3225
3554
|
def accept(visitor)
|
|
3226
3555
|
visitor.visit_string(self)
|
|
3227
3556
|
end
|
|
@@ -3264,13 +3593,17 @@ module Psych
|
|
|
3264
3593
|
# Visit an ObjectNode.
|
|
3265
3594
|
def visit_object(node)
|
|
3266
3595
|
with_comments(node) do |value|
|
|
3267
|
-
if (tag = node.tag)
|
|
3268
|
-
@q.text("#{tag} ")
|
|
3269
|
-
end
|
|
3270
|
-
|
|
3271
3596
|
if !node.dirty && (psych_node = node.psych_node)
|
|
3272
|
-
|
|
3597
|
+
if (tag = node.tag)
|
|
3598
|
+
@q.text("#{tag} ")
|
|
3599
|
+
end
|
|
3600
|
+
|
|
3601
|
+
@q.text(psych_node.source || psych_node.value)
|
|
3273
3602
|
else
|
|
3603
|
+
if (tag = node.tag) && tag != "tag:yaml.org,2002:binary"
|
|
3604
|
+
@q.text("#{tag} ")
|
|
3605
|
+
end
|
|
3606
|
+
|
|
3274
3607
|
@q.text(dump_object(value))
|
|
3275
3608
|
end
|
|
3276
3609
|
end
|
|
@@ -3293,11 +3626,19 @@ module Psych
|
|
|
3293
3626
|
# Visit a StringNode.
|
|
3294
3627
|
def visit_string(node)
|
|
3295
3628
|
with_comments(node) do |value|
|
|
3296
|
-
if (
|
|
3297
|
-
|
|
3298
|
-
|
|
3629
|
+
if !node.dirty && (psych_node = node.psych_node)
|
|
3630
|
+
if (tag = node.tag)
|
|
3631
|
+
@q.text("#{tag} ")
|
|
3632
|
+
end
|
|
3299
3633
|
|
|
3300
|
-
|
|
3634
|
+
@q.text(psych_node.source || psych_node.value)
|
|
3635
|
+
else
|
|
3636
|
+
if (tag = node.tag) && tag != "tag:yaml.org,2002:binary"
|
|
3637
|
+
@q.text("#{tag} ")
|
|
3638
|
+
end
|
|
3639
|
+
|
|
3640
|
+
@q.text(dump_object(value))
|
|
3641
|
+
end
|
|
3301
3642
|
end
|
|
3302
3643
|
end
|
|
3303
3644
|
|
|
@@ -3334,12 +3675,38 @@ module Psych
|
|
|
3334
3675
|
@q.breakable
|
|
3335
3676
|
end
|
|
3336
3677
|
|
|
3337
|
-
|
|
3678
|
+
current_line = nil
|
|
3679
|
+
contents.each_with_index do |element, index|
|
|
3680
|
+
psych_node = element.psych_node
|
|
3681
|
+
leading = psych_node&.comments&.leading
|
|
3682
|
+
|
|
3683
|
+
if index > 0
|
|
3684
|
+
@q.breakable
|
|
3685
|
+
|
|
3686
|
+
if current_line && psych_node
|
|
3687
|
+
start_line = (leading&.first || psych_node).start_line
|
|
3688
|
+
@q.breakable if start_line - current_line >= 2
|
|
3689
|
+
end
|
|
3690
|
+
end
|
|
3691
|
+
|
|
3692
|
+
current_line = psych_node&.end_line
|
|
3693
|
+
visit_leading_comments(leading) if leading&.any?
|
|
3694
|
+
|
|
3695
|
+
if psych_node && (trailing = psych_node.comments.trailing).any?
|
|
3696
|
+
current_line = trailing.last.end_line
|
|
3697
|
+
end
|
|
3698
|
+
|
|
3338
3699
|
@q.text("-")
|
|
3339
3700
|
next if element.is_a?(NilNode)
|
|
3340
3701
|
|
|
3341
3702
|
@q.text(" ")
|
|
3342
|
-
@q.nest(2)
|
|
3703
|
+
@q.nest(2) do
|
|
3704
|
+
if psych_node
|
|
3705
|
+
psych_node.comments.without_leading { visit(element) }
|
|
3706
|
+
else
|
|
3707
|
+
visit(element)
|
|
3708
|
+
end
|
|
3709
|
+
end
|
|
3343
3710
|
end
|
|
3344
3711
|
|
|
3345
3712
|
@q.current_group.break
|
|
@@ -3447,9 +3814,26 @@ module Psych
|
|
|
3447
3814
|
@q.breakable
|
|
3448
3815
|
end
|
|
3449
3816
|
|
|
3817
|
+
current_line = nil
|
|
3450
3818
|
((0...children.length) % 2).each do |index|
|
|
3451
|
-
|
|
3452
|
-
|
|
3819
|
+
key = children[index]
|
|
3820
|
+
value = children[index + 1]
|
|
3821
|
+
|
|
3822
|
+
if index > 0
|
|
3823
|
+
@q.breakable
|
|
3824
|
+
|
|
3825
|
+
if current_line && (psych_node = key.psych_node)
|
|
3826
|
+
start_line = psych_node.start_line
|
|
3827
|
+
if (leading = key.psych_node.comments.leading).any?
|
|
3828
|
+
start_line = leading.first.start_line
|
|
3829
|
+
end
|
|
3830
|
+
|
|
3831
|
+
@q.breakable if start_line - current_line >= 2
|
|
3832
|
+
end
|
|
3833
|
+
end
|
|
3834
|
+
|
|
3835
|
+
current_line = (psych_node = value.psych_node) ? psych_node.end_line : nil
|
|
3836
|
+
visit_hash_key_value(key, value)
|
|
3453
3837
|
end
|
|
3454
3838
|
|
|
3455
3839
|
@q.current_group.break
|
|
@@ -3478,23 +3862,29 @@ module Psych
|
|
|
3478
3862
|
end
|
|
3479
3863
|
end
|
|
3480
3864
|
|
|
3865
|
+
# Visit the leading comments for a node, printing them out with proper
|
|
3866
|
+
# line breaks.
|
|
3867
|
+
def visit_leading_comments(comments)
|
|
3868
|
+
line = nil
|
|
3869
|
+
|
|
3870
|
+
comments.each do |comment|
|
|
3871
|
+
while line && line < comment.start_line
|
|
3872
|
+
@q.breakable
|
|
3873
|
+
line += 1
|
|
3874
|
+
end
|
|
3875
|
+
|
|
3876
|
+
@q.text(comment.value)
|
|
3877
|
+
line = comment.end_line
|
|
3878
|
+
end
|
|
3879
|
+
|
|
3880
|
+
@q.breakable
|
|
3881
|
+
end
|
|
3882
|
+
|
|
3481
3883
|
# Print out the leading and trailing comments of a node, as well as
|
|
3482
3884
|
# yielding the value of the node to the block.
|
|
3483
3885
|
def with_comments(node)
|
|
3484
3886
|
if (comments = node.psych_node&.comments) && (leading = comments.leading).any?
|
|
3485
|
-
|
|
3486
|
-
|
|
3487
|
-
leading.each do |comment|
|
|
3488
|
-
while line && line < comment.start_line
|
|
3489
|
-
@q.breakable
|
|
3490
|
-
line += 1
|
|
3491
|
-
end
|
|
3492
|
-
|
|
3493
|
-
@q.text(comment.value)
|
|
3494
|
-
line = comment.end_line
|
|
3495
|
-
end
|
|
3496
|
-
|
|
3497
|
-
@q.breakable
|
|
3887
|
+
visit_leading_comments(leading)
|
|
3498
3888
|
end
|
|
3499
3889
|
|
|
3500
3890
|
yield node.value
|
|
@@ -3576,6 +3966,7 @@ module Psych
|
|
|
3576
3966
|
# Very rare circumstance here that there are leading comments attached
|
|
3577
3967
|
# to the root object of a document that occur before the --- marker. In
|
|
3578
3968
|
# this case we want to output them first here, then dump the object.
|
|
3969
|
+
reload_comments = nil
|
|
3579
3970
|
if (object.is_a?(LoadedObject) || object.is_a?(LoadedHash)) && (psych_node = object.psych_node).comments? && (leading = psych_node.comments.leading).any?
|
|
3580
3971
|
leading = [*leading]
|
|
3581
3972
|
line = psych_node.start_line - 1
|
|
@@ -3598,6 +3989,8 @@ module Psych
|
|
|
3598
3989
|
|
|
3599
3990
|
line = comment.start_line
|
|
3600
3991
|
end
|
|
3992
|
+
|
|
3993
|
+
reload_comments = leading.concat(psych_node.comments.leading)
|
|
3601
3994
|
end
|
|
3602
3995
|
|
|
3603
3996
|
@io << "---"
|
|
@@ -3620,6 +4013,12 @@ module Psych
|
|
|
3620
4013
|
|
|
3621
4014
|
@io << q.output
|
|
3622
4015
|
end
|
|
4016
|
+
|
|
4017
|
+
# If we initially split up the leading comments, then we need to reload
|
|
4018
|
+
# them back to their original state here.
|
|
4019
|
+
unless reload_comments.nil?
|
|
4020
|
+
object.psych_node.comments.leading.replace(reload_comments)
|
|
4021
|
+
end
|
|
3623
4022
|
end
|
|
3624
4023
|
|
|
3625
4024
|
private
|
|
@@ -3627,8 +4026,6 @@ module Psych
|
|
|
3627
4026
|
# Dump the tag value for a given node.
|
|
3628
4027
|
def dump_tag(value)
|
|
3629
4028
|
case value
|
|
3630
|
-
when nil, "tag:yaml.org,2002:binary"
|
|
3631
|
-
nil
|
|
3632
4029
|
when /\Atag:yaml.org,2002:(.+)\z/
|
|
3633
4030
|
"!!#{$1}"
|
|
3634
4031
|
else
|
|
@@ -3655,7 +4052,14 @@ module Psych
|
|
|
3655
4052
|
end
|
|
3656
4053
|
|
|
3657
4054
|
if @object_nodes.key?(object)
|
|
3658
|
-
|
|
4055
|
+
@object_anchors[object] ||=
|
|
4056
|
+
if psych_node.is_a?(Nodes::Alias)
|
|
4057
|
+
psych_node.anchor
|
|
4058
|
+
else
|
|
4059
|
+
@object_anchor += 1
|
|
4060
|
+
end
|
|
4061
|
+
|
|
4062
|
+
AliasNode.new(@object_nodes[object].anchor = @object_anchors[object], psych_node)
|
|
3659
4063
|
else
|
|
3660
4064
|
case object
|
|
3661
4065
|
when Psych::Omap
|
|
@@ -3670,8 +4074,7 @@ module Psych
|
|
|
3670
4074
|
when Hash
|
|
3671
4075
|
contents =
|
|
3672
4076
|
if base_object.is_a?(LoadedHash)
|
|
3673
|
-
|
|
3674
|
-
object.flat_map { |key, value| [dump(psych_node_keys.fetch(key, key)), dump(value)] }
|
|
4077
|
+
base_object.psych_assocs.flat_map { |(key, value)| [dump(key), dump(value)] }
|
|
3675
4078
|
else
|
|
3676
4079
|
object.flat_map { |key, value| [dump(key), dump(value)] }
|
|
3677
4080
|
end
|
|
@@ -3683,13 +4086,12 @@ module Psych
|
|
|
3683
4086
|
when String
|
|
3684
4087
|
dumped = StringNode.new(object, psych_node)
|
|
3685
4088
|
dumped.tag = dump_tag(psych_node&.tag)
|
|
3686
|
-
|
|
4089
|
+
dumped.dirty = dirty
|
|
3687
4090
|
dumped
|
|
3688
4091
|
else
|
|
3689
4092
|
dumped = ObjectNode.new(object, psych_node)
|
|
3690
4093
|
dumped.tag = dump_tag(psych_node&.tag)
|
|
3691
4094
|
dumped.dirty = dirty
|
|
3692
|
-
|
|
3693
4095
|
dumped
|
|
3694
4096
|
end
|
|
3695
4097
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: psych-pure
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.4
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Kevin Newton
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2025-
|
|
11
|
+
date: 2025-11-11 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: psych
|
|
@@ -113,7 +113,7 @@ licenses:
|
|
|
113
113
|
- MIT
|
|
114
114
|
metadata:
|
|
115
115
|
bug_tracker_uri: https://github.com/kddnewton/psych-pure/issues
|
|
116
|
-
changelog_uri: https://github.com/kddnewton/psych-pure/blob/v0.1.
|
|
116
|
+
changelog_uri: https://github.com/kddnewton/psych-pure/blob/v0.1.4/CHANGELOG.md
|
|
117
117
|
source_code_uri: https://github.com/kddnewton/psych-pure
|
|
118
118
|
rubygems_mfa_required: 'true'
|
|
119
119
|
post_install_message:
|