如何在Psych中反序列化以返回现有对象,例如类对象?
要进行类的序列化,我可以做
require "psych"
class Class
yaml_tag 'class'
def encode_with coder
coder.represent_scalar 'class', name
end
end
yaml_string = Psych.dump(String) # => "--- !<class> String\n...\n"
但如果我尝试对其进行Psych.load
,我会得到一个匿名类,而不是String类。
正常的反序列化方法是Object#init_with(coder)
,但这只会改变现有匿名类的状态,而我想要String类。
Psych::Visitors::ToRuby#visit_Psych_Nodes_Scalar(o)
的情况是,不是使用init_with
修改现有对象,而是确保首先创建正确的对象(例如,调用Complex(o.value)
来反序列化复数),但我认为我不应该用monkeypatching那种方法。
我注定要处理低水平或中等水平的发射,还是我遗失了什么?
背景
我将描述项目,为什么需要类,以及它为什么需要 (DE)的序列化。
Small Eigen Collider旨在为Ruby创建随机任务。 最初的目的是看看Ruby的不同实现 (例如,Rubinius和JRuby)在给出时返回相同的结果 相同的随机任务,但我发现它也有好处 检测破坏Rubinius和YARV的方法。
每项任务由以下内容组成:
receiver.send(method_name, *parameters, &block)
其中receiver
是随机选择的对象,method_name
是。{
随机选择的方法的名称,*parameters
是一个数组
随机选择的对象。 &block
不是很随意 - 基本上就是这样
相当于{|o| o.inspect}
。
例如,如果receiver是“a”,则method_name为:casecmp,和 参数是[“b”],然后你要调用
"a".send(:casecmp, "b") {|x| x.inspect}
相当于(因为块无关紧要)
"a".casecmp("b")
Small Eigen Collider运行此代码,并记录这些输入和 还有返回值。在这个例子中,Ruby的大多数实现 返回-1,但在一个阶段,Rubinius返回+1。 (我把它作为一个提交 bug https://github.com/evanphx/rubinius/issues/518和Rubinius 维护者修复了这个bug)
我希望能够在我的Small Eigen Collider中使用类对象。 通常,他们将是接收者,但他们也可能是其中之一 参数。
例如,我发现将YARV分段错误的一种方法是
Thread.kill(nil)
在这种情况下,receiver是类对象Thread,参数是 [零]。 (错误报告:http://redmine.ruby-lang.org/issues/show/4367)
小特征对撞机需要序列化,原因有两个。
一个是使用随机数生成器生成一系列 每次随机任务都不实用。 JRuby有一个不同的内置 随机数生成器,所以即使给出相同的PRNG种子它也是 为YARV提供不同的任务。相反,我所做的是创建一个列表 随机任务一次(第一次运行ruby bin / small_eigen_collider),让初始运行序列化列表 任务到tasks.yml,然后有后续运行的 程序(使用不同的Ruby实现)读入tasks.yml 文件以获取任务列表。
我需要序列化的另一个原因是我希望能够编辑 任务列表。如果我有很长的任务列表导致a 分段错误,我想将列表减少到最低要求 导致分段错误。例如,出现以下错误 https://github.com/evanphx/rubinius/issues/643,
ObjectSpace.undefine_finalizer(:symbol)
本身不会导致分段错误,也不会导致
Symbol.all_symbols.inspect
但如果你把两者放在一起,那就确实如此。但我开始时 成千上万的任务,需要把它缩回到那两个 任务。
反序列化返回现有的类对象是否有意义 在这种背景下,还是你认为有更好的方法?
答案 0 :(得分:1)
我目前研究的现状:
要使您所需的行为正常工作,您可以使用我上面提到的解决方法。
这里有格式良好的代码示例:
string_yaml = Psych.dump(Marshal.dump(String))
# => "--- ! \"\\x04\\bc\\vString\"\n"
string_class = Marshal.load(Psych.load(string_yaml))
# => String
修改Class的hack可能永远不会起作用,因为在mental / yaml中没有实现真正的类处理。
您可以使用此repo tenderlove/psych,这是独立的lib。
(宝石:psych - 要加载它,请使用:gem 'psych'; require 'psych'
并检查Psych::VERSION
)
正如您在line 249-251中所看到的,处理具有匿名类的对象不会处理。
而不是monkeypatching class Class我建议你通过扩展这个类处理来为Psych lib做贡献。
所以在我看来,最终的yaml结果应该是:"--- !ruby/class String"
经过一夜的思考,我可以说,这个功能真的很棒!
<强>更新强>
找到一个似乎按预期方式工作的小解决方案:
代码要点: gist.github.com/1012130 (带描述性评论)
答案 1 :(得分:1)