YAML(Ruby)loading" on"是的

时间:2015-02-13 19:24:46

标签: ruby yaml

我正在尝试从YAML文件加载单词列表。在文件中有一个条目

- on

Ruby将此加载为" true"而不是" on"。同样地" off"加载为" false"。快速检查心理代码显示"是"和"不"以同样的方式对待。

除了在on和off周围添加引号之外,我有什么办法可以改变这种行为吗?

如果我读取文件并解析,而不是load_file,我能够看到这些值。

# test.yaml
- true
- false
- yes
- no
- on
- off
- y
- n
- Y
- N

我通过解析而不是加载得到一个Psych文档,它在转换为native之前有文本。

YAML.parse_file('test.yaml')

想知道如何正确提取它。

来自文档

"表示阶段表示已组成YAML :: BaseNode对象的数据。在此阶段,文档可用作节点对象树。您可以在此级别执行YPath查询和转换。 (参见YAML :: parse。)"

需要有关编写全面YPath查询以提取数据的帮助。

(PS:这看起来有点迂回,但这为我清理了很多数据管理方面的事情)

4 个答案:

答案 0 :(得分:3)

它列在YAML reference card上,但我在规范中找不到任何引用。

Language Independent Scalar types:
   ...
    { Y, true, Yes, ON  }    : Boolean true
    { n, FALSE, No, off }    : Boolean false
   ...

我认为报价是你唯一的选择。

答案 1 :(得分:1)

正如其他答案中已经解释过的那样,on被视为" truthy"值。此行为是intentionally coded in Psych

正如Arup Rakshit和Mikhail P所解释的那样,问题的最佳解决方案是引用该值。但是,鉴于您的问题要求替代方案,这里有一个替代方案。

Psych中的标量转换在Psych::ScalarScanner#tokenize中是硬编码的。可能(但强烈反对)选项是修改此方法以更改此case statement

    when /^(yes|true|on)$/i
      true
    when /^(no|false|off)$/i
      false

正如您可能已经意识到查看源代码一样,该方法很长,并且猴子补丁会强制您复制/粘贴相当大的代码块。没有简单的方法,选项被硬编码到精选案例中(还有一个迹象表明这不是一个好主意)。

就个人而言,我永远不会这样。修改Psych的核心行为可能会导致一些意想不到的副作用,因为其他库可能依赖于此行为。


如果您不想在物理上修改原始文件,另一个选择是编写一个在运行时更改它的代理。

实际上,您可以创建一个实现parse_file方法的CustomYaml解析器。该方法将读取内存中文件的内容,执行"搜索&替换"任何未转义on"on"的情况,然后感觉YAML.load()

这会欺骗YAML解析,导致它解释每个" on"令牌作为标量字符串。

与此预处理方法类似,您可以通过遍历Psych返回的YAML AST来采用后处理方法。

答案 2 :(得分:0)

正如您所暗示的那样,通过修改AST来使其正常工作。

代码如下:

src = YAML.parse(data)
src.select{ |node| node.is_a?(Psych::Nodes::Scalar) &&
                   %w(on off).include?(node.value) }
  .each{|node| node.quoted = true }

所以基本上,这只是欺骗系统认为引用了值为onoff的所有值节点。这使他们看起来像字符串。

当然,这是依赖于实现的,对于除了Psych之外的其他人,这必须以不同的方式完成。

答案 3 :(得分:0)

这似乎符合我目前的要求。

require 'yaml'

ydoc = YAML.parse_file('test.yaml')
puts ydoc.children.map { |sequence| sequence.children.map { |scalar| scalar.value }}

"孩子"帮助从心理文件向下移动>心理序列>心理标量。

请告诉我你的意见。