Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

More complex inheritance in YAML?

YAML has inheritance. The most clear example I have ever seen is here: http://blog.101ideas.cz/posts/dry-your-yaml-files.html

I need something more complex: I need to override object's object's property. Here is an example:

database: &default   server:     ip: 192.168.1.5     port: 2000   db_name: test   user:      name: root     password: root  # database foo differs from default by only its port and user password foo_database:   <<: *default   server:     port: 2001   db_name: foo   user:     password: foo_root 

I want to get this result:

foo_database.server.ip -> 192.168.1.5 foo_database.server.port -> 2001 foo_database.db_name -> foo foo_database.user.name -> root foo_database.user.password -> foo_root 

But if you declare like this, you will get these properties incorrect (according to expected values):

foo_database.server.ip -> will be None foo_database.user.name -> will be None 

because new "server" object has only "port" property and it overrides whole old "server" object.

How do I get the kind of inheritance which I want to achieve?

Edit

Here is my exact intention with a working code in LiveScript:

config =    default:      ip: \192.168.1.5     port: 2000     name: \root      password: \root      db:       name: \default       location: \LA    foo-database:~ -> @default `merge` do      ip: \11.11.11.11     db:       name: \my-foo     bar-database:~ -> @foo-database `merge` do      password: \1234      db:       location: \SF  config.default  # => {"ip":"192.168.1.5","port":2000,"name":"root","password":"root","db":{"name":"default","location":"LA"}} config.foo-database   # => {"ip":"11.11.11.11","port":2000,"name":"root","password":"root","db":{"name":"my-foo","location":"LA"}} config.bar-database   # => {"ip":"11.11.11.11","port":2000,"name":"root","password":"1234","db":{"name":"my-foo","location":"SF"}} 
like image 514
ceremcem Avatar asked Jan 06 '13 17:01

ceremcem


People also ask

Does YAML support inheritance?

Unfortunately, you can't get the kind of "inheritance" you want to achieve because YAML's "inheritance" is more like a form of "merging hashes".

What is <<: In YAML file?

The <<: inserts the content of that node. Repeated nodes (objects) are first identified by an anchor (marked with the ampersand - “&”), and are then aliased (referenced with an asterisk - “*”) thereafter.

Can I include a YAML file inside another?

No, YAML does not include any kind of "import" or "include" statement. You could create a ! include <filename> handler.

Does ordering matter in YAML?

In general the order of keys in a YAML file does not matter. Neither do blank lines. Indentation may be with any number of spaces, as long as it is consistent throughout the file.


1 Answers

Unfortunately, you can't get the kind of "inheritance" you want to achieve because YAML's "inheritance" is more like a form of "merging hashes".

Expanding out your configuration at the point you use the *default alias, you have:

foo_database:   server:     ip: 192.168.1.5     port: 2000   db_name: test   user:      name: root     password: root 

If you use hashes with the same keys afterwards, they will completely overwrite the hashes declared earlier, leaving you with (excuse the formatting):

foo_database: 

  server:     ip: 192.168.1.5     port: 2000   db_name: test   user:     name: root    password: root   

  server:     port: 2001   db_name: foo   user:     password: foo_root 

So, in your case, it would seem that since the config is not exactly the same, DRYing up your configuration using anchors and aliases probably isn't the right approach.

More references on this issue below:

  • Rake, YAML and Inherited Build Configuration
  • Merging hashes in yaml conf files

Edit

If you really wanted to, I think you could reconfigure your YAML as below to get exactly what you want, but in your case, I would say the extra obfuscation isn't worth it:

server_defaults: &server_defaults   ip: 192.168.1.5   port: 2000  user_defaults: &user_defaults   name: root   password: root  database: &default   server:     <<: *server_defaults   db_name: test   user:      <<: *user_defaults  foo_database:   <<: *default   server:     <<: *server_defaults     port: 2001   db_name: foo   user:     <<: *user_defaults     password: foo_root 
like image 160
Paul Fioravanti Avatar answered Sep 20 '22 14:09

Paul Fioravanti