我有一个类Foo应该以最人性化的方式序列化为文本文件,我使用ruby的默认yaml(psych)和customencode_with。我的问题是:如果我像这样删除!ruby/object:Foo

def encode_with coder
  coder.tag = nil
  ...
end

我是否还可以强制psych加载一个映射作为类的对象(使用它的Foo)。理想情况下,我也想删除init_with文档标记。
当然,这很容易用---来解决,但我想知道是否有心理上的解决方案。不幸的是,psych并不是最好的宝石记录。

最佳答案

你可以提供你自己的Handler给psych:

class MyHandler < Psych::Handlers::DocumentStream
  def start_mapping(anchor, tag, implicit, style)
    unless @__root
      tag = "!ruby/hash:MyHash"
      @__root = true
    end
    super anchor, tag, implicit, style
  end
end

class MyHash < Hash
end

def my_parse(yaml)
  parser = Psych::Parser.new(MyHandler.new{|node| return node})
  parser.parse yaml
  false
end

# {a: 1, b: {c: 2, d: 3}, c: [1,2,3]}.to_yaml
str = "---\n:a: 1\n:b:\n  :c: 2\n  :d: 3\n:c:\n- 1\n- 2\n- 3\n"

result = my_parse(str).to_ruby
puts result.class # => MyHash

一些文件。my_parse只是psychdefault parse method的重新实现。我在这里使用MyHandler而不是default handler
MyHandler'sstart_mapping方法重写TreeBuilder'sdefault implementation。这是一个回调,当解析器在yaml中遇到map时调用,而document root是一个map。所以您只需要将标记替换为根元素(不必为其他任何事情操心——这就是为什么我使用@__root变量来跳过进一步的修改)。

10-05 21:42