0

I would like to parse the YAML

foo: &foo
  - a: 1
bar: 
  <<: *foo

When I try to do this using ruby's YAML I get an odd result:

YAML.load("
foo: &foo
  - a: 1
bar: 
  <<: *foo
")

=> {"foo"=>[{"a"=>1}], "bar"=>{"<<"=>[{"a"=>1}]}}

Note the appearance of the odd <<. I would have expected

   {"foo"=>[{"a"=>1}], "bar"=>[{"a"=>1}]} 

Am I misunderstanding how to use the YAML syntax?

In case relevant:

ENV['RBENV_VERSION']
=> "2.4"
YAML.libyaml_version
=> [0, 1, 4]

I'm also a bit suspicious of my syntax because when I plug this into an online yaml parser I get different output , but also different from what I expect:

{
  "foo": [{"a": 1}],
  "bar": {"a": 1}
}

(sorry, that's json -- but the point is that in the bar values is not wrapped in array brackets as I would expect.

brahn
  • 12,096
  • 11
  • 39
  • 49
  • It seems that in Ruby, only one part of merge key was implemented. Your second example is the correct one. That's what the merge key does, it results in a mapping, not a sequence of mappings. – tinita Jan 12 '18 at 08:50

2 Answers2

1

It seems that you cannot use arrays as top level keys when merging. If you create a new rails app, you can see rails using this pattern inside config/database.yml (here's a snippet)

# config/database.yml

default: &default
  adapter: postgresql

development:
  <<: *default

In the example above it works fine, but see there's no array right below the default key.

In order for you code to work fine, you should wrap your array inside another key, like so:

# example.yml
foo: &foo
  list:
    - a: 1
bar:
  <<: *foo

And then you'll get:

YAML.load_file('example.yml')
#=> {"foo"=>{"list"=>[{"a"=>1}]}, "bar"=>{"list"=>[{"a"=>1}]}}

As you can see, the main problem is using arrays without wrapping them into a parent key.

Jonathan Duarte
  • 753
  • 5
  • 9
  • Thanks! Maybe the feature request to the YAML gem folks would be to reject the original syntax as a parse error rather than doing something weird... – brahn Jan 12 '18 at 16:25
0

OK I think I found the answer in this question: https://stackoverflow.com/a/4949139/239712 . Namely,

...it's not defined what the merge does. Per the spec, a merge key can have a value:

  • A mapping, in which case it's merged into the parent mapping.
  • A sequence of mappings, in which case each is merged, one-by-one, into the parent mapping.

There's no way of merging sequences.

brahn
  • 12,096
  • 11
  • 39
  • 49