Type Families

Typing is YAML's most extensible feature. YAML.rb is setup to handle Ruby objects under the ruby.yaml.org domain. When a document is loaded containing an object flagged with the type !ruby/symbol, the parser knows to handle this object inside of YAML.rb. Other programming languages likely don't have handlers for !ruby types. You may want to create your own type families to pass to other languages.

Loading a Type Family with a Domain

Your type families must be classified with a domain. For example, if you were the owner of 'rubyjunkies.com', then might want to categorize your types under that domain. A YAML document using your own custom address book could look like this:

--- !rubyjunkies.com,2002-10-24/addressBook
name: Bunbury Olsen
phone: 801-090-0900
address: |
  12 E. 400 S.
  SLC, UT 84020
Ex. 31: Custom type family assigned to a domain

A type family can be loaded however you choose. Using the YAML.add_domain_type method, you can register a new type, such as the address book type above:

YAML.add_domain_type( "rubyjunkies.com,2002-10-24", "addressBook" ) { |type, val|
  # Do something with 'val' here
}
Ex. 32: Registering the address book type with YAML.add_domain_type

In most cases, you'll want to map a type family directly to a class. Your address book type likely has an AddressBook class counterpart with 'name', 'phone', and 'address' attributes. The YAML.object_maker method can be used to automate your type family handler.

class AddressBook
  attr_accessor :name, :phone, :address
end

YAML.add_domain_type( "rubyjunkies.com,2002-10-24", "addressBook" ) { |type, val|
  YAML.object_maker( AddressBook, val )
}
Ex. 33: YAML.add_domain_type and YAML.object_maker
Emitting a Type Family with a Domain

So you're now covered to load your custom YAML type into a class. But you'll also need a to_yaml method to emit this class under your domain type. The default to_yaml method for the AddressBook class will emit as type family "!ruby/Object:AddressBook". To emit as type family "!rubyjunkies.com,2002-10-24/addressBook", you can overload the to_yaml method:

class AddressBook
  def to_yaml( opts = {} )
    YAML.quick_emit( self.id, opts ) { |out|
      out.map( "!rubyjunkies.com,2002-10-24" ) { |map|
        instance_variables.sort.each { |iv|
          map.add( iv[1..-1], instance_eval( iv ) )
        }
      }
    }
  end
end
Ex. 34: Overloading to_yaml for your type family

The above code is quite verbose and we'll go into a quicker technique in the next example. But this example does illustrate a few other methods which are at you disposal in customizing the to_yaml method.

The YAML.quick_emit method takes two parameters: the Object id and the options hash. The id helps YAML.rb detect duplicates in the stream, supplying an anchor for the duplicated object. If you don't want to use an anchor, merely pass nil in as the id.

For most objects, though you may just want to emit a custom type name. In this case, merely overload the to_yaml_type method in your class.

def to_yaml_type
  "!rubyjunkies.com,2002-10-24/addressBook"
end
Ex. 35: Quicker to_yaml_type for classes

Another popular request among developers who use object type families concerns ordering of properties. Not only ordering the properties displayed in the YAML document, but also suppressing properties.

By overloading the to_yaml_properties method, you can control which properties are emitted and in which order. The to_yaml_properties method should return an array of property names, along with their '@' prefix.

To order the @name, @phone, and @address properties:

def to_yaml_properties
  [ '@name', '@phone', '@address' ]
end
Ex. 36: Overloading to_yaml_properties