gpt4 book ai didi

ruby - 如何在 Psych 中反序列化类?

转载 作者:数据小太阳 更新时间:2023-10-29 07:37:01 27 4
gpt4 key购买 nike

如何在 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) 来反序列化一个复数),但我认为我不应该对那个方法进行猴子补丁。

我注定要使用低级或中级发射,还是我错过了什么?

背景

我将描述这个项目,为什么它需要类,为什么它需要
(反)序列化。

项目

Small Eigen Collider 旨在为 Ruby 运行创建随机任务。
最初的目的是看看 Ruby 的不同实现
(例如,Rubinius 和 JRuby)在给定时返回相同的结果
相同的随机任务,但我发现它也有利于
检测段错误 Rubinius 和 YARV 的方法。

每个任务由以下部分组成:
receiver.send(method_name, *parameters, &block)

哪里 receiver是一个随机选择的对象,而 method_name是个
随机选择的方法的名称,以及 *parameters是一个数组
随机选择的对象。 &block不是很随机 - 基本上是
相当于 {|o| o.inspect} .

例如,如果接收者是“a”,method_name 是:casecmp,并且
参数是 ["b"],然后你会打电话
"a".send(:casecmp, "b") {|x| x.inspect}

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

Small Eigen Collider 运行此代码,并记录这些输入和
还有返回值。在这个例子中,Ruby 的大多数实现
返回 -1,但在某一阶段,Rubinius 返回 +1。 (我将此作为
错误 https://github.com/evanphx/rubinius/issues/518和鲁比纽斯
维护者修复了错误)

为什么需要类

我希望能够在我的 Small Eigen Collider 中使用类对象。
通常,他们将是接收者,但他们也可以是以下对象之一
参数。

例如,我发现对 YARV 进行段错误的一种方法是执行
Thread.kill(nil)

在这种情况下,接收者是类对象 Thread,参数是
[零]。 (错误报告: http://redmine.ruby-lang.org/issues/show/4367)

为什么需要(反)序列化

Small Eigen Collider 需要序列化有几个原因。

一种是使用随机数生成器生成一系列
每次都是随机任务是不切实际的。 JRuby 有一个不同的内置
随机数生成器,因此即使给定相同的 PRNG 种子,它也会
给 YARV 分配不同的任务。相反,我所做的是创建一个列表
随机任务一次(第一次运行 ruby
bin/small_eigen_collider),让初始运行序列化列表
任务到tasks.yml,然后有后续的运行
在tasks.yml中读取的程序(使用不同的Ruby实现)
文件以获取任务列表。

我需要序列化的另一个原因是我希望能够编辑
任务列表。如果我有一长串任务导致
段错误,我想将列表减少到所需的最小值
导致段错误。例如,有以下错误
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 的技巧可能永远不会奏效,因为真正的类处理不是在 psych/yaml 中实现的。

你可以拿这个 repo tenderlove/psych ,这是独立的库。

( gem : psych - 加载它,使用: gem 'psych'; require 'psych' 并检查 Psych::VERSION )

正如您在 line 249-251 中看到的那样不处理具有匿名类 Class 的对象。

我建议您通过扩展此类处理来为 Psych 库做出贡献,而不是对类 Class 进行猴子修补。

所以在我看来,最终的 yaml 结果应该是这样的: "--- !ruby/class String"
经过一晚的思考,我可以说,这个功能真的很棒!

更新

找到了一个似乎以预期方式工作的小解决方案:

代码要点: gist.github.com/1012130 (带有描述性注释)

关于ruby - 如何在 Psych 中反序列化类?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5774580/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com