如何在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该方法.
我注定要使用低水平或中等水平的发射,或者我错过了什么?
背景
我将描述该项目,为什么需要类,以及它为什么需要
(德)序列化.
项目
Small Eigen Collider旨在为Ruby创建随机任务.
最初的目的是看看Ruby的不同实现
(例如,Rubinius和JRuby)在给出时返回相同的结果
相同的随机任务,但我发现它也有好处
检测破坏Rubinius和YARV的方法.
每项任务由以下内容组成:
receiver.send(method_name, *parameters, &block)
其中receiver是随机选择的对象,method_name是
随机选择的方法的名称,*参数是一个数组
随机选择的对象. & block不是很随意 – 基本上就是这样
相当于{| o | o.inspect}.
例如,如果receiver是“a”,则method_name为:casecmp,和
参数是[“b”],然后你会打电话
"a".send(:casecmp, "b") {|x| x.inspect}
相当于(因为块无关紧要)
"a".casecmp("b")
小特征碰撞器运行此代码,并记录这些输入和
还有返回值.在这个例子中,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
但如果你把两者放在一起,那就确实如此.但我开始时
成千上万的任务,需要把它缩回到那两个
任务.
反序列化返回现有的类对象是否有意义
这个背景,还是你认为有更好的方法?
最佳答案 我目前研究的现状:
要使您所需的行为正常工作,您可以使用上面提到的解决方法.
这里格式很好的代码示例:
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 – 加载它,使用:宝石’心理’;需要’心理’并与Psych :: VERSION进行检查)
正如您在line 249-251中所看到的那样,处理具有匿名类Class的对象不会被处理.
我没有对班级进行monkeypatching,而是建议您通过扩展此类处理来为Psych lib做贡献.
所以在我看来,最终的yaml结果应该是这样的:“—!ruby / class String”
经过一夜思考,我可以说,这个功能真的很棒!
更新
找到一个似乎按预期方式工作的小解决方案:
代码要点:gist.github.com/1012130(带描述性注释)