File Coverage

blib/lib/Google/Chart.pm
Criterion Covered Total %
statement 1 3 33.3
branch n/a
condition n/a
subroutine 1 1 100.0
pod n/a
total 2 4 50.0


line stmt bran cond sub pod time code
1              
2             package Google::Chart;
3 13     13   405139 use Moose;
  0            
  0            
4             use Google::Chart::Data;
5             use Google::Chart::Title;
6             use Google::Chart::Types;
7             use LWP::UserAgent;
8             use namespace::clean -except => qw(meta);
9              
10             our $VERSION = '0.09000_05';
11              
12             has title => (
13             is => 'ro',
14             isa => 'Google::Chart::Title',
15             coerce => 1,
16             predicate => 'has_title',
17             );
18              
19             has type => (
20             init_arg => undef, # should NOT be initialized by callers
21             is => 'ro',
22             isa => 'Str',
23             required => 1,
24             lazy_build => 1,
25             );
26              
27             has google_chart_uri => (
28             is => 'ro',
29             isa => 'URI',
30             lazy_build => 1
31             );
32              
33             has ua => (
34             is => 'ro',
35             isa => 'LWP::UserAgent',
36             lazy_build => 1,
37             );
38              
39             has width => (
40             is => 'rw',
41             isa => 'Int',
42             required => 1
43             );
44              
45             has height => (
46             is => 'rw',
47             isa => 'Int',
48             required => 1
49             );
50              
51             around BUILDARGS => sub {
52             my ($next, $self, @args) = @_;
53             my $args = $next->($self, @args);
54              
55             if (my $size = delete $args->{size}) {
56             my ($width, $height) = split /x/, $size;
57             $args->{width} = $width;
58             $args->{height} = $height;
59             }
60              
61             return $args;
62             };
63              
64             sub _build_google_chart_uri {
65             require URI;
66             return $ENV{GOOGLE_CHART_URI} ?
67             URI->new($ENV{GOOGLE_CHART_URI}) :
68             URI->new("http://chart.apis.google.com/chart");
69             }
70              
71             sub _build_type { confess "Unknown type $_[0] (Did you implement a _build_type() method ?" }
72              
73             sub _build_ua {
74             my $self = shift;
75             my $ua = LWP::UserAgent->new(
76             agent => "perl/Google-Chart-$VERSION",
77             env_proxy => exists $ENV{GOOGLE_CHART_ENV_PROXY} ? $ENV{GOOGLE_CHART_ENV_PROXY} : 1,
78             );
79             return $ua;
80             }
81              
82             sub create {
83             my ($class, $chart_class, @args) = @_;
84              
85             if ($chart_class !~ s/^\+//) {
86             $chart_class = "Google::Chart::Type::$chart_class";
87             }
88              
89             if (! Class::MOP::is_class_loaded($chart_class) ) {
90             Class::MOP::load_class($chart_class);
91             }
92              
93             return $chart_class->new(@args);
94             }
95              
96             sub prepare_query {
97             my $self = shift;
98              
99             my @query = (
100             cht => $self->type,
101             chs => join('x', $self->width, $self->height )
102             );
103              
104             foreach my $element (map { $self->$_() } qw(title)) {
105             next unless defined $element;
106             my @params = $element->as_query( $self );
107             while (@params) {
108             my ($name, $value) = splice(@params, 0, 2);
109             next unless length $value;
110             push @query, ($name => $value);
111             }
112             }
113              
114             return @query;
115             }
116              
117             sub as_uri {
118             my $self = shift;
119              
120             # If in case you want to change this for debugging or whatever...
121             my $uri = $self->google_chart_uri()->clone;
122             my @query = $self->prepare_query();
123              
124             # XXX Be paranoid and don't squash duplicates... unless we should!
125             my %seen;
126             my @final;
127             while (@query) {
128             my ($key, $value) = splice(@query, 0, 2);
129             if ($key =~ /^ch[mf]$/) {
130             if ($seen{$key}) {
131             ${$seen{$key}} = join( '|', ${$seen{$key}}, $value );
132             } else {
133             $seen{$key} = \$value;
134             push @final, ($key => $value);
135             }
136             } else {
137             push @final, ($key => $value);
138             }
139             }
140              
141             $uri->query_form( @final );
142             return $uri;
143             }
144              
145             sub render {
146             my $self = shift;
147             my $response = $self->ua->get($self->as_uri);
148              
149             if ($response->is_success) {
150             return $response->content;
151             } else {
152             die $response->status_line;
153             }
154             }
155              
156             sub render_to_file {
157             # XXX - This is done like this because there was a document-implementation
158             # mismatch. In the future, single argument form should be deprecated
159             my $self = shift;
160             my $filename = (@_ > 1) ? do {
161             my %args = @_;
162             $args{filename};
163             }: $_[0];
164              
165             open my $fh, '>', $filename or die "can't open $filename for writing: $!\n";
166             binmode($fh); # be nice to windows
167             print $fh $self->render;
168             close $fh or die "can't close $filename: $!\n";
169             }
170              
171             __PACKAGE__->meta->make_immutable;
172              
173             1;
174              
175             __END__
176              
177             =head1 NAME
178              
179             Google::Chart - Interface to Google Charts API
180              
181             =head1 SYNOPSIS
182              
183             use Google::Chart;
184              
185             my $chart = Google::Chart->create(
186             Bar => (
187             bar_space => 20,
188             bar_width => 10,
189             group_space => 5,
190             orientation => 'horizontal'
191             size => "400x300",
192             stacked => 1,
193             )
194             );
195             $chart->add_axis(
196             location => 'x',
197             label => [ qw(foo bar baz) ],
198             );
199             $chart->add_dataset(
200             color => 'FF0000',
201             data => [ 1, 2, 3, 4, 5 ],
202             );
203              
204             print $chart->as_uri, "\n"; # or simply print $chart, "\n"
205              
206             $chart->render_to_file( filename => 'filename.png' );
207              
208             =head1 DESCRITPION
209              
210             Google::Chart provides a Perl Interface to Google Charts API
211             (http://code.google.com/apis/chart/).
212              
213             Please note that version 0.10000 is a major rewrite, and has little to no
214             backwards compatibility.
215              
216             =head1 METHODS
217              
218             =head2 create( $chart_type => %args )
219              
220             Creates a new chart of type $chart_type. The rest of the arguments are passed
221             to the constructor of the appropriate $chart_type class. Each chart type may
222             have a different set of attributes that it can initialize, but the following
223             are common to all chrats:
224              
225             =over 4
226              
227             =item width, height
228              
229             Specifies the chart width and height.
230              
231             =item size (deprecated)
232              
233             Strings like "400x300" are converted to their respective width and height
234              
235             my $chart = Google::Chart->new(
236             size => "400x300",
237             );
238              
239             =item title
240              
241             =back
242              
243             Other parameters differ depending on the chart type.
244              
245             =head2 new(%args)
246              
247             Creates a new Google::Chart instance. You should be using C<create> unless you're hacking on a new chart type.
248              
249             =head2 as_uri()
250              
251             Returns the URI that represents the chart object.
252              
253             =head2 render()
254              
255             Generates the chart image, and returns the contents.
256             This method internally uses LWP::UserAgent. If you want to customize LWP settings, create an instance of LWP::UserAgent and pass it in the constructor
257              
258             Google::Chart->new(
259             ....,
260             ua => LWP::UserAgent->new( %your_args )
261             );
262              
263             Proxy settings are automatically read via LWP::UserAgent->env_proxy(), unless you specify GOOGLE_CHART_ENV_PROXY environment variable to 0
264              
265             =head2 render_to_file( %args )
266              
267             Generates the chart, and writes the contents out to the file specified by
268             `filename' parameter
269              
270             =head2 BASE_URI
271              
272             The base URI for Google Chart
273              
274             =head1 CHART TYPES
275              
276             =head2 L<Bar|Google::Chart::Type::Bar>
277              
278             =head2 L<GoogleOMeter|Google::Chart::Type::GoogleOMeter>
279              
280             =head2 L<Line|Google::Chart::Type::Line>
281              
282             =head2 L<Map|Google::Chart::Type::Map>
283              
284             =head2 L<Pie|Google::Chart::Type::Pie>
285              
286             =head2 L<QRcode|Google::Chart::Type::QRcode>
287              
288             =head2 L<Radar|Google::Chart::Type::Radar>
289              
290             =head2 L<ScatterPlot|Google::Chart::Type::ScatterPlot>
291              
292             =head2 L<SparkLine|Google::Chart::Type::SparkLine>
293              
294             =head2 L<Venn|Google::Chart::Type::Venn>
295              
296             =head2 L<XY|Google::Chart::Type::XY>
297              
298             =head1 FEEDBACK
299              
300             We don't believe that we fully utilize Google Chart's abilities. So there
301             might be things missing, things that should be changed for easier use.
302             If you find any such case, PLEASE LET US KNOW! Suggestions are welcome, but
303             code snippets, pseudocode, or even better, test cases, are most welcome.
304              
305             =head1 TODO
306              
307             =over 4
308              
309             =item Coverage
310              
311             I've taken Google::Chart and challenged myself to implement every example
312             in the developer's manual (the japanese version, anyway). Unfortunately
313             there are a handful of examples that don't render /exactly/ the way it's in
314             the documents.
315              
316             You can check which ones are failing in the included "samples.html",
317             and send us patches ;)
318              
319             =back
320              
321             =head1 AUTHORS
322              
323             Daisuke Maki C<< <daisuke@endeworks.jp> >> (current maintainer)
324              
325             Nobuo Danjou C<< <nobuo.danjou@gmail.com> >>
326              
327             Marcel Grünauer C<< <marcel@cpan.org> >> (original author)
328              
329             =head1 LICENSE
330              
331             This program is free software; you can redistribute it and/or modify it
332             under the same terms as Perl itself.
333              
334             See http://www.perl.com/perl/misc/Artistic.html
335              
336             =cut