Force Psych读取YAML地图作为给定类的对象

Bor*_*nho 3 ruby serialization yaml

我有一个Foo应该以最人性化的方式序列化为文本文件的类,我使用Ruby的默认YAML(Psych)和自定义encode_with.我的问题是:如果我这样删除!ruby/object:Foo:

def encode_with coder
  coder.tag = nil
  ...
end
Run Code Online (Sandbox Code Playgroud)

我能以某种方式继续强迫Psych将地图加载为类的对象Foo(使用它init_with).理想情况下,我也想删除---文档标记.

当然,这很容易解决gsub,但我想知道是否有一些心理解决方案.不幸的是,Psych并不是宝石中最好的记录.

Eug*_*Zol 5

你可以提供自己Handler的心理:

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
Run Code Online (Sandbox Code Playgroud)

一些文档.my_parse只是一个重新实现的Psych 默认解析方法.而不是默认处理程序MyHandler在这里使用.

MyHandlerstart_mapping方法覆盖TreeBuilder默认实现.这是一个回调,当解析器在YAML中碰撞到Map时调用,而文档根 Map.因此,您只需要为根元素交换标记(并且不要为其他所有内容而烦恼 - 这就是我使用@__root变量跳过进一步修改的原因).