
I wanted to parse an AWS SAM template file using Ruby. This format uses [intrinsic](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference.html) functions which can be YAML custom tags, e.g. [!Ref](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-ref.html) to reference a parameter or resource.
How do I parse a YAML custom tag in ruby? There are two options YAML.add_domain_type or YAML.add_tag.
Domain types are **** easier:
require "yaml"``YAML.add_domain_type("", "Ref") do |type, value| value.upcase end``out = YAML.safe_load("test: !Ref value")``puts out # {“test”=>”VALUE”} puts out.to_yaml # test: VALUE
The domain type tag replaces any !Ref tag with the return value of the given block. This can simply return a string or a more complex object.
Tags are a bit more complicated:
`require “yaml”
require “json”class Ref def init_with(coder) [@value](http://twitter.com/value) = coder.scalar end def to_s
@value.upcase
end
endYAML.add_tag("!Ref", Ref)out = YAML.safe_load(“test: !Ref value”, [Ref])``puts out # {“test”=>#<Ref:0x00 @value=”value”>}
puts out.to_yaml
test: !Ref
value: value``puts out.to_json # {“test”:”VALUE”}`
YAML.add_tag replaces !Ref with an instance of the tag class instantiated with init_with(coder) where coder is a Psych::Coder containing the typed value of the tag (in this case a scalar string).
You should always safely parse any user supplied YAML document with safe_load. To allow the YAML parser to instantiate the custom tag classes you have to whitelist them as the second argument to safe_load.
Finish
For simple implementation use add_domain_type, for more complicated solutions use add_tag.
If there is anything I missed please let me know :)
PS
If using the safe_yaml gem, you have to parse using YAML.safe_load("test: !Ref value", nil, {whitelisted_tags: ["!Ref"]})
