The tiny representable gem got some improvements recently. Not only did we refactor the internals to make it easier adding new representation engines, we also used that to give you a new format: YAML!
YAML, Who Needs YAML?
I use YAML very rarely. But sometimes clients happen to require it, or an API might be based on this format. Let’s make the world a better place and support it in representable!
Consider the following domain class.
require 'ostruct' class Song < OpenStruct end song = Song.new(:title => "Scarified", :track => 4)
To render this into YAML a simple representer is needed.
module SongRepresenter include Representable::YAML property :title property :track end
Note the usage of the Representable::YAML module. After injecting, the domain object is fully equipped with #to_yaml and #from_yaml.
puts song.extend(SongRepresenter).to_yaml # => " --- title: Scarified track: 4"
As always, this works also with parsing.
song = Song.new.extend(SongRepresenter) song.from_yaml("--- title: Jackhammer track: 5 ") puts song.inspect #=> #<Song title="Jackhammer", track=5>
Nested Models? Not A Big Deal.
Often you may want to represent nested setups – where models contain models. This has always been a key feature in representable.
class Album < OpenStruct end module AlbumRepresenter include Representable::YAML property :name collection :songs, :extend => SongRepresenter, :class => Song end
Since an Album contains a list of Songs we wanna represent those embedded objects with the SongRepresenter we already wrote.
Seting up a demo album, first.
album = Album.new(:songs => [ Song.new(:title => "Scarified", :track => 4), Song.new(:title => "Jackhammer", :track => 5) ])
The YAML representer will now create a proper YAML document for the nested objects.
album.extend(AlbumRepresenter).to_yaml #=> "--- songs: - title: Scarified track: 4 - title: Jackhammer track: 5"
See how easy that is?
And Finally: Flow-Style Lists.
Another cool feature is the ability to declare collections as flow-style which is an official part of the YAML specification but only very poorly implemented in available YAML gems.
Usually, lists are rendered in the block style.
class HotBands < OpenStruct end module HotBandsRepresenter include Representable::YAML property :for collection :names end
After creating and rendering one of those HotBands, the names list is rendered in block style – the default in all YAML gems.
HotBands.new(:for => "Nick", :names => [ "Bad Religion", "Van Halen", "Mozart" ]).extend(HotBandsRepresenter).to_yaml #=> "--- for: Nick names: - Bad Religion - Van Halen - Mozart"
Now, if you don’t like that style where one list item is displayed per line, you might want to switch to the oh-so-flowing flow style.
module HotBandsRepresenter include Representable::YAML property :for collection :names, :style => :flow end
By using the :style => :flow option in the collection you can achieve just that!
hotties.to_yaml #=> "--- for: Nick names: [Bad Religion, Van Halen, Mozart]"
Check how it flows. That is just awesome.
Introducing The Hash Representer.
We did a little bit of internal refactorings cleaning up representable. What came out is the new hash representer which gives basic functionality to most of the other representer engines. It can also be helpful if you want to parse incoming form data or use the params hash from Rails or Sinatra to fill your objects.
Consider this representer.
require 'representable/hash' module BandRepresenter include Representable::Hash property :name property :label end
This representer can read and write plain Ruby hashes. Sounds stupid? It is! However, what if you wanna use Rails’ params hash to update a model?
params = {"band" => {"name" => "Paul Gilbert", "label" => "n/a"}}
This could be a form Rails (or Sinatra) automatically parsed for you. Now let’s use that on a new Band instance.
band = Band.new.extend(BandRepresenter). from_hash(params["band"])
Note that this could be an existing Band instance, too, as from Band.find(params[:id]).
Inspecting the result of our “parsing” we see that it actually works.
band.inspect #=> #<Band name="Paul Gilbert", label="n/a">
This new hash representer is especially helpful for using representers with forms.
One Module, Multiple Representers
Another nice little cleanup lets you include different representer engines into a single module, so you can transform to and from different media types.
module BandRepresenter include Representable::JSON include Representable::XML
This would give your objects the power of both XML and JSON.
More To Come.
In the next release we’re planning readable/writeable policy support, polymorphic collections, letting you pass arguments to the represented accessors if you need that and more stuff I already forgot. Let us know if you need anything more, and ¡Salud!
