[ruby/psych] Handle Ruby 3.5 new Set class

Since `Set` no longer is a regular object class holding a Hash
it needs to be specially handled.

https://github.com/ruby/psych/commit/c2d185d27c
This commit is contained in:
Jean Boussier 2025-04-30 09:13:29 +02:00 committed by git
parent 46c9e46ef6
commit f55138c9e7
3 changed files with 92 additions and 42 deletions

View File

@ -17,3 +17,17 @@ end
if defined?(::IRB)
require_relative 'y'
end
# TODO: how best to check for builtin Set?
if defined?(::Set) && Object.const_source_location(:Set) == ["ruby", 0]
class Set
def encode_with(coder)
coder["hash"] = to_h
end
def init_with(coder)
replace(coder["hash"].keys)
end
end
end

View File

@ -0,0 +1,57 @@
# frozen_string_literal: true
require_relative 'helper'
module Psych
class TestPsychSet < TestCase
def setup
super
@set = Psych::Set.new
@set['foo'] = 'bar'
@set['bar'] = 'baz'
end
def test_dump
assert_match(/!set/, Psych.dump(@set))
end
def test_roundtrip
assert_cycle(@set)
end
###
# FIXME: Syck should also support !!set as shorthand
def test_load_from_yaml
loaded = Psych.unsafe_load(<<-eoyml)
--- !set
foo: bar
bar: baz
eoyml
assert_equal(@set, loaded)
end
def test_loaded_class
assert_instance_of(Psych::Set, Psych.unsafe_load(Psych.dump(@set)))
end
def test_set_shorthand
loaded = Psych.unsafe_load(<<-eoyml)
--- !!set
foo: bar
bar: baz
eoyml
assert_instance_of(Psych::Set, loaded)
end
def test_set_self_reference
@set['self'] = @set
assert_cycle(@set)
end
def test_stringify_names
@set[:symbol] = :value
assert_match(/^:symbol: :value/, Psych.dump(@set))
assert_match(/^symbol: :value/, Psych.dump(@set, stringify_names: true))
end
end
end

View File

@ -1,57 +1,36 @@
# encoding: UTF-8
# frozen_string_literal: true
require_relative 'helper'
require 'set' unless defined?(Set)
module Psych
class TestSet < TestCase
def setup
super
@set = Psych::Set.new
@set['foo'] = 'bar'
@set['bar'] = 'baz'
@set = ::Set.new([1, 2, 3])
end
def test_dump
assert_match(/!set/, Psych.dump(@set))
assert_equal <<~YAML, Psych.dump(@set)
--- !ruby/object:Set
hash:
1: true
2: true
3: true
YAML
end
def test_load
assert_equal @set, Psych.load(<<~YAML, permitted_classes: [::Set])
--- !ruby/object:Set
hash:
1: true
2: true
3: true
YAML
end
def test_roundtrip
assert_cycle(@set)
end
###
# FIXME: Syck should also support !!set as shorthand
def test_load_from_yaml
loaded = Psych.unsafe_load(<<-eoyml)
--- !set
foo: bar
bar: baz
eoyml
assert_equal(@set, loaded)
end
def test_loaded_class
assert_instance_of(Psych::Set, Psych.unsafe_load(Psych.dump(@set)))
end
def test_set_shorthand
loaded = Psych.unsafe_load(<<-eoyml)
--- !!set
foo: bar
bar: baz
eoyml
assert_instance_of(Psych::Set, loaded)
end
def test_set_self_reference
@set['self'] = @set
assert_cycle(@set)
end
def test_stringify_names
@set[:symbol] = :value
assert_match(/^:symbol: :value/, Psych.dump(@set))
assert_match(/^symbol: :value/, Psych.dump(@set, stringify_names: true))
assert_equal @set, Psych.load(Psych.dump(@set), permitted_classes: [::Set])
end
end
end