File Coverage

blib/lib/Net/Google/Analytics/Response.pm
Criterion Covered Total %
statement 77 79 97.4
branch 7 8 87.5
condition n/a
subroutine 11 12 91.6
pod 6 6 100.0
total 101 105 96.1


line stmt bran cond sub pod time code
1             package Net::Google::Analytics::Response;
2             $Net::Google::Analytics::Response::VERSION = '3.04';
3 2     2   11 use strict;
  2         4  
  2         48  
4 2     2   12 use warnings;
  2         6  
  2         99  
5              
6             # ABSTRACT: Google Analytics API response
7              
8             use Class::XSAccessor
9 2         14 accessors => [ qw(
10             is_success
11             code message content
12             total_results start_index items_per_page
13             contains_sampled_data
14             profile_info
15             rows
16             _column_headers
17             _totals
18             ) ],
19 2     2   10 constructor => 'new';
  2         2  
20              
21             sub error_message {
22 0     0 1 0 my $self = shift;
23              
24 0         0 return join(' ', $self->code, $self->message, $self->content);
25             }
26              
27             sub _parse_json {
28 2     2   7 my ($self, $json) = @_;
29              
30 2         13 $self->items_per_page($json->{itemsPerPage});
31 2         10 $self->total_results($json->{totalResults});
32 2         10 $self->contains_sampled_data($json->{containsSampledData});
33 2         10 $self->profile_info($json->{profileInfo});
34              
35 2         5 my $json_totals = $json->{totalsForAllResults};
36 2         6 my %totals;
37              
38 2         16 while (my ($json_name, $total) = each(%$json_totals)) {
39 3         12 my $column_name = _parse_column_name($json_name);
40 3         20 $totals{$column_name} = $total;
41             }
42              
43 2         11 $self->_totals(\%totals);
44              
45 2         4 my @column_headers;
46              
47 2         5 for my $column_header (@{ $json->{columnHeaders} }) {
  2         7  
48             push(@column_headers, {
49             name => _parse_column_name($column_header->{name}),
50             column_type => $column_header->{columnType},
51             data_type => $column_header->{dataType},
52 6         17 });
53             }
54              
55 2         11 $self->_column_headers(\@column_headers);
56              
57 2         21 my $class = Net::Google::Analytics::Row->_gen_class(\@column_headers);
58              
59 2         5 my @rows = map { $class->new($_) } @{ $json->{rows} };
  10         46  
  2         6  
60 2         15 $self->rows(\@rows);
61             }
62              
63             sub _parse_column_name {
64 9     9   16 my $name = shift;
65              
66 9 50       50 my ($res) = $name =~ /^(?:ga|rt):(\w{1,64})\z/
67             or die("invalid column name: $name");
68              
69             # convert camel case
70 9         30 $res =~ s/[A-Z]/'_' . lc($&)/ge;
  5         26  
71              
72 9         45 return $res;
73             }
74              
75             sub num_rows {
76 3     3 1 2423 my $self = shift;
77              
78 3         6 return scalar(@{ $self->rows });
  3         24  
79             }
80              
81             sub metrics {
82 3     3 1 2359 my $self = shift;
83              
84 3         10 return $self->_columns('METRIC');
85             }
86              
87             sub dimensions {
88 3     3 1 1697 my $self = shift;
89              
90 3         9 return $self->_columns('DIMENSION');
91             }
92              
93             sub totals {
94 4     4 1 16901 my ($self, $metric) = @_;
95              
96 4         26 return $self->_totals->{$metric};
97             }
98              
99             sub _columns {
100 6     6   11 my ($self, $type) = @_;
101              
102 6         13 my $column_headers = $self->_column_headers;
103 6         8 my @results;
104              
105 6         12 for my $column_header (@$column_headers) {
106 18 100       47 if ($column_header->{column_type} eq $type) {
107 9         17 push(@results, $column_header->{name});
108             }
109             }
110              
111 6         22 return @results;
112             }
113              
114             sub project {
115 1     1 1 3 my ($self, $proj_dim_names, $projection) = @_;
116              
117 1         2 my (@metric_indices, @proj_column_headers);
118 1         4 my $column_headers = $self->_column_headers;
119              
120 1         5 for (my $i = 0; $i < @$column_headers; ++$i) {
121 4         6 my $column_header = $column_headers->[$i];
122              
123 4 100       47 if ($column_header->{column_type} eq 'METRIC') {
124 2         4 push(@metric_indices, $i);
125 2         9 push(@proj_column_headers, { %$column_header });
126             }
127             }
128              
129 1         2 for my $name (@$proj_dim_names) {
130 1         4 push(@proj_column_headers, {
131             name => $name,
132             column_type => 'DIMENSION',
133             });
134             }
135              
136 1         4 my $class = Net::Google::Analytics::Row->_gen_class(\@proj_column_headers);
137              
138             # Projected rows are collected in hash %proj_rows. The keys of the hash
139             # are the the projected dimension values joined with zero bytes.
140              
141 1         3 my %proj_rows;
142              
143 1         2 for my $row (@{ $self->rows }) {
  1         4  
144 5         10 my @proj_dim_values = $projection->($row);
145 5         34 my $key = join("\0", @proj_dim_values);
146              
147 5         6 my $proj_row = $proj_rows{$key};
148              
149 5 100       13 if (!$proj_row) {
150 2         3 my @proj_metric_values = map { $row->[$_] } @metric_indices;
  4         9  
151 2         14 $proj_rows{$key} = $class->new(
152             [ @proj_metric_values, @proj_dim_values ],
153             );
154             }
155             else {
156 3         9 for (my $i = 0; $i < @metric_indices; ++$i) {
157 6         7 my $mi = $metric_indices[$i];
158 6         19 $proj_row->[$i] += $row->[$mi];
159             }
160             }
161             }
162              
163 1         4 my @rows = values(%proj_rows);
164              
165 1         11 return Net::Google::Analytics::Response->new(
166             is_success => 1,
167             total_results => scalar(@rows),
168             start_index => 1,
169             items_per_page => scalar(@rows),
170             rows => \@rows,
171             _totals => $self->_totals,
172             _column_headers => \@proj_column_headers,
173             );
174             }
175              
176             1;
177              
178             __END__