Use YAML with variables

134,034

Solution 1

I had this same question, and after a lot of research, it looks like it's not possible.

The answer from cgat is on the right track, but you can't actually concatenate references like that.

Here are things you can do with "variables" in YAML (which are officially called "node anchors" when you set them and "references" when you use them later):

Define a value and use an exact copy of it later:

default: &default_title This Post Has No Title
title: *default_title

{ or }

example_post: &example
  title: My mom likes roosters
  body: Seriously, she does. And I don't know when it started.
  date: 8/18/2012
first_post: *example
second_post:
  title: whatever, etc.

For more info, see this section of the wiki page about YAML: http://en.wikipedia.org/wiki/YAML#References

Define an object and use it with modifications later:

default: &DEFAULT
  URL:          stooges.com
  throw_pies?:  true  
  stooges:  &stooge_list
    larry:  first_stooge
    moe:    second_stooge
    curly:  third_stooge

development:
  <<: *DEFAULT
  URL:      stooges.local
  stooges: 
    shemp: fourth_stooge

test:
  <<: *DEFAULT
  URL:    test.stooges.qa
  stooges: 
    <<: *stooge_list
    shemp: fourth_stooge

This is taken directly from a great demo here: https://gist.github.com/bowsersenior/979804

Solution 2

After some search, I've found a cleaner solution wich use the % operator.

In your YAML file :

key : 'This is the foobar var : %{foobar}'

In your ruby code :

require 'yaml'

file = YAML.load_file('your_file.yml')

foobar = 'Hello World !'
content = file['key']
modified_content = content % { :foobar => foobar }

puts modified_content

And the output is :

This is the foobar var : Hello World !

As @jschorr said in the comment, you can also add multiple variable to the value in the Yaml file :

Yaml :

key : 'The foo var is %{foo} and the bar var is %{bar} !'

Ruby :

# ...
foo = 'FOO'
bar = 'BAR'
# ...
modified_content = content % { :foo => foo, :bar => bar }

Output :

The foo var is FOO and the bar var is BAR !

Solution 3

This is an old post, but I had a similar need and this is the solution I came up with. It is a bit of a hack, but it works and could be refined.

require 'erb'
require 'yaml'

doc = <<-EOF
  theme:
  name: default
  css_path: compiled/themes/<%= data['theme']['name'] %>
  layout_path: themes/<%= data['theme']['name'] %>
  image_path: <%= data['theme']['css_path'] %>/images
  recursive_path: <%= data['theme']['image_path'] %>/plus/one/more
EOF

data = YAML::load("---" + doc)

template = ERB.new(data.to_yaml);
str = template.result(binding)
while /<%=.*%>/.match(str) != nil
  str = ERB.new(str).result(binding)
end

puts str

A big downside is that it builds into the yaml document a variable name (in this case, "data") that may or may not exist. Perhaps a better solution would be to use $ and then substitute it with the variable name in Ruby prior to ERB. Also, just tested using hashes2ostruct which allows data.theme.name type notation which is much easier on the eyes. All that is required is to wrap the YAML::load with this

data = hashes2ostruct(YAML::load("---" + doc))

Then your YAML document can look like this

doc = <<-EOF
  theme:
  name: default
  css_path: compiled/themes/<%= data.theme.name %>
  layout_path: themes/<%= data.theme.name %>
  image_path: <%= data.theme.css_path %>/images
  recursive_path: <%= data.theme.image_path %>/plus/one/more
EOF

Solution 4

This is how I was able to configure yaml files to refer to variable.

I have values.yaml where we have root level fields which are used as template variables inside values.yaml

values.yaml

.....  
databaseUserPropName: spring.datasource.username  
databaseUserName: sa  
.....  
secrets:
    type: Opaque  
    name: dbservice-secrets  
    data:  
      - name: "{{ .Values.databaseUserPropName }}"  
        value: "{{ .Values.databaseUserName }}"  
.....

When referencing these values in secret.yaml, we would use tpl function using syntax {{ tpl TEMPLATE_STRING VALUES }}

secret.yaml

when using inside range i:e iteration

  {{ range .Values.deployments.secrets.data }}
    {{ tpl .name $ }}: "{{ tpl .value $ }}"
  {{ end }}

when directly referring as variable

  {{ tpl .Values.deployments.secrets.data.name . }}
  {{ tpl .Values.deployments.secrets.data.value . }}

$ - this is global variable and will always point to the root context . - this variable will point to the root context based on where it used.

Solution 5

if your requirement is like parsing an replacing multiple variable and then use it as a hash/or anything then you can do something like this

require 'yaml'
require 'json'
yaml = YAML.load_file("xxxx.yaml")
blueprint = yaml.to_json % { var_a: "xxxx", var_b: "xxxx"}
hash = JSON.parse(blueprint)

inside the yaml just put variables like this

"%{var_a}"
Share:
134,034
brewster
Author by

brewster

Updated on October 18, 2021

Comments

  • brewster
    brewster over 2 years

    Are variables within YAML files possible? For example:

    theme:
      name: default
      css_path: compiled/themes/$theme.name
      layout_path: themes/$theme.name
    

    In this example, how can theme: name: default be used in other settings? What is the syntax?