RAML.eval

The RAML.eval() method parses a RAML document using the Kernel.eval. In this way Ruby scripting can still be utilized within the document.

Require the RAML library.

require 'raml'

Given a RAML document:

website "http://rubygems.org"

We can load the text via the #load method. (Note above document text has been placed in the @text variable.)

data = RAML.eval(@text)

data.assert == {:website=>"http://rubygems.org"}

One of the nicer features of RAML derives from Ruby’s block notation, allowing for nested entries.

Given a RAML document:

resources do
  home "http://rubyworks.github.com/raml"
  docs "http://rubyworks.github.com/raml/docs/api"
  wiki "http://wiki.rubyworks.github.com/raml"
end

We get a two layer hash.

data = RAML.eval(@text)

data[:resources][:home].assert == "http://rubyworks.github.com/raml"
data[:resources][:docs].assert == "http://rubyworks.github.com/raml/docs/api"
data[:resources][:wiki].assert == "http://wiki.rubyworks.github.com/raml"

RAML is also considers the content of a block. If it is a scalar entry, such as a String, then that will be assigned to the key.

Given a RAML document:

description %{
  This is a description.
  It can have multiple lines.
  RAML handles this just fine,
  because Ruby does too.
}

Loading this document, description will contain the text as expected.

data = RAML.eval(@text)

text = data[:description].sub(/\s+/, ' ').strip

text.assert.start_with?("This is")
text.assert.end_with?("does too.")

It is only unfortunate that Ruby doesn’t have a margin controlled string notation (e.g. `%L{ }`) so that post processing with `sub()` would not be neccessary.

RAML has some options that makes it more flexible than many other data lanaguages. For instance, it can allow for multi-key entries.

Given a RAML document:

source "http://rubygems.org"
gem "facets", "~> 2.8"
gem "ansi", "~> 1.1"

We simply need to inform the loader to allow identical keys.

data = RAML.eval(@text, :multikey=>true)

data.assert == {
  :source=>"http://rubygems.org",
  :gem=>[["facets", "~> 2.8"],["ansi", "~> 1.1"]]
}

If we did not turn on the multi-key option, then the last `gem` entry would have simply overwritten the former.

data = RAML.eval(@text)

data.assert == {
  :source=>"http://rubygems.org",
  :gem=>["ansi", "~> 1.1"]
}

Not let’s show-off the benefit of using RAML.eval instead of RAML.load.

Given a RAML document:

sum 1 + 1

We will see that the value of `sum` will be evaluated as 2.

data = RAML.eval(@text)

data.assert == {:sum=>2}

RAML.read

The RAML.read() method parses a RAML document using Ripper. In this way a RAML document is treated purely as data and cannot contain any Ruby scripting.

Require the RAML library.

require 'raml'

Given a RAML document:

website "http://rubygems.org"

We can load the text via the #read method. (Note above document text has been placed in the @text variable.)

data = RAML.read(@text)

data.assert == {:website=>"http://rubygems.org"}

One of the nicer features of RAML derives from Ruby’s block notation, allowing for nested entries.

Given a RAML document:

resources do
  home "http://rubyworks.github.com/raml"
  docs "http://rubyworks.github.com/raml/docs/api"
  wiki "http://wiki.rubyworks.github.com/raml"
end

We get a two layer hash.

data = RAML.read(@text)

data[:resources][:home].assert == "http://rubyworks.github.com/raml"
data[:resources][:docs].assert == "http://rubyworks.github.com/raml/docs/api"
data[:resources][:wiki].assert == "http://wiki.rubyworks.github.com/raml"

RAML is also considers the content of a block. If it is a scalar entry, such as a String, then that will be assigned to the key.

Given a RAML document:

description %{
  This is a description.
  It can have multiple lines.
  RAML handles this just fine,
  because Ruby does too.
}

Loading this document, description will contain the text as expected.

data = RAML.read(@text)

text = data[:description].sub(/\s+/, ' ').strip

text.assert.start_with?("This is")
text.assert.end_with?("does too.")

It is only unfortunate that Ruby doesn’t have a margin controlled string notation (e.g. `%L{ }`) so that post processing with `sub()` would not be neccessary.

RAML has some options that makes it more flexible than many other data lanaguages. For instance, it can allow for multi-key entries.

Given a RAML document:

source "http://rubygems.org"
gem "facets", "~> 2.8"
gem "ansi", "~> 1.1"

We simply need to inform the reader to allow identical keys.

data = RAML.read(@text, :multikey=>true)

data.assert == {
  :source=>"http://rubygems.org",
  :gem=>[["facets", "~> 2.8"],["ansi", "~> 1.1"]]
}

If we did not turn on the multi-key option, then the last `gem` entry would have simply overwritten the former.

data = RAML.read(@text)

data.assert == {
  :source=>"http://rubygems.org",
  :gem=>["ansi", "~> 1.1"]
}

Not let’s show-off the benefit of using RAML.read instead of RAML.eval.

Given a RAML document:

sum "word".upcase

We will see that the result of calling `#upcase` CANNOT be evaluated and will raise an error.

expect Exception do
  data = RAML.read(@text)
end if RUBY_VERSION >= '1.9'

Note, this last assertion is only true for Ruby 1.9+, becuase Ripper is not supported by older versions of Ruby.