我有一个Foo
的子类Hash
。
class Foo < Hash
# whatever Foo-specific methods/etc
end
当我将它转储到带有YAML的文件时,它会写一个表示该类的标记。
> f = Foo.new
> f[:bar] = "baz"
> puts YAML.dump(f)
--- !ruby/hash:Foo
:bar: baz
我希望它只是写成一个普通的旧哈希(不是!ruby/hash:Foo
)
> puts YAML.dump({bar:"baz"})
---
:bar: baz
...以便我的数据的消费者不需要了解Foo
。是否有一种神奇的方法可以添加到我的类中以转换为序列化,或者是一个传递给YAML.dump的魔术选项?
当然很容易将一个Foo
对象转换为哈希值,但是它们可能会嵌套在我要转储的实际哈希中的任何级别,而我宁愿不必这样做搜索和替换。
答案 0 :(得分:3)
您可以使用(记录不完整的)encode_with
和represent_map
方法实现此目的。要自定义对象的YAML序列化,请使用encode_with
方法接受coder
对象,其中一个方法是represent_map
。
class Foo < Hash
# other methods ...
def encode_with coder
coder.represent_map nil, self
end
end
现在YAML.dump
只会将您的对象输出为普通哈希值。
有一个问题,因为有一个错误会导致失败并且是only fixed in the latest Gem version of Psych。在当前最新的Ruby版本(ruby 2.0.0p247)中修复了 not 。它is fixed in Ruby trunk所以后来的补丁发布应该没问题。
为了使用它,您必须确保使用最新的Psych Gem,而不是与Ruby捆绑的版本。这应该像
一样简单gem 'psych', '2.0.0'
在您需要Yaml之前,但似乎在Ruby 2.0中,由于某些我无法弄清楚的原因,这不起作用。使用Bundler来指定Gem版本确实有效,因此如果你还没有使用它,你可能需要创建一个Gemfile
并在那里指定Psych。
答案 1 :(得分:0)
搜索和替换实际上并不太糟糕:
# Convert Hash/Array subclasses into plain hashes/arrays for YAML dump.
# Assumptions:
# Hash keys will be simple objects - don't need to clear them
# No custom objects containing Hash/Array subclass instances
def deep_clear_subclasses(obj, dedup = {})
case obj
when Hash
return dedup[obj] if dedup.has_key? obj
dedup[obj] = copy = {}
obj.each {|k,v| copy[k] = deep_clear_subclasses(v, dedup)}
copy
when Array
return dedup[obj] if dedup.has_key? obj
obj.inject(dedup[obj] = []) {|a,v| a << deep_clear_subclasses(v,dedup)}
else
obj # not going to operate on other kinds of objects
end
end