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.03';
3 2     2   7 use strict;
  2         3  
  2         61  
4 2     2   8 use warnings;
  2         2  
  2         81  
5              
6             # ABSTRACT: Google Analytics API response
7              
8             use Class::XSAccessor
9 2         9 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   11 constructor => 'new';
  2         3  
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   5 my ($self, $json) = @_;
29              
30 2         12 $self->items_per_page($json->{itemsPerPage});
31 2         8 $self->total_results($json->{totalResults});
32 2         8 $self->contains_sampled_data($json->{containsSampledData});
33 2         6 $self->profile_info($json->{profileInfo});
34              
35 2         4 my $json_totals = $json->{totalsForAllResults};
36 2         4 my %totals;
37              
38 2         11 while (my ($json_name, $total) = each(%$json_totals)) {
39 3         9 my $column_name = _parse_column_name($json_name);
40 3         15 $totals{$column_name} = $total;
41             }
42              
43 2         9 $self->_totals(\%totals);
44              
45 2         2 my @column_headers;
46              
47 2         4 for my $column_header (@{ $json->{columnHeaders} }) {
  2         7  
48 6         13 push(@column_headers, {
49             name => _parse_column_name($column_header->{name}),
50             column_type => $column_header->{columnType},
51             data_type => $column_header->{dataType},
52             });
53             }
54              
55 2         10 $self->_column_headers(\@column_headers);
56              
57 2         19 my $class = Net::Google::Analytics::Row->_gen_class(\@column_headers);
58              
59 2         5 my @rows = map { $class->new($_) } @{ $json->{rows} };
  10         40  
  2         8  
60 2         16 $self->rows(\@rows);
61             }
62              
63             sub _parse_column_name {
64 9     9   12 my $name = shift;
65              
66 9 50       48 my ($res) = $name =~ /^(?:ga|rt):(\w{1,64})\z/
67             or die("invalid column name: $name");
68              
69             # convert camel case
70 9         22 $res =~ s/[A-Z]/'_' . lc($&)/ge;
  5         18  
71              
72 9         41 return $res;
73             }
74              
75             sub num_rows {
76 3     3 1 2251 my $self = shift;
77              
78 3         5 return scalar(@{ $self->rows });
  3         24  
79             }
80              
81             sub metrics {
82 3     3 1 2427 my $self = shift;
83              
84 3         12 return $self->_columns('METRIC');
85             }
86              
87             sub dimensions {
88 3     3 1 1405 my $self = shift;
89              
90 3         9 return $self->_columns('DIMENSION');
91             }
92              
93             sub totals {
94 4     4 1 2905 my ($self, $metric) = @_;
95              
96 4         27 return $self->_totals->{$metric};
97             }
98              
99             sub _columns {
100 6     6   9 my ($self, $type) = @_;
101              
102 6         14 my $column_headers = $self->_column_headers;
103 6         9 my @results;
104              
105 6         11 for my $column_header (@$column_headers) {
106 18 100       44 if ($column_header->{column_type} eq $type) {
107 9         14 push(@results, $column_header->{name});
108             }
109             }
110              
111 6         19 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         5 my $column_headers = $self->_column_headers;
119              
120 1         8 for (my $i = 0; $i < @$column_headers; ++$i) {
121 4         4 my $column_header = $column_headers->[$i];
122              
123 4 100       108 if ($column_header->{column_type} eq 'METRIC') {
124 2         2 push(@metric_indices, $i);
125 2         10 push(@proj_column_headers, { %$column_header });
126             }
127             }
128              
129 1         3 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         5 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         2 my %proj_rows;
142              
143 1         1 for my $row (@{ $self->rows }) {
  1         5  
144 5         7 my @proj_dim_values = $projection->($row);
145 5         30 my $key = join("\0", @proj_dim_values);
146              
147 5         5 my $proj_row = $proj_rows{$key};
148              
149 5 100       14 if (!$proj_row) {
150 2         2 my @proj_metric_values = map { $row->[$_] } @metric_indices;
  4         7  
151 2         15 $proj_rows{$key} = $class->new(
152             [ @proj_metric_values, @proj_dim_values ],
153             );
154             }
155             else {
156 3         8 for (my $i = 0; $i < @metric_indices; ++$i) {
157 6         6 my $mi = $metric_indices[$i];
158 6         16 $proj_row->[$i] += $row->[$mi];
159             }
160             }
161             }
162              
163 1         3 my @rows = values(%proj_rows);
164              
165 1         18 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__