mirror of
https://github.com/ruby/ruby.git
synced 2025-08-15 13:39:04 +02:00
parent
bd1d6e8cd7
commit
a397e4d4b0
7 changed files with 130 additions and 0 deletions
|
@ -6,6 +6,7 @@ module Psych
|
|||
class ClassLoader # :nodoc:
|
||||
BIG_DECIMAL = 'BigDecimal'
|
||||
COMPLEX = 'Complex'
|
||||
DATA = 'Data' unless RUBY_VERSION < "3.2"
|
||||
DATE = 'Date'
|
||||
DATE_TIME = 'DateTime'
|
||||
EXCEPTION = 'Exception'
|
||||
|
|
|
@ -197,6 +197,14 @@ module Psych
|
|||
s
|
||||
end
|
||||
|
||||
when /^!ruby\/data(?::(.*))?$/
|
||||
data = register(o, resolve_class($1).allocate) if $1
|
||||
members = {}
|
||||
revive_data_members(members, o)
|
||||
data ||= allocate_anon_data(o, members)
|
||||
data.send(:initialize, **members)
|
||||
data
|
||||
|
||||
when /^!ruby\/object:?(.*)?$/
|
||||
name = $1 || 'Object'
|
||||
|
||||
|
@ -340,6 +348,20 @@ module Psych
|
|||
list
|
||||
end
|
||||
|
||||
def allocate_anon_data node, members
|
||||
klass = class_loader.data.define(*members.keys)
|
||||
register(node, klass.allocate)
|
||||
end
|
||||
|
||||
def revive_data_members hash, o
|
||||
o.children.each_slice(2) do |k,v|
|
||||
name = accept(k)
|
||||
value = accept(v)
|
||||
hash[class_loader.symbolize(name)] = value
|
||||
end
|
||||
hash
|
||||
end
|
||||
|
||||
def revive_hash hash, o, tagged= false
|
||||
o.children.each_slice(2) { |k,v|
|
||||
key = accept(k)
|
||||
|
|
|
@ -162,6 +162,16 @@ module Psych
|
|||
|
||||
alias :visit_Delegator :visit_Object
|
||||
|
||||
def visit_Data o
|
||||
tag = ['!ruby/data', o.class.name].compact.join(':')
|
||||
register o, @emitter.start_mapping(nil, tag, false, Nodes::Mapping::BLOCK)
|
||||
o.members.each do |member|
|
||||
@emitter.scalar member.to_s, nil, nil, true, false, Nodes::Scalar::ANY
|
||||
accept o.send member
|
||||
end
|
||||
@emitter.end_mapping
|
||||
end
|
||||
|
||||
def visit_Struct o
|
||||
tag = ['!ruby/struct', o.class.name].compact.join(':')
|
||||
|
||||
|
|
|
@ -31,6 +31,11 @@ module Psych
|
|||
assert_reference_trip Struct.new(:foo).new(1)
|
||||
end
|
||||
|
||||
def test_data_has_references
|
||||
omit "Data requires ruby >= 3.2" if RUBY_VERSION < "3.2"
|
||||
assert_reference_trip Data.define(:foo).new(1)
|
||||
end
|
||||
|
||||
def assert_reference_trip obj
|
||||
yml = Psych.dump([obj, obj])
|
||||
assert_match(/\*-?\d+/, yml)
|
||||
|
|
|
@ -114,6 +114,38 @@ module Psych
|
|||
end
|
||||
end
|
||||
|
||||
D = Data.define(:d) unless RUBY_VERSION < "3.2"
|
||||
|
||||
def test_data_depends_on_sym
|
||||
omit "Data requires ruby >= 3.2" if RUBY_VERSION < "3.2"
|
||||
assert_safe_cycle(D.new(nil), permitted_classes: [D, Symbol])
|
||||
assert_raise(Psych::DisallowedClass) do
|
||||
cycle D.new(nil), permitted_classes: [D]
|
||||
end
|
||||
end
|
||||
|
||||
def test_anon_data
|
||||
omit "Data requires ruby >= 3.2" if RUBY_VERSION < "3.2"
|
||||
assert Psych.safe_load(<<-eoyml, permitted_classes: [Data, Symbol])
|
||||
--- !ruby/data
|
||||
foo: bar
|
||||
eoyml
|
||||
|
||||
assert_raise(Psych::DisallowedClass) do
|
||||
Psych.safe_load(<<-eoyml, permitted_classes: [Data])
|
||||
--- !ruby/data
|
||||
foo: bar
|
||||
eoyml
|
||||
end
|
||||
|
||||
assert_raise(Psych::DisallowedClass) do
|
||||
Psych.safe_load(<<-eoyml, permitted_classes: [Symbol])
|
||||
--- !ruby/data
|
||||
foo: bar
|
||||
eoyml
|
||||
end
|
||||
end
|
||||
|
||||
def test_safe_load_default_fallback
|
||||
assert_nil Psych.safe_load("")
|
||||
end
|
||||
|
|
|
@ -6,6 +6,7 @@ require_relative 'helper'
|
|||
# [ruby-core:01946]
|
||||
module Psych_Tests
|
||||
StructTest = Struct::new( :c )
|
||||
DataTest = Data.define( :c ) unless RUBY_VERSION < "3.2"
|
||||
end
|
||||
|
||||
class Psych_Unit_Tests < Psych::TestCase
|
||||
|
@ -1075,6 +1076,44 @@ EOY
|
|||
|
||||
end
|
||||
|
||||
def test_ruby_data
|
||||
omit "Data requires ruby >= 3.2" if RUBY_VERSION < "3.2"
|
||||
Object.remove_const :MyBookData if Object.const_defined?(:MyBookData)
|
||||
# Ruby Data value objects
|
||||
book_class = Data.define(:author, :title, :year, :isbn)
|
||||
Object.const_set(:MyBookData, book_class)
|
||||
assert_to_yaml(
|
||||
[ book_class.new( "Yukihiro Matsumoto", "Ruby in a Nutshell", 2002, "0-596-00214-9" ),
|
||||
book_class.new( [ 'Dave Thomas', 'Andy Hunt' ], "The Pickaxe", 2002,
|
||||
book_class.new( "This should be the ISBN", "but I have more data here", 2002, "None" )
|
||||
)
|
||||
], <<EOY
|
||||
- !ruby/data:MyBookData
|
||||
author: Yukihiro Matsumoto
|
||||
title: Ruby in a Nutshell
|
||||
year: 2002
|
||||
isbn: 0-596-00214-9
|
||||
- !ruby/data:MyBookData
|
||||
author:
|
||||
- Dave Thomas
|
||||
- Andy Hunt
|
||||
title: The Pickaxe
|
||||
year: 2002
|
||||
isbn: !ruby/data:MyBookData
|
||||
author: This should be the ISBN
|
||||
title: but I have more data here
|
||||
year: 2002
|
||||
isbn: None
|
||||
EOY
|
||||
)
|
||||
|
||||
assert_to_yaml( Psych_Tests::DataTest.new( 123 ), <<EOY )
|
||||
--- !ruby/data:Psych_Tests::DataTest
|
||||
c: 123
|
||||
EOY
|
||||
|
||||
end
|
||||
|
||||
def test_ruby_rational
|
||||
assert_to_yaml( Rational(1, 2), <<EOY )
|
||||
--- !ruby/object:Rational
|
||||
|
|
|
@ -73,6 +73,27 @@ module Psych
|
|||
assert_equal s.method, obj.method
|
||||
end
|
||||
|
||||
D = Data.define(:foo) unless RUBY_VERSION < "3.2"
|
||||
|
||||
def test_data
|
||||
omit "Data requires ruby >= 3.2" if RUBY_VERSION < "3.2"
|
||||
assert_cycle D.new('bar')
|
||||
end
|
||||
|
||||
def test_data_anon
|
||||
omit "Data requires ruby >= 3.2" if RUBY_VERSION < "3.2"
|
||||
d = Data.define(:foo).new('bar')
|
||||
obj = Psych.unsafe_load(Psych.dump(d))
|
||||
assert_equal d.foo, obj.foo
|
||||
end
|
||||
|
||||
def test_data_override_method
|
||||
omit "Data requires ruby >= 3.2" if RUBY_VERSION < "3.2"
|
||||
d = Data.define(:method).new('override')
|
||||
obj = Psych.unsafe_load(Psych.dump(d))
|
||||
assert_equal d.method, obj.method
|
||||
end
|
||||
|
||||
def test_exception
|
||||
ex = Exception.new 'foo'
|
||||
loaded = Psych.unsafe_load(Psych.dump(ex))
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue