如何在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操作,就会得到一个匿名类,而不是字符串类。
通常的反序列化方法是Object#init_with(coder),但这只会更改现有匿名类的状态,而我需要的是string类。
Psych::Visitors::ToRuby#visit_Psych_Nodes_Scalar(o)有这样的情况,即与其使用init_with修改现有对象,不如确保首先创建正确的对象(例如,调用Complex(o.value)来反序列化一个复数),但我不认为应该对该方法进行MonkeyPatching。
我是注定要在低水平还是中等水平的发射下工作,还是我遗漏了什么?
背景
我将描述这个项目,为什么它需要类,为什么它需要
(反)序列化。
项目
小型特征碰撞器的目标是为ruby创建运行的随机任务。
最初的目的是查看ruby的不同实现
(例如,rubinius和jruby)在给定时返回相同的结果
同样的随机任务,但我发现
rubinius和yarv的检测方法。
每个任务由以下部分组成:
receiver.send(method_name, *parameters, &block)

其中receiver是随机选择的对象,而method_name
随机选择的方法的名称,*parameters
随机选择的对象。&block不是很随机的-基本上是
相当于{|o| o.inspect}
例如,如果接收器是“A”,则方法名为:casecmp,并且
参数是[“b”],那么您将调用
"a".send(:casecmp, "b") {|x| x.inspect}

相当于(因为块不相关)
"a".casecmp("b")

小型特征对撞机运行此代码,并记录这些输入和
也是返回值。在本例中,大多数ruby实现
return-1,但在一个阶段,rubinius返回+1。(我将此作为
虫子https://github.com/evanphx/rubinius/issues/518和鲁宾纽斯
维修人员修复了错误)
为什么需要上课
我想在我的小型特征对撞机中使用类对象。
通常,他们是接收者,但也可以是
参数。
例如,我发现一种方法是
Thread.kill(nil)

在本例中,receiver是类对象线程,参数是
[n]。(错误报告:http://redmine.ruby-lang.org/issues/show/4367
为什么它需要(反)序列化
小型本征对撞机需要串行化有几个原因。
一种是使用随机数生成器生成一系列
每次随机任务都不实用。JRuby有一个不同的内置
随机数发生器,所以即使给同一个prng种子
给yarv不同的任务。相反,我做的是创建一个
随机任务一次(ruby的第一次运行
bin/small_eigen_collider),让初始运行的序列化列表
任务到tasks.yml,然后有
程序(使用不同的ruby实现)读入tasks.yml
文件以获取任务列表。
我需要序列化的另一个原因是我希望能够编辑
任务列表。如果我有一长串的任务,导致
分段错误,我想将列表减少到所需的最小值
导致分割错误。例如,有以下错误
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

你修改类的技巧可能永远不会起作用,因为真正的类处理不是在psych/yaml中实现的。
您可以使用这个repotenderlove/psych,它是独立的lib。
(gem:psych-要加载它,请使用:gem 'psych'; require 'psych'并使用Psych::VERSION进行检查)
正如您在line 249-251中看到的,不处理具有匿名类的对象。
我建议您通过扩展这个类处理来贡献psych库,而不是对类类进行monkeypatching。
所以在我看来,最终的yaml结果应该是这样的:"--- !ruby/class String"
经过一个晚上的思考,我可以说,这个功能将非常好!
更新
找到了一个小的解决方案,它似乎以预期的方式工作:
代码要点:gist.github.com/1012130(带描述性注释)

09-05 14:31