如何从外部源反序列化 YAML 文档并对类成员拥有完全访问权限?
在 Ruby 中,通过将“to_yaml
”方法的输出保存到文件中,任何对象都可以传输(即序列化)到 YAML 文档。之后,可以使用 YAML::load
方法再次读取该 YAML 文件,即反序列化。此外,人们可以完全访问底层类/对象的所有成员。
只要我使用 Ruby 作为单一平台,所有这些都是有效的。一旦我在 Java 中序列化对象并在 Ruby 下反序列化它们,由于 NoMethodError
异常,我无法再访问该对象。这是由于不同系统下对象/本地数据类型的命名方式所致。
给定一个 Ruby 类“Car”:
# A simple class describing a car
#
class Car
attr :brand, :horsepower, :color, :extra_equipment
def initialize(brand, horsepower, color, extra_equipment)
@brand = brand
@horsepower = horsepower
@color = color
@extra_equipment = extra_equipment
end
end
创建一个简单的实例:
# creating new instance of class 'Car' ...
porsche = Car.new("Porsche", 180, "red", ["sun roof", "air conditioning"])
调用 porsche.to_yaml 会产生以下输出:
--- !ruby/object:Car
brand: Porsche
color: red
extra_equipment:
- sun roof
- air conditioning
horsepower: 180
我通过加载 YAML 输出来测试反序列化:
# reading existing yaml file from file system
sample_car = YAML::load(File.open("sample.yaml"))
puts sample_car.brand # returns "Porsche"
这按预期工作,但现在让我们假设 YAML该文档是由不同的系统生成的,并且缺少对 Ruby 的任何引用,尽管有一个符合 yaml 的对象描述“!Car
”,而不是“!ruby/object:Car”:
--- !Car
brand: Porsche
color: red
extra_equipment:
- sun roof
- air conditioning
horsepower: 180
此代码:
# reading existing yaml file from file system
sample_car = YAML::load(File.open("sample.yaml"))
puts sample_car.brand # returns "Porsche"
返回此异常:
/path/yaml_to_object_converter.rb.rb:27:in `<main>':
undefined method `brand' for #<YAML::DomainType:0x9752bec> (NoMethodError)
有没有办法处理“外部”YAML 文档中定义的对象?
In Ruby any object can be transferred, i.e. serialized, to a YAML document by saving the output of the "to_yaml
" method to a file. Afterwards, this YAML file can be read again, i.e. deserialized, by using the YAML::load
method. Moreover, one has full access on all members of the underlying class/object.
All of this is valid as long I'm using Ruby as a single platform. Once I serialize objects in Java and deserialize them under Ruby, I cannot access the object any more because of a NoMethodError
exception. This is due to to the way objects/local data types are named under different systems.
Given a Ruby class "Car":
# A simple class describing a car
#
class Car
attr :brand, :horsepower, :color, :extra_equipment
def initialize(brand, horsepower, color, extra_equipment)
@brand = brand
@horsepower = horsepower
@color = color
@extra_equipment = extra_equipment
end
end
Creating a simple instance:
# creating new instance of class 'Car' ...
porsche = Car.new("Porsche", 180, "red", ["sun roof", "air conditioning"])
Calling porsche.to_yaml
results in the following output:
--- !ruby/object:Car
brand: Porsche
color: red
extra_equipment:
- sun roof
- air conditioning
horsepower: 180
I test deserialization by loading the YAML output:
# reading existing yaml file from file system
sample_car = YAML::load(File.open("sample.yaml"))
puts sample_car.brand # returns "Porsche"
This works as expected, but now let's assume the YAML document was produced by a different system and lacks any reference to Ruby, although having a yaml-conform object description, "!Car
", instead of "!ruby/object:Car
":
--- !Car
brand: Porsche
color: red
extra_equipment:
- sun roof
- air conditioning
horsepower: 180
This code:
# reading existing yaml file from file system
sample_car = YAML::load(File.open("sample.yaml"))
puts sample_car.brand # returns "Porsche"
returns this exception:
/path/yaml_to_object_converter.rb.rb:27:in `<main>':
undefined method `brand' for #<YAML::DomainType:0x9752bec> (NoMethodError)
Is there a way to deal with objects defined in "external" YAML documents?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
对我来说,IRB shell 中的
sample_car
计算结果为:然后我发出
sample_car.value
:这是一个哈希值。这意味着,您可以通过向
Car
添加类方法来构造 您的 Car 对象,如下所示:然后我尝试了:
返回:
这是最丑陋的做法。可能还有其他人。 =)
编辑(2011 年 5 月 19 日):顺便说一句,只是想出了一个更简单的方法:
为了在您的情况下工作,您的构造函数不得需要参数。然后你可以简单地做:
...这给你:
For me
sample_car
in the IRB shell evaluates to:Then I issued
sample_car.value
:Which is a Hash. This means, that you can construct your Car object by adding a class method to
Car
like so:Then I tried it:
Which returned:
That's the ugliest way of doing it. There might be others. =)
EDIT (19-May-2011): BTW, Just figured a lot easier way:
For this to work in your case, your constructor must not require parameters. Then you can simply do:
...which gives you: