2015 twenty-four merry days of Perl Feed

Garlands of YAML and JSON

File::Serialize - 2015-12-15

Gluggagægir the Elf had to admit that the myriad of IT systems that worked together at the North Pole was amazing. All built different, in different languages, and with different technologies. Luckily, the Elves had decided that everyone should use a universal serialization format so that all the different systems could talk to each other. Unfortunately, however, none of the elves could agree what that should be, and they'd all ended up using a different universal serialization format.

While some elves are working at Santa's Gift Factories for a Holidays season or two before they move to greener pastures (usually quite literally greener, as the Easter Bunny is notoriously known to be the biggest elf poacher around) Gluggagægir is one of your long-term commitment type of elf. He's been around and worked in most departments, and expects to be around longer still, slowly moving up the yuletide ladder until — who knows? — he makes it as Cheers Chief Officer.

So Glugg has made the decision not to argue with the trend du jour, whatever that might be. Why can't we just accept input in any of the contested serialization formats and have the computer, which is pretty smart at processing data, figure it all out?

The current hot debate was should the elves be serializing data in either YAML or JSON, both of which are readable and fairly easy to manipulate. Either was perfectly fine with Glugg, as he's an old-hand to the serialization/deserialization dance. And happens to have one more handy tool on his belt for those tasks: File::Serialize.

Keep it short, keep it sweet

The main raison d'être of File::Serialize is to encapsulate and take care of all the boring, repetitive details that come with serialization. Before using File::Serialize, Glugg used to have two scripts that looked like

use NorthPole::DB;
use YAML;

my $nice_children = YAML::LoadFile( 'nice.yaml' );

update_db( nice => $nice_children );

and

use NorthPole::DB;
use JSON;
use Path::Tiny;

my $naughty_children = from_json path('naughty')->slurp;

update_db( naughty => $naughty_children );

In other words, almost the same, except for the serialization engine. But with File::Serialize, he now can just hide that difference under the blanket:

use NorthPole::DB;
use File::Serialize;

my %list = (
    nice => 'nice.yaml',
    naughty => 'naughty.json',
);

while ( my( $status, $file ) = each %list ) {
    update_db( $status => deserialize_file $file );
}

And it goes the other way around as well. The module can also figure out the right output format and deal with common options (pretty-printing, utf8 output, canonical representation) based on the filename the script is writing to:

use NorthPole::DB;
use File::Serialize { pretty => 1, canonical => 1, utf8 => 1 };

my $children = query_db();

my %report = (
    nice => 'nice_out.yaml',
    naughty => 'naughty_out.json',
);

while ( my( $status, $file ) = each %list ) {
    serialize_file $file => [
        map { $_->behavior eq $status } @$children
    ];
}

With, of course, always the possibility to explicitly choose a specific format, for those special cases.

# TODO: have a chat with the Teddy Bear division 
# about cutesy extensions...

   serialize_file 'teddy.hohoho' => [
    grep { $_->want eq 'teddy bear' } @$nice_children
   ], { format => 'json' };

Keep it magic, when you need to be l33t

And then there is the module's carefully guarded little hidden bonus: it also has a function called transerialize_file, which allows to implement a small pipeline (or, in develfoper lingo, a garland) of transformations. For example, Glugg's real script is even shorter than the snippets given above, and looks something like this:

transerialize_file query_db()
    => { 'all_children.yml' => undef }
    => [
        [
            sub { [ grep { $_->behavior eq 'naughty' } @$_ ] }
                => 'naughty.json'
        ],
        [
            sub { [ grep { $_->behavior eq 'nice' } @$_ ] }
                => { 'nice.json' => undef },
                => sub { [ grep { $_->want eq 'teddy bear' } ] @$_ }
                => { 'teddy.hohoho' => { format => 'json' } }
        ]
    ];

Short and efficient. That's how elves are, and that's how they like their code to be.

Gravatar Image This article contributed by: Yanick Champoux <yanick@cpan.org>