Is there a better way to use YAML?

Hi,

I’m trying to use YAML files as a read-only datastore. I have a YAML file with an array of objects. Let’s say Authors. And I have a corresponding Author struct. I’m reading the YAML, looping through each record and returning an Array(Author).

However, I noticed that YAML is deserializing the array as YAML::Any instead of an array of hash (like Ruby). So, I had to typecast to get it to work.

struct Author
  property id, name, email

  def initialize(@id : Int32, @name : String, @email : String)
  end
end
require "yaml"
require "./data_provider"

class YamlDataProvider < DataProvider

  def authors : Array(Author)
    results = Array(Author).new
    yaml = YAML.parse(File.read("../db/authors.yaml"))
    yaml["authors"].as_a.each do |author|
      results << Author.new(
        author["id"].to_i.to_s,
        author["name"].to_s,
        author["email"].to_s
      )
    end
    results
  end
end

Is there a better way to achieve this? Something more idiomatic for Crystal? Am I missing something?

Thanks!

Hi!

You should take a look at YAML::Serializable

Just include YAML::Serializable in your Author type. Then you can do Author.from_yaml(...) or even Array(Author).from_yaml(...) (or Hash, or Author nested in other types, etc.).

For example:

require "yaml"

struct Author
  include YAML::Serializable

  property id, name, email

  def initialize(@id : Int32, @name : String, @email : String)
  end
end

yaml = %(
- id: 1
  name: Foo
  email: foo@example.com
- id: 2
  name: Bar
  email: boo@example.com
)

authors = Array(Author).from_yaml(yaml)
pp authors

See it in play

2 Likes

Thanks! I also saw from the serializable documentation the ? which came in handy for my nullable dates. Thanks again!