Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can one YAML object refer to another?

Tags:

ruby

yaml

I'd like to have one yaml object refer to another, like so:

intro: "Hello, dear user."

registration: $intro Thanks for registering!

new_message: $intro You have a new message!

The above syntax is just an example of how it might work (it's also how it seems to work in this cpan module.)

I'm using the standard ruby yaml parser.

Is this possible?

like image 391
John Bachir Avatar asked Jun 29 '10 14:06

John Bachir


People also ask

Can YAML reference another YAML?

No, standard YAML does not include any kind of "import" or "include" statement. You could create a ! include <filename> handler. @clarkevans sure, but that construct would be "outside" the YAML language.

Can a YAML file reference itself?

JSON. YAML 1.2 is a superset of JavaScript Object Notation (JSON) but has some built-in advantages. For example, YAML can self-reference, support complex datatypes, embed block literals, support comments, and more.

Does YAML support inheritance?

With this directive, you can inherit from an existing registered definition item in order to create a new definition item.

How do I merge YAML files?

Yaml files can be merged using the 'merge' command. Each additional file merged with the first file will set values for any key not existing already or where the key has no value.


2 Answers

Some yaml objects do refer to the others:

irb> require 'yaml'
#=> true
irb> str = "hello"
#=> "hello"
irb> hash = { :a => str, :b => str }
#=> {:a=>"hello", :b=>"hello"}
irb> puts YAML.dump(hash)
---
:a: hello
:b: hello
#=> nil
irb> puts YAML.dump([str,str])
---
- hello
- hello
#=> nil
irb> puts YAML.dump([hash,hash])
---
- &id001
  :a: hello
  :b: hello
- *id001
#=> nil

Note that it doesn't always reuse objects (the string is just repeated) but it does sometimes (the hash is defined once and reused by reference).

YAML doesn't support string interpolation - which is what you seem to be trying to do - but there's no reason you couldn't encode it a bit more verbosely:

intro: Hello, dear user
registration: 
- "%s Thanks for registering!"
- intro
new_message: 
- "%s You have a new message!"
- intro

Then you can interpolate it after you load the YAML:

strings = YAML::load(yaml_str)
interpolated = {}
strings.each do |key,val|
  if val.kind_of? Array
    fmt, *args = *val
    val = fmt % args.map { |arg| strings[arg] }
  end
  interpolated[key] = val
end

And this will yield the following for interpolated:

{
  "intro"=>"Hello, dear user", 
  "registration"=>"Hello, dear user Thanks for registering!", 
  "new_message"=>"Hello, dear user You have a new message!"
}
like image 105
rampion Avatar answered Sep 18 '22 23:09

rampion


Rather than trying to use implicit references in your yaml, why don't you use substitution strings (like you show above, you need quotes though) and explicitly substitute the contents of them at parse time?

like image 42
Jason S Avatar answered Sep 17 '22 23:09

Jason S