How to YAML

It is no secret, I’m enjoying Octopress! I’ve been tweaking Octopress to better suite my needs and make my process even simpler. In my effort to build a couple custom rake tasks for my Octopress fork I required the ability to read a few properties from the _config.yaml file. Before we dive into the code, what is YAML anyway? YAML stands for YAML Ain’t Markup Language and it is a versatile human friendly data serialization format. Some people believe YAML is easier to use and understand than JSON. That might be true, but I believe they serve two different purposes.

YAML is a simple human readable store of name/value pairs. You could compare it to an INI file, some also compare it to a Java properties file. Comparing YAML to JSON, you can, they both store name/value pairs or collections of but JSON is the accepted data transport for the web. When you think of RESTful services or even AJAX calls, I do not think of YAML for data transport, I think of JSON. Why? Because JavaScript understands JSON natively, not YAML. There are JavaScript YAML parsers available, like this js-yaml and checkout js-yaml online. In the same respect, dealing with configuration files, I think of YAML, XML or INI files not JSON.

Here is a simple YAML file to store values for root, url_base, and disqus_developer. In the Octopress world this file is called _config.yml, you name it anything you’d like just ensure it has .yml extension.

root: /
url_base: http://i-m-code.com/blog/
disqus_developer: 0

Open your favorite editor, mine is Sublime Text 2, create a new file, save it as Rakefile. Now add the below code to create your first Rake task to output the values in your YAML file. Open a terminal, navigate to the directory, run bundle exec rake burst to execute the task.

Rakefile burst
1
2
3
4
5
6
7
8
9
10
require "rubygems"
require "bundler/setup"

desc "My first Rake task to read and output a YAML file."
task :burst do
  yml = YAML::load(File.open('_config.yml'))
  puts yml['root'] # /
  puts yml['url_base'] # http://i-m-code.com/blog/
  puts yml['disqus_developer'] # 0
end

Well, that is really not too useful. Instead, to output all the name/value pairs in a YAML file update the Rake task to take in a parameter ( yamlfile ). Then loop through the yml name/value collection using each_pair using puts to output the key and value. Open a terminal, navigate to the directory, run bundle exec rake burst_loop[“_config.yml”] to execute the task.

Rakefile burst_loop["_config.yml"]
1
2
3
4
5
6
7
8
desc "My first Rake task to read and output a YAML file."
task :burst_loop, :yamlfile do |t,args|
  raise "### You must specify a YAML file name." unless args[:yamlfile]
  yml = YAML::load(File.open(args.yamlfile))
  yml.each_pair { |key, value|
    puts "#{key} = #{value}"
  }
end

Use the code below to write to the YAML file. Open a terminal, navigate to the directory, run bundle exec rake burst_write[“_config-write.yml”,“mykey:myvalue”] to execute the task. You can also do it like this bundle exec rake burst_write[“_config-write.yml”,“{‘mykey’ => ‘myvalue’}”]. Of course you can send in more complex data like a class or a stream.

Rakefile burst_write["yaml_file","yamldata"]
1
2
3
4
5
6
7
8
desc "Rake task to write YAML to a new YAML file."
task :burst_write, :yamlfile, :yamldata do |t,args|
  raise "### You must specify a YAML file name." unless args[:yamlfile]
  raise "### You must specify a YAML data." unless args[:yamldata]
  File.open(args.yamlile, 'w') do |out|
    YAML::dump(args.yamldata, out)
  end
end

What about merging two configuration files using YAML. First, create a new config-default.yml and config-dev.yml file in the directory root of the Rakefile you are working with. Next open each in editor of choice, add a few name/value pairs in config-default.yml and config-dev.yml as seen below then save.

_config-default.yml

team: 49ners
winner: no
root: /blog
url_base: http://i-m-code.com/blog/

_config-dev.yml

root: /
url_base: http://localhost:4000/blog/
disqus_developer: 0

Now you are ready to test the the Rake task below. Open a terminal, navigate to the directory, run bundle exec rake burst_merge[“config-default.yml”, “config-dev.yml”] to execute the task.

Rakefile burst_merge["yaml_file1" "yaml_file2"]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
desc "Rake task to merge two YAML files into one output YAML file."
task :burst_merge, :yamlfile1, :yamlfile2 do |t,args|
  raise "### You must specify a YAML file 1 name." unless args[:yamlfile1]
  raise "### You must specify a YAML file 2 name." unless args[:yamlfile2]
  outputfile = '_config-test.yml'
  puts "## Generating #{outputfile} from #{args.yamlfile1} and #{args.yamlfile2}"

  config = YAML::load( File.open(args.yamlfile1) )
  config_mode = YAML::load( File.open(args.yamlfile2) )
  config.merge!( config_mode )
    File.open( outputfile, 'w') do |f|
    f.puts("# Generated file. Do not edit")
    f.write(config.to_yaml)
  end
end

After merging the two YAML files _config-test.yml output will look like this.

team: 49ners
winner: no
root: /
url_base: http://localhost:4000/blog/
disqus_developer: 0

A more detailed tutorial.

Comments