The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Data::Google::Visualization::DataTable - Easily create Google DataTable objects

VERSION

version 0.11

DESCRIPTION

Easily create Google DataTable objects without worrying too much about typed data

OVERVIEW

Google's excellent Visualization suite requires you to format your Javascript data very carefully. It's entirely possible to do this by hand, especially with the help of the most excellent JSON::XS but it's a bit fiddly, largely because Perl doesn't natively support data types and Google's API accepts a super-set of JSON - see "JSON vs Javascript" below.

This module is attempts to hide the gory details of preparing your data before sending it to a JSON serializer - more specifically, hiding some of the hoops that have to be jump through for making sure your data serializes to the right data types.

More about the Google Visualization API.

Every effort has been made to keep naming conventions as close as possible to those in the API itself.

To use this module, a reasonable knowledge of Perl is assumed. You should be familiar with Perl references and Perl objects.

SYNOPSIS

 use Data::Google::Visualization::DataTable;

 my $datatable = Data::Google::Visualization::DataTable->new();

 $datatable->add_columns(
        { id => 'date',     label => "A Date",        type => 'date', p => {}},
        { id => 'datetime', label => "A Datetime",    type => 'datetime' },
        { id => 'timeofday',label => "A Time of Day", type => 'timeofday' },
        { id => 'bool',     label => "True or False", type => 'boolean' },
        { id => 'number',   label => "Number",        type => 'number' },
        { id => 'string',   label => "Some String",   type => 'string' },
 );

 $datatable->add_rows(

 # Add as array-refs
        [
                { v => DateTime->new() },
                { v => Time::Piece->new(), f => "Right now!" },
                { v => [6, 12, 1], f => '06:12:01' },
                { v => 1, f => 'YES' },
                15.6, # If you're getting lazy
                { v => 'foobar', f => 'Foo Bar', p => { display => 'none' } },
        ],

 # And/or as hash-refs (but only if you defined id's for each of your columns)
        {
                date      => DateTime->new(),
                datetime  => { v => Time::Piece->new(), f => "Right now!" },
                timeofday => [6, 12, 1],
                bool      => 1,
                number    => 15.6,
                string    => { v => 'foobar', f => 'Foo Bar' },
        },

 );

 # Get the data...

 # Fancy-pants
 my $output = $datatable->output_javascript(
        columns => ['date','number','string' ],
        pretty  => 1,
 );

 # Vanilla
 my $output = $datatable->output_javascript();

COLUMNS, ROWS AND CELLS

We've tried as far as possible to stay as close as possible to the underlying API, so make sure you've had a good read of: Google Visualization API.

Columns

Columns are specified using a hashref, and follow exactly the format of the underlying API itself. All of type, id, label, pattern, and p are supported. The contents of p will be passed directly to JSON::XS to serialize as a whole.

Rows

A row is either a hash-ref where the keys are column IDs and the values are cells, or an array-ref where the values are cells.

Cells

Cells can be specified in several ways, but the best way is using a hash-ref that exactly conforms to the API. v is NOT checked against your data type - but we will attempt to convert it. If you pass in an undefined value, it will return a JS 'null', regardless of the data type. f needs to be a string if you provide it. p will be bassed directly to JSON::XS.

For any of the date-like fields (date, datetime, timeofday), you can pass in 4 types of values. We accept DateTime objects, Time::Piece objects, epoch seconds (as a string - converted internally using localtime), or an array-ref of values that will be passed directly to the resulting Javascript Date object eg:

 Perl:
  date => [ 5, 4, 3 ]
 JS:
  new Date( 5, 4, 3 )

Remember that JS dates 0-index the month. Make sure you read the sections on Dates and Times below if you want any chance of doing this right...

For non-date fields, if you specify a cell using a string or number, rather than a hashref, that'll be mapped to a cell with v set to the string you specified.

boolean: we test the value you pass in for truth, the Perl way, although undef values will come out as null, not 0.

Properties

Properties can be defined for the whole datatable (using set_properties), for each column (using p), for each row (using p) and for each cell (again using p). The documentation provided is a little unclear as to exactly what you're allowed to put in this, so we provide you ample rope and let you specify anything you like.

When defining properties for rows, you must use the hashref method of row creation. If you have a column with id of p, you must use _p as your key for defining properties.

METHODS

new

Constructor. In 99% of cases, you really don't need to provide any options at all to the constructor. Accepts a hashref of arguments:

p - a datatable-wide properties element (see Properties above and the Google docs).

with_timezone - defaults to false. An experimental feature for doing dates the right way. See: "DATES AND TIMES" for discussion below.

json_object - optional, and defaults to a sensibly configured JSON::XS object. If you really want to avoid using JSON::XS for some reason, you can pass in something else here that supports an encode method (and also avoid loading JSON::XS at all, as we lazy-load it). If you just want to configure the JSON::XS object we use, consider using the json_xs_object method specified below instead. tl;dr: ignore this option.

add_columns

Accepts zero or more columns, in the format specified above, and adds them to our list of columns. Returns the object. You can't call this method after you've called add_rows for the first time.

add_rows

Accepts zero or more rows, either as a list of hash-refs or a list of array-refs. If you've provided hash-refs, we'll map the key name to the column via its ID (you must have given every column an ID if you want to do this, or it'll cause a fatal error).

If you've provided array-refs, we'll assume each cell belongs in subsequent columns - your array-ref must have the same number of members as you have set columns.

pedantic

We do some data checking for sanity, and we'll issue warnings about things the API considers bad data practice - using reserved words or fancy characters and IDs so far. If you don't want that, simple say:

 $object->pedantic(0);

Defaults to true.

set_properties

Sets the datatable-wide properties value. See the Google docs.

json_xs_object

You may want to configure your JSON::XS object in some magical way. This is a read/write accessor to it. If you didn't understand that, or why you'd want to do that, you can ignore this method.

output_javascript

Returns a Javascript serialization of your object. You can optionally specify two parameters:

pretty - bool - defaults to false - that specifies if you'd like your Javascript spread-apart with whitespace. Useful for debugging.

columns - array-ref of strings - pick out certain columns only (and in the order you specify). If you don't provide an argument here, we'll use them all and in the order set in add_columns.

output_json

An alias to output_javascript above, with a very misleading name, as it outputs Javascript, not JSON - see "JSON vs Javascript" below.

JSON vs Javascript

Please note this module outputs Javascript, and not JSON. JSON is a subset of Javascript, and Google's API requires a similar - but different - subset of Javascript. Specifically some values need to be set to native Javascript objects, such as (and currently limited to) the Date object. That means we output code like:

 {"v":new Date( 2011, 2, 21, 2, 6, 25 )}

which is valid Javascript, but not valid JSON.

DATES AND TIMES

Dates are one of the reasons this module is needed at all - Google's API in theory accepts Date objects, rather than a JSON equivalent of it. However, given:

 new Date( 2011, 2, 21, 2, 6, 25 )

in Javascript, what timezone is that? If you guessed UTC because that would be The Right Thing To Do, sadly you guessed wrong - it's actually set in the timezone of the client. And as you don't know what the client's timezone is, if you're going to actually use this data for anything other than display to that user, you're a little screwed.

Even if we don't attempt to rescue that, if you pass in an Epoch timestamp, I have no idea which timezone you want me to use to convert that in to the above. We started off using localtime, which shows I hadn't really thought about it, and will continue to use it for backwards compatibility, but:

Don't pass this module epoch time stamps. Either do the conversion in your code using localtime or gmtime, or pass in a DateTime object whose <-hour>> and friends return the right thing.

We accept four types of date input, and this is how we handle each one:

epoch seconds

We use localtime, and then drop the returned fields straight in to a call to new Date() in JS.

DateTime and Time::Piece

We use whatever's being returned by hour, min and sec. Timezone messin' in the object itself to get the output you want is left to you.

Raw values

We stick it straight in as you specified it.

... and one more thing

So it is actually possible - although a PITA - to create a Date object in Javascript using Date.parse() which has an offset. In theory, all browsers should support dates in RFC 2822's format:

 Thu, 01 Jan 1970 00:00:00 GMT-0400

If you're thinking trolololo at this point, you're on the right track...

So here's the deal: IF you specify with_timezone to this module's new AND you pass in a DateTime object, you'll get dates like:

 new Date("Thu, 01 Jan 1970 00:00:00 GMT-0400")

in your output.

BUG BOUNTY

Find a reproducible bug, file a bug report, and I (Peter Sergeant) will donate $10 to The Perl Foundation (or Wikipedia). Feature Requests are not bugs :-) Offer subject to author's discretion...

$20 donated 31Dec2010 to TPF re properties handling bug

$10 donated 11Nov2010 to TPF re null display bug

SUPPORT

If you find a bug, please use this modules page on the CPAN bug tracker to raise it, or I might never see.

AUTHOR

Peter Sergeant pete@clueball.com on behalf of Investor Dynamics - Letting you know what your market is thinking.

SEE ALSO

Python library that does the same thing

JSON::XS - The underlying module

Google Visualization API.

Github Page for this code

COPYRIGHT

Copyright 2010 Investor Dynamics Ltd, some rights reserved.

This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.