在YAML中使用Ruby的别名

时间:2015-09-28 19:08:43

标签: ruby yaml

我有以下YAML:

- PRO_PLAN:
  - description: This is the Pro plan
    publicName: Pro Plan
    startDate: 12-20-2015

  - PRO_MONTHLY_DIRECT:
    - publicName: Pro Monthly 
      price: 20
      sub_target: zone

    - PRICING_COMPONENTS: &pro_entitlements
      analytics_range: 21600
      rules: 10
      cannon: true


  - PRO_ANNUAL_DIRECT:
    - publicName: Pro Annual  
      price: 240
      sub_target: zone

    - PRICING_COMPONENTS:
      <<: *pro_entitlements

结果数组不会为第二个节点引入pro_entitlements

[8] pry(BF)> app_hash[0]['PRO_PLAN'][1]
=> {"PRO_MONTHLY_DIRECT"=>[{"publicName"=>"Pro Monthly", "price"=>20, "sub_target"=>"zone"}, {"PRICING_COMPONENTS"=>nil, "analytics_range"=>21600, "page_rules"=>10, "polish"=>true}]}
[9] pry(BF)> app_hash[0]['PRO_PLAN'][2]
=> {"PRO_ANNUAL_DIRECT"=>[{"publicName"=>"Pro Annual", "price"=>240, "sub_target"=>"zone"}, {"PRICING_COMPONENTS"=>nil, "<<"=>nil}]}

4 个答案:

答案 0 :(得分:4)

当我需要构建一个更复杂的YAML文档时,我通常首先使用Ruby和Ruby的Hash和Array对象。 YAML序列化程序知道如何构建别名和锚点,如果我们允许的话,它将会这样做:

require 'yaml'

foo = {'foo' => 1}
bar = {'bar' => 2, 'foo' => foo}
baz = {'baz' => 3, 'foo' => foo}

puts [foo, bar, baz].to_yaml

# >> ---
# >> - &1
# >>   foo: 1
# >> - bar: 2
# >>   foo: *1
# >> - baz: 3
# >>   foo: *1

这里为foo数组创建了一个别名,然后在序列化哈希数组时引用它。

对你的YAML使用相同的想法:

require 'yaml'

PRO_ENTITLEMENTS = {
  'analytics_range' => 21600,
  'rules'           => 10,
  'cannon'          => true
}

doc = [
  {
    'PRO_PLAN' => 
    [
      {
        'description' => 'This is the Pro plan',
        'publicName'  => 'Pro Plan',
        'startDate'   => '12-20-2015'
      },
      {
        'PRO_MONTHLY_DIRECT' => 
        [
          {
            'publicName' => 'Pro Monthly',
            'price'      => 20,
            'sub_target' => 'zone'
          },
          {
            'PRICING_COMPONENTS' => PRO_ENTITLEMENTS,
            'analytics_range'    => 21600,
            'rules'              => 10,
            'cannon'             => true
          }
        ]
      },
      {
        'PRO_ANNUAL_DIRECT' => 
        [
          {
            'publicName' => 'Pro Annual',
            'price'      => 240,
            'sub_target' => 'zone'
          },
          {
            'PRICING_COMPONENTS' => PRO_ENTITLEMENTS,
          }
        ]
      }
    ]
  }
]

puts doc.to_yaml

运行它会返回:

---
- PRO_PLAN:
  - description: This is the Pro plan
    publicName: Pro Plan
    startDate: 12-20-2015
  - PRO_MONTHLY_DIRECT:
    - publicName: Pro Monthly
      price: 20
      sub_target: zone
    - PRICING_COMPONENTS: &1
        analytics_range: 21600
        rules: 10
        cannon: true
      analytics_range: 21600
      rules: 10
      cannon: true
  - PRO_ANNUAL_DIRECT:
    - publicName: Pro Annual
      price: 240
      sub_target: zone
    - PRICING_COMPONENTS: *1

这不能保证是您正确使用的输出,只是如何在Ruby中构建结构并让YAML输出它的示例,以便您可以看到序列化后它应该是什么样子。

我们可以进行往返测试:

YAML.load(doc.to_yaml)
# => [{"PRO_PLAN"=>
#       [{"description"=>"This is the Pro plan",
#         "publicName"=>"Pro Plan",
#         "startDate"=>"12-20-2015"},
#        {"PRO_MONTHLY_DIRECT"=>
#          [{"publicName"=>"Pro Monthly", "price"=>20, "sub_target"=>"zone"},
#           {"PRICING_COMPONENTS"=>
#             {"analytics_range"=>21600, "rules"=>10, "cannon"=>true},
#            "analytics_range"=>21600,
#            "rules"=>10,
#            "cannon"=>true}]},
#        {"PRO_ANNUAL_DIRECT"=>
#          [{"publicName"=>"Pro Annual", "price"=>240, "sub_target"=>"zone"},
#           {"PRICING_COMPONENTS"=>
#             {"analytics_range"=>21600, "rules"=>10, "cannon"=>true}}]}]}]

答案 1 :(得分:0)

我不是YAML大师,但看起来你使用了错误的语法。试试这个:

-
  PRO_PLAN:
    -
      description: "This is the Pro plan"
      publicName: "Pro Plan"
      startDate: 12-20-2015
    -
      PRO_MONTHLY_DIRECT:
        -
          price: 20
          publicName: "Pro Monthly"
          sub_target: zone
        -
          PRICING_COMPONENTS: &pro_entitlements
            -
              analytics_range: 21600
              cannon: true
              rules: 10
              works: true
    -
      PRO_ANNUAL_DIRECT:
        -
          price: 240
          publicName: "Pro Annual"
          sub_target: zone
        -
          PRICING_COMPONENTS:
            -
              <<: *pro_entitlements

答案 2 :(得分:0)

似乎正确的语法是为Hash的子PRICING_COMPONENTS添加缩进:

---
- PRO_PLAN:
  - description: This is the Pro plan
    publicName: Pro Plan
    startDate: 12-20-2015

  - PRO_MONTHLY_DIRECT:
    - publicName: Pro Monthly 
      price: 20
      sub_target: zone

    - PRICING_COMPONENTS: &pro_entitlements
        analytics_range: 21600
        rules: 10
        cannon: true

  - PRO_ANNUAL_DIRECT:
    - publicName: Pro Annual  
      price: 240
      sub_target: zone

    - PRICING_COMPONENTS:
        <<: *pro_entitlements

或者如上一个人所述,添加Array短划线而非Hash缩进。

答案 3 :(得分:0)

我认为ruby YAML解析器无法检测到错误。如果您尝试在我的ruamel.yaml解析器上进行往返(基于Python,这将保留别名/锚名称和<<<),那么

expected a mapping or list of mappings for merging, but found scalar   
   in "<byte string>", line 11, column 27:  
        - PRICING_COMPONENTS: &pro_entitlements
                              ^

表示其余的PRICING_COMPONENTS是由键/值对的非缩进引起的标量(null)。

你甚至不需要使用python或我的解析器,你可以check online你使用的解析器不会抛出错误。

原因是YAML文件的映射可以为空值。而你没有缩进analytics_range: 21600会使整个序列元素

- PRICING_COMPONENTS: &pro_entitlements
  analytics_range: 21600
  rules: 10
  cannon: true

由单个地图组成的单个序列元素,而不是由PRICING_COMPONENTS地图组成的单个元素,以及其下方三个值的映射。在您的情况下,pro_elements是null值的锚点,由PRICING_COMPONENTS的空值引起。 所以这都是“正常的”,虽然不是你想要的。

解析器出错的地方就是使用:<<应该在没有指向映射锚点的别名上抛出错误,因为文档指定mappings to be merged