* ext/psych/lib/psych/visitors/to_ruby.rb: support objects that are

marshalable, but inherit from basic object.
  Thanks Sean Griffin <sean@thoughtbot.com>

* ext/psych/lib/psych/visitors/yaml_tree.rb: ditto

* test/psych/test_marshalable.rb: test for fix

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@48675 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
tenderlove 2014-12-01 21:35:11 +00:00
Родитель 0a190272cd
Коммит 12396fda40
4 изменённых файлов: 93 добавлений и 0 удалений

Просмотреть файл

@ -1,3 +1,13 @@
Tue Dec 2 06:34:08 2014 Aaron Patterson <aaron@tenderlovemaking.com>
* ext/psych/lib/psych/visitors/to_ruby.rb: support objects that are
marshalable, but inherit from basic object.
Thanks Sean Griffin <sean@thoughtbot.com>
* ext/psych/lib/psych/visitors/yaml_tree.rb: ditto
* test/psych/test_marshalable.rb: test for fix
Tue Dec 2 06:32:02 2014 Nobuyoshi Nakada <nobu@ruby-lang.org> Tue Dec 2 06:32:02 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
* parse.y (ripper_flush_string_content): preserve the dispatched * parse.y (ripper_flush_string_content): preserve the dispatched

Просмотреть файл

@ -271,6 +271,21 @@ module Psych
end end
map map
when /^!ruby\/marshalable:(.*)$/
name = $1
klass = resolve_class(name)
obj = register(o, klass.allocate)
if obj.respond_to?(:init_with)
init_with(obj, revive_hash({}, o), o)
elsif obj.respond_to?(:marshal_load)
marshal_data = o.children.map(&method(:accept))
obj.marshal_load(marshal_data)
obj
else
raise ArgumentError, "Cannot deserialize #{name}"
end
else else
revive_hash(register(o, {}), o) revive_hash(register(o, {}), o)
end end

Просмотреть файл

@ -27,6 +27,8 @@ module Psych
def key? target def key? target
@obj_to_node.key? target.object_id @obj_to_node.key? target.object_id
rescue NoMethodError
false
end end
def id_for target def id_for target
@ -411,6 +413,18 @@ module Psych
end end
end end
def visit_BasicObject o
tag = Psych.dump_tags[o.class]
tag ||= "!ruby/marshalable:#{o.class.name}"
map = @emitter.start_mapping(nil, tag, false, Nodes::Mapping::BLOCK)
register(o, map)
o.marshal_dump.each(&method(:accept))
@emitter.end_mapping
end
private private
# FIXME: Remove the index and count checks in Psych 3.0 # FIXME: Remove the index and count checks in Psych 3.0
NULL = "\x00" NULL = "\x00"

Просмотреть файл

@ -0,0 +1,54 @@
require_relative 'helper'
require 'delegate'
module Psych
class TestMarshalable < TestCase
def test_objects_defining_marshal_dump_and_marshal_load_can_be_dumped
sd = SimpleDelegator.new(1)
loaded = Psych.load(Psych.dump(sd))
assert_instance_of(SimpleDelegator, loaded)
assert_equal(sd, loaded)
end
class PsychCustomMarshalable < BasicObject
attr_reader :foo
def initialize(foo)
@foo = foo
end
def marshal_dump
[foo]
end
def mashal_load(data)
@foo = data[0]
end
def init_with(coder)
@foo = coder['foo']
end
def encode_with(coder)
coder['foo'] = 2
end
def respond_to?(method)
[:marshal_dump, :marshal_load, :init_with, :encode_with].include?(method)
end
def class
PsychCustomMarshalable
end
end
def test_init_with_takes_priority_over_marshal_methods
obj = PsychCustomMarshalable.new(1)
loaded = Psych.load(Psych.dump(obj))
assert(PsychCustomMarshalable === loaded)
assert_equal(2, loaded.foo)
end
end
end