magynhard/yaml_extend

Issues with the order extends work

Closed this issue · 3 comments

As I understand, extends seems to add the extended files at the end of the main file, and not at the beginning.

This is a little counter intuitive (since everywhere else, extend or include means "first use the content of the included file"), and causes issues when using anchors.

Example use case:

This is a valid YAML:

one: &one
  hello: world

menu:
  <<: *one

While this is not a valid YAML:

menu:
  <<: *one

one: &one
  hello: world

So, if I wish to provide "blocks of YAML" that can be used by other blocks, I cannot use the extend functionality. The below example is broken:

# test.rb
require 'yaml_extend'
data = YAML.ext_load_file 'child.yml'
puts data.to_yaml
# child.yml
extends:
- parent.yml

menu:
  <<: *one
  <<: *two
# parent.yml
one: &one
  hello: world

two: &two
  hi: world
  hey: world

I know there are other ways around it, but my use case was more naturally implemented with anchors, and now I know they cannot be used this way.

Is there any reason for the included content to come last and not first?

Hi @DannyBen, thank you very much for your issue ticket.

Is there any reason for the included content to come last and not first?

My assumption was that no one would use anchors with file inheritance anyway, as that would bring much more complexity. That's why I didn't consider anchors and the order here at all.

But you would do! ;-)

Then we not only have to adjust the order, but also update the anchors once everything is loaded, which means we have to parse the assembled YAML file again.

Does this suit your ideas or did I forget to consider something else?

Well, I vote for simplicity almost above all else. So unless this change is very simple to do, I would not do it.

What I had in mind initially - but perhaps I am wrong and it is NOT how yaml_extend works - is that it might be just a matter of changing the order of where you use yaml1.merge yaml2.

In any case, I would not do anything that is specific to anchors, since these are internal YAML constructs - so we let YAML handle it.

I was hoping that somewhere in your code, there is a #merge call that can be switched, perhaps to demonstrate:

require 'yaml'

yaml1 = { one: 1 }
yaml2 = { two: 2 }

p yaml1.merge yaml2
p yaml2.merge yaml1

#=> {:one=>1, :two=>2}
#=> {:two=>2, :one=>1}

As a side note - for my particular case, I solved it by having the main YAML file include ONLY extend directive, so the order of the files in the extend match the order of things as I want them. It is not exactly what I wanted, but it is sufficient.

I might take a look at your code later, to see if I can come up with something interesting.

I am closing this. I realize that since the YAML is evaluated to find its extends, it cannot contain anchors that reference not-yet-loaded definintions.