image

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"]})