psych-pure 0.1.2 → 0.1.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0fb90297ca479adfe033c6d8db3544ec41c8e8083f23884e990de4ee2d8eb402
4
- data.tar.gz: 8f895282ff5733903665ddcd0d1be2a28696dce0380242f8804ad42ce45123fe
3
+ metadata.gz: 62e40e29dab03fe116feadefc2a62967ec840deb52bee18bff89ae1318bf4d02
4
+ data.tar.gz: 3f5612a277682bbef3a698e03cc3bde6e9da02dc3f3024d9978aff34af8a624c
5
5
  SHA512:
6
- metadata.gz: 4ad4470231f6587e40da0fe271ef65a1ba441f70ecc87bd7900f4fcc17a2da4be63396b73d15a131359977b62e53cfbd9d333969dbd920e984c6647741bfab34
7
- data.tar.gz: 17965e31133a24c3f14c9d452884665f0d40e0c2e3edbf573fc59db5888471fb934caed61b9bed836287253061e549e540e4b79085360f9ec7a9a8082f4b7107
6
+ metadata.gz: 5be228176e34e4e908e1ea6af1cebbf41b59fa311de3e4a5abec21aefd9e6028f87473714b9e2c0ccf554bec1a379986b9323744c94ebdf9144cdc08d9116991
7
+ data.tar.gz: 4ba02fec03109e76b40883918d1d46125bdd8c1afb9d486a5af2decb868ebc6c967229dda3758e6281b5df709a89b2e6f704d747bad7f307d748861aba580b98
data/CHANGELOG.md CHANGED
@@ -6,6 +6,12 @@ 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.3] - 2025-10-24
10
+
11
+ - Fix up roundtripping when using `<<` inside mappings.
12
+ - Fix up roundtripping when using duplicate keys inside mappings.
13
+ - Fix up comment handling when using duplicate keys inside mappings.
14
+
9
15
  ## [0.1.2] - 2025-03-04
10
16
 
11
17
  - Fix up comment dumping to not drift around objects.
@@ -25,7 +31,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a
25
31
 
26
32
  - 🎉 Initial release. 🎉
27
33
 
28
- [unreleased]: https://github.com/kddnewton/psych-pure/compare/v0.1.2...HEAD
34
+ [unreleased]: https://github.com/kddnewton/psych-pure/compare/v0.1.3...HEAD
35
+ [0.1.3]: https://github.com/kddnewton/psych-pure/compare/v0.1.2...v0.1.3
29
36
  [0.1.2]: https://github.com/kddnewton/psych-pure/compare/v0.1.1...v0.1.2
30
37
  [0.1.1]: https://github.com/kddnewton/psych-pure/compare/v0.1.0...v0.1.1
31
38
  [0.1.0]: https://github.com/kddnewton/psych-pure/compare/24de62...v0.1.0
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Psych
4
4
  module Pure
5
- VERSION = "0.1.2"
5
+ VERSION = "0.1.3"
6
6
  end
7
7
  end
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 is wraps the input string and provides methods to access line and
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 << line.match?(/\A(?: *#.*)?\n\z/)
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
@@ -161,33 +192,75 @@ module Psych
161
192
  @psych_node = psych_node
162
193
  @dirty = dirty
163
194
  end
195
+
196
+ def replace(psych_node)
197
+ @psych_node = psych_node
198
+ @dirty = true
199
+ end
164
200
  end
165
201
 
166
202
  # Wraps a Ruby hash with its node from the source input.
167
203
  class LoadedHash < SimpleDelegator
204
+ class PsychKey
205
+ attr_reader :key_node, :value_node
206
+
207
+ def initialize(key_node, value_node)
208
+ @key_node = key_node
209
+ @value_node = value_node
210
+ end
211
+
212
+ def replace(value_node)
213
+ @value_node = value_node
214
+ end
215
+ end
216
+
168
217
  # The node associated with the hash.
169
218
  attr_reader :psych_node
170
219
 
171
- # The nodes associated with the keys of the hash.
172
- attr_reader :psych_node_keys
173
-
174
- def initialize(object, psych_node, psych_node_keys = {})
220
+ def initialize(object, psych_node)
175
221
  super(object)
176
222
  @psych_node = psych_node
177
- @psych_node_keys = psych_node_keys
223
+ @psych_keys = []
224
+ end
225
+
226
+ def psych_keys
227
+ @psych_keys.map do |psych_key|
228
+ [psych_key.key_node, psych_key.value_node]
229
+ end
178
230
  end
179
231
 
180
232
  def []=(key, value)
181
- if (previous = self[key])
182
- if previous.is_a?(LoadedObject)
183
- value = LoadedObject.new(value, previous.psych_node, true)
184
- elsif previous.is_a?(LoadedHash)
185
- value = LoadedHash.new(value, previous.psych_node, previous.psych_node_keys)
233
+ if begin
234
+ @psych_keys.none? do |psych_key|
235
+ key_node = psych_key.key_node
236
+ key_node_inner =
237
+ if key_node.is_a?(LoadedHash) || key_node.is_a?(LoadedObject)
238
+ key_node.__getobj__
239
+ else
240
+ key_node
241
+ end
242
+
243
+ if key_node_inner.eql?(key)
244
+ psych_key.replace(value)
245
+ true
246
+ end
186
247
  end
248
+ end then
249
+ @psych_keys << PsychKey.new(key, value)
187
250
  end
188
251
 
189
252
  super(key, value)
190
253
  end
254
+
255
+ def set!(key_node, value_node)
256
+ @psych_keys << PsychKey.new(key_node, value_node)
257
+ __getobj__[key_node.__getobj__] = value_node
258
+ end
259
+
260
+ def join!(key_node, value_node)
261
+ @psych_keys << PsychKey.new(key_node, value_node)
262
+ merge!(value_node)
263
+ end
191
264
  end
192
265
 
193
266
  # This module contains all of the extensions to Psych that we need in order
@@ -349,8 +422,6 @@ module Psych
349
422
  def initialize(ss, class_loader, symbolize_names: false, freeze: false, comments: false)
350
423
  super(ss, class_loader, symbolize_names: symbolize_names, freeze: freeze)
351
424
  @comments = comments
352
- @nodeless_objs = {}.compare_by_identity
353
- @nodeless_keys = {}.compare_by_identity
354
425
  end
355
426
 
356
427
  def accept(node)
@@ -360,31 +431,66 @@ module Psych
360
431
  case result
361
432
  when LoadedObject, LoadedHash
362
433
  # skip
363
- when Hash
364
- if !@nodeless_objs.key?(result)
365
- nodeless_obj = {}
366
- nodeless_key = {}
367
-
368
- result.each do |key, value|
369
- if key.is_a?(LoadedObject) || key.is_a?(LoadedHash)
370
- nodeless_obj[key.__getobj__] = value
371
- nodeless_key[key.__getobj__] = key
372
- else
373
- nodeless_obj[key] = value
434
+ else
435
+ result = LoadedObject.new(result, node)
436
+ end
437
+ end
438
+
439
+ result
440
+ end
441
+
442
+ private
443
+
444
+ def revive_hash(hash, node, tagged = false)
445
+ return super unless @comments
446
+
447
+ revived = LoadedHash.new(hash, node)
448
+ node.children.each_slice(2) do |key_node, value_node|
449
+ key = accept(key_node)
450
+ value = accept(value_node)
451
+
452
+ if key == "<<" && key_node.tag != "tag:yaml.org,2002:str"
453
+ case value_node
454
+ when Nodes::Alias, Nodes::Mapping
455
+ begin
456
+ # h1:
457
+ # <<: *h2
458
+ # <<: { k: v }
459
+ revived.join!(key, value)
460
+ rescue TypeError
461
+ # a: &a [1, 2, 3]
462
+ # h: { <<: *a }
463
+ revived.set!(key, value)
464
+ end
465
+ when Nodes::Sequence
466
+ # h1:
467
+ # <<: [*h2, *h3]
468
+ begin
469
+ temporary = {}
470
+ value.reverse_each { |value| temporary.merge!(value) }
471
+ rescue TypeError
472
+ revived.set!(key, value)
473
+ else
474
+ value_node.children.zip(value).reverse_each do |(child_value_node, child_value)|
475
+ revived.join!(key, child_value)
374
476
  end
375
477
  end
376
-
377
- @nodeless_objs[result] = nodeless_obj
378
- @nodeless_keys[result] = nodeless_key
478
+ else
479
+ # k: v
480
+ revived.set!(key, value)
379
481
  end
380
-
381
- result = LoadedHash.new(@nodeless_objs.fetch(result), node, @nodeless_keys.fetch(result))
382
482
  else
383
- result = LoadedObject.new(result, node)
483
+ if !tagged && @symbolize_names && key.is_a?(String)
484
+ key = key.to_sym
485
+ elsif !@freeze
486
+ key = deduplicate(key)
487
+ end
488
+
489
+ revived.set!(key, value)
384
490
  end
385
491
  end
386
492
 
387
- result
493
+ revived
388
494
  end
389
495
  end
390
496
 
@@ -493,11 +599,12 @@ module Psych
493
599
  # A scalar event represents a single value in the YAML document. It can be
494
600
  # many different types.
495
601
  class Scalar
496
- attr_reader :location, :value, :style
602
+ attr_reader :location, :source, :value, :style
497
603
  attr_accessor :anchor, :tag
498
604
 
499
- def initialize(location, value, style)
605
+ def initialize(location, source, value, style)
500
606
  @location = location
607
+ @source = source
501
608
  @value = value
502
609
  @anchor = nil
503
610
  @tag = nil
@@ -506,14 +613,19 @@ module Psych
506
613
 
507
614
  def accept(handler)
508
615
  handler.event_location(*@location.trim)
509
- handler.scalar(
510
- @value,
511
- @anchor,
512
- @tag,
513
- (!@tag || @tag == "!") && (@style == Nodes::Scalar::PLAIN),
514
- (!@tag || @tag == "!") && (@style != Nodes::Scalar::PLAIN),
515
- @style
516
- )
616
+
617
+ event =
618
+ handler.scalar(
619
+ @value,
620
+ @anchor,
621
+ @tag,
622
+ (!@tag || @tag == "!") && (@style == Nodes::Scalar::PLAIN),
623
+ (!@tag || @tag == "!") && (@style != Nodes::Scalar::PLAIN),
624
+ @style
625
+ )
626
+
627
+ event.source = source if event.is_a?(Nodes::Scalar)
628
+ event
517
629
  end
518
630
  end
519
631
 
@@ -1453,7 +1565,7 @@ module Psych
1453
1565
  # e-scalar ::=
1454
1566
  # <empty>
1455
1567
  def parse_e_scalar
1456
- events_push_flush_properties(Scalar.new(Location.point(@source, @scanner.pos), "", Nodes::Scalar::PLAIN))
1568
+ events_push_flush_properties(Scalar.new(Location.point(@source, @scanner.pos), "", "", Nodes::Scalar::PLAIN))
1457
1569
  true
1458
1570
  end
1459
1571
 
@@ -1557,7 +1669,7 @@ module Psych
1557
1669
  end
1558
1670
  end
1559
1671
 
1560
- events_push_flush_properties(Scalar.new(Location.new(@source, pos_start, @scanner.pos), value, Nodes::Scalar::DOUBLE_QUOTED))
1672
+ events_push_flush_properties(Scalar.new(Location.new(@source, pos_start, @scanner.pos), from(pos_start), value, Nodes::Scalar::DOUBLE_QUOTED))
1561
1673
  true
1562
1674
  end
1563
1675
  end
@@ -1701,7 +1813,7 @@ module Psych
1701
1813
  value.gsub!(/(?:[\ \t]*\r?\n[\ \t]*)/, "\n")
1702
1814
  value.gsub!(/\n(\n*)/) { $1.empty? ? " " : $1 }
1703
1815
  value.gsub!("''", "'")
1704
- events_push_flush_properties(Scalar.new(Location.new(@source, pos_start, @scanner.pos), value, Nodes::Scalar::SINGLE_QUOTED))
1816
+ events_push_flush_properties(Scalar.new(Location.new(@source, pos_start, @scanner.pos), from(pos_start), value, Nodes::Scalar::SINGLE_QUOTED))
1705
1817
  true
1706
1818
  end
1707
1819
  end
@@ -2241,10 +2353,13 @@ module Psych
2241
2353
  end
2242
2354
 
2243
2355
  if result
2244
- value = from(pos_start)
2356
+ source = from(pos_start)
2357
+
2358
+ value = source.dup
2245
2359
  value.gsub!(/(?:[\ \t]*\r?\n[\ \t]*)/, "\n")
2246
2360
  value.gsub!(/\n(\n*)/) { $1.empty? ? " " : $1 }
2247
- events_push_flush_properties(Scalar.new(Location.new(@source, pos_start, @scanner.pos), value, Nodes::Scalar::PLAIN))
2361
+
2362
+ events_push_flush_properties(Scalar.new(Location.new(@source, pos_start, @scanner.pos), source, value, Nodes::Scalar::PLAIN))
2248
2363
  end
2249
2364
 
2250
2365
  result
@@ -2470,8 +2585,7 @@ module Psych
2470
2585
  parse_l_literal_content(n + m, t)
2471
2586
  } then
2472
2587
  @in_scalar = false
2473
- lines = events_cache_pop
2474
- value = lines.map { |line| "#{line}\n" }.join
2588
+ value = events_cache_pop.map { |line| "#{line}\n" }.join
2475
2589
 
2476
2590
  case t
2477
2591
  when :clip
@@ -2484,7 +2598,8 @@ module Psych
2484
2598
  raise InternalException, t.inspect
2485
2599
  end
2486
2600
 
2487
- events_push_flush_properties(Scalar.new(Location.new(@source, pos_start, @scanner.pos), value, Nodes::Scalar::LITERAL))
2601
+ location = Location.new(@source, pos_start, @scanner.pos).trim_comments
2602
+ events_push_flush_properties(Scalar.new(location, @scanner.string.byteslice(location.range).chomp, value, Nodes::Scalar::LITERAL))
2488
2603
  true
2489
2604
  else
2490
2605
  @in_scalar = false
@@ -2582,7 +2697,8 @@ module Psych
2582
2697
  raise InternalException, t.inspect
2583
2698
  end
2584
2699
 
2585
- events_push_flush_properties(Scalar.new(Location.new(@source, pos_start, @scanner.pos), value, Nodes::Scalar::FOLDED))
2700
+ location = Location.new(@source, pos_start, @scanner.pos).trim_comments
2701
+ events_push_flush_properties(Scalar.new(location, @scanner.string.byteslice(location.range).chomp, value, Nodes::Scalar::FOLDED))
2586
2702
  true
2587
2703
  else
2588
2704
  @in_scalar = false
@@ -3220,8 +3336,14 @@ module Psych
3220
3336
 
3221
3337
  # Represents a string object.
3222
3338
  class StringNode < Node
3339
+ # The explicit tag associated with the object.
3223
3340
  attr_accessor :tag
3224
3341
 
3342
+ # Whether or not this object was modified after being loaded. In this
3343
+ # case we cannot rely on the source formatting, and need to instead
3344
+ # format the value ourselves.
3345
+ attr_accessor :dirty
3346
+
3225
3347
  def accept(visitor)
3226
3348
  visitor.visit_string(self)
3227
3349
  end
@@ -3264,13 +3386,17 @@ module Psych
3264
3386
  # Visit an ObjectNode.
3265
3387
  def visit_object(node)
3266
3388
  with_comments(node) do |value|
3267
- if (tag = node.tag)
3268
- @q.text("#{tag} ")
3269
- end
3270
-
3271
3389
  if !node.dirty && (psych_node = node.psych_node)
3272
- @q.text(psych_node.value)
3390
+ if (tag = node.tag)
3391
+ @q.text("#{tag} ")
3392
+ end
3393
+
3394
+ @q.text(psych_node.source || psych_node.value)
3273
3395
  else
3396
+ if (tag = node.tag) && tag != "tag:yaml.org,2002:binary"
3397
+ @q.text("#{tag} ")
3398
+ end
3399
+
3274
3400
  @q.text(dump_object(value))
3275
3401
  end
3276
3402
  end
@@ -3293,11 +3419,19 @@ module Psych
3293
3419
  # Visit a StringNode.
3294
3420
  def visit_string(node)
3295
3421
  with_comments(node) do |value|
3296
- if (tag = node.tag)
3297
- @q.text("#{tag} ")
3298
- end
3422
+ if !node.dirty && (psych_node = node.psych_node)
3423
+ if (tag = node.tag)
3424
+ @q.text("#{tag} ")
3425
+ end
3299
3426
 
3300
- @q.text(dump_object(value))
3427
+ @q.text(psych_node.source || psych_node.value)
3428
+ else
3429
+ if (tag = node.tag) && tag != "tag:yaml.org,2002:binary"
3430
+ @q.text("#{tag} ")
3431
+ end
3432
+
3433
+ @q.text(dump_object(value))
3434
+ end
3301
3435
  end
3302
3436
  end
3303
3437
 
@@ -3447,9 +3581,26 @@ module Psych
3447
3581
  @q.breakable
3448
3582
  end
3449
3583
 
3584
+ current_line = nil
3450
3585
  ((0...children.length) % 2).each do |index|
3451
- @q.breakable if index != 0
3452
- visit_hash_key_value(children[index], children[index + 1])
3586
+ key = children[index]
3587
+ value = children[index + 1]
3588
+
3589
+ if index > 0
3590
+ @q.breakable
3591
+
3592
+ if current_line && (psych_node = key.psych_node)
3593
+ start_line = psych_node.start_line
3594
+ if (leading = key.psych_node.comments.leading).any?
3595
+ start_line = leading.first.start_line
3596
+ end
3597
+
3598
+ @q.breakable if start_line - current_line >= 2
3599
+ end
3600
+ end
3601
+
3602
+ current_line = (psych_node = value.psych_node) ? psych_node.end_line : nil
3603
+ visit_hash_key_value(key, value)
3453
3604
  end
3454
3605
 
3455
3606
  @q.current_group.break
@@ -3576,6 +3727,7 @@ module Psych
3576
3727
  # Very rare circumstance here that there are leading comments attached
3577
3728
  # to the root object of a document that occur before the --- marker. In
3578
3729
  # this case we want to output them first here, then dump the object.
3730
+ reload_comments = nil
3579
3731
  if (object.is_a?(LoadedObject) || object.is_a?(LoadedHash)) && (psych_node = object.psych_node).comments? && (leading = psych_node.comments.leading).any?
3580
3732
  leading = [*leading]
3581
3733
  line = psych_node.start_line - 1
@@ -3598,6 +3750,8 @@ module Psych
3598
3750
 
3599
3751
  line = comment.start_line
3600
3752
  end
3753
+
3754
+ reload_comments = leading.concat(psych_node.comments.leading)
3601
3755
  end
3602
3756
 
3603
3757
  @io << "---"
@@ -3620,6 +3774,12 @@ module Psych
3620
3774
 
3621
3775
  @io << q.output
3622
3776
  end
3777
+
3778
+ # If we initially split up the leading comments, then we need to reload
3779
+ # them back to their original state here.
3780
+ unless reload_comments.nil?
3781
+ object.psych_node.comments.leading.replace(reload_comments)
3782
+ end
3623
3783
  end
3624
3784
 
3625
3785
  private
@@ -3627,8 +3787,6 @@ module Psych
3627
3787
  # Dump the tag value for a given node.
3628
3788
  def dump_tag(value)
3629
3789
  case value
3630
- when nil, "tag:yaml.org,2002:binary"
3631
- nil
3632
3790
  when /\Atag:yaml.org,2002:(.+)\z/
3633
3791
  "!!#{$1}"
3634
3792
  else
@@ -3655,7 +3813,14 @@ module Psych
3655
3813
  end
3656
3814
 
3657
3815
  if @object_nodes.key?(object)
3658
- AliasNode.new(@object_nodes[object].anchor = (@object_anchors[object] ||= (@object_anchor += 1)), nil)
3816
+ @object_anchors[object] ||=
3817
+ if psych_node.is_a?(Nodes::Alias)
3818
+ psych_node.anchor
3819
+ else
3820
+ @object_anchor += 1
3821
+ end
3822
+
3823
+ AliasNode.new(@object_nodes[object].anchor = @object_anchors[object], psych_node)
3659
3824
  else
3660
3825
  case object
3661
3826
  when Psych::Omap
@@ -3670,8 +3835,7 @@ module Psych
3670
3835
  when Hash
3671
3836
  contents =
3672
3837
  if base_object.is_a?(LoadedHash)
3673
- psych_node_keys = base_object.psych_node_keys
3674
- object.flat_map { |key, value| [dump(psych_node_keys.fetch(key, key)), dump(value)] }
3838
+ base_object.psych_keys.flat_map { |(key, value)| [dump(key), dump(value)] }
3675
3839
  else
3676
3840
  object.flat_map { |key, value| [dump(key), dump(value)] }
3677
3841
  end
@@ -3683,13 +3847,12 @@ module Psych
3683
3847
  when String
3684
3848
  dumped = StringNode.new(object, psych_node)
3685
3849
  dumped.tag = dump_tag(psych_node&.tag)
3686
-
3850
+ dumped.dirty = dirty
3687
3851
  dumped
3688
3852
  else
3689
3853
  dumped = ObjectNode.new(object, psych_node)
3690
3854
  dumped.tag = dump_tag(psych_node&.tag)
3691
3855
  dumped.dirty = dirty
3692
-
3693
3856
  dumped
3694
3857
  end
3695
3858
  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.2
4
+ version: 0.1.3
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-03-04 00:00:00.000000000 Z
11
+ date: 2025-10-24 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.2/CHANGELOG.md
116
+ changelog_uri: https://github.com/kddnewton/psych-pure/blob/v0.1.3/CHANGELOG.md
117
117
  source_code_uri: https://github.com/kddnewton/psych-pure
118
118
  rubygems_mfa_required: 'true'
119
119
  post_install_message: