File Coverage

blib/lib/Net/Google/Analytics/MeasurementProtocol.pm
Criterion Covered Total %
statement 44 56 78.5
branch 7 20 35.0
condition 11 32 34.3
subroutine 6 9 66.6
pod 2 2 100.0
total 70 119 58.8


line stmt bran cond sub pod time code
1             package Net::Google::Analytics::MeasurementProtocol;
2 4     4   82503 use strict;
  4         6  
  4         94  
3 4     4   12 use warnings;
  4         5  
  4         74  
4 4     4   12 use Carp ();
  4         8  
  4         2656  
5              
6             our $VERSION = 0.05;
7              
8             sub new {
9 1     1 1 58 my $class = shift;
10 1 50       5 my %args = (@_ == 1 ? %{$_[0]} : @_ );
  0         0  
11              
12             Carp::croak 'tracking_id (tid) missing or invalid'
13 1 50 33     12 unless $args{tid} && $args{tid} =~ /^(?:UA|MO|YT)-\d+-\d+$/;
14              
15             # If the 'aip' key exists, even if set to 0, the ip will be anonymized.
16             # So we only push it to our args if user set it to 1.
17 1 50 33     5 delete $args{aip} if exists $args{aip} && !$args{aip};
18              
19             # default settings:
20 1   33     14 $args{ua} ||= __PACKAGE__ . "/$VERSION";
21 1   33     6 $args{cid} ||= _gen_uuid_v4();
22 1   50     5 $args{v} ||= 1;
23 1   50     11 $args{cd} ||= '/';
24 1   50     4 $args{an} ||= 'My App';
25 1   50     4 $args{ds} ||= 'app';
26              
27 1   33     6 my $ua_object = delete $args{ua_object} || _build_user_agent( $args{ua} );
28 1 50 33     9 unless ( $ua_object->isa('Furl') || $ua_object->isa('LWP::UserAgent') ) {
29 0         0 Carp::croak('ua_object must be of type Furl or LWP::UserAgent');
30             }
31              
32 1         2 my $debug = delete $args{debug};
33 1         5 return bless {
34             args => \%args,
35             debug => $debug,
36             ua => $ua_object,
37             }, $class;
38             }
39              
40             sub send {
41 0     0 1 0 my ($self, $hit_type, $args) = @_;
42              
43 0         0 return $self->_request( $self->_build_request_args( $hit_type, $args ) );
44             }
45              
46             sub _build_request_args {
47 1     1   7 my ($self, $hit_type, $args) = @_;
48              
49 1         2 my %args = (%{$self->{args}}, %$args, t => $hit_type);
  1         9  
50 1         15 my %required = (
51             pageview => [qw(v tid cid cd an)],
52             screenview => [qw(v tid cid cd an)],
53             event => [qw(v tid cid cd an ec ea)],
54             transaction => [qw(v tid cid cd an ti)],
55             item => [qw(v tid cid cd an ti in)],
56             social => [qw(v tid cid cd an sn sa st)],
57             exception => [qw(v tid cid cd an)],
58             timing => [qw(v tid cid cd an utc utv utt)],
59             );
60 1 50       3 Carp::croak("invalid hit type $hit_type") unless $required{$hit_type};
61              
62 1         1 foreach my $required ( @{$required{$hit_type}} ) {
  1         3  
63             Carp::croak("argument '$required' is required for '$hit_type' hit type. See https://developers.google.com/analytics/devguides/collection/protocol/v1/parameters#$required for more information")
64 6 50       10 unless $args{$required};
65             }
66             Carp::croak('for "pageview" hit types you must set either "dl" or both "dh" and "dp"')
67 1 50 0     7 if $hit_type eq 'pageview' && !($args{dl} || ($args{dh} && $args{dp}));
      33        
68 1         5 return \%args;
69             }
70              
71             sub _request {
72 0     0   0 my ($self, $args) = @_;
73              
74 0         0 my $ua = $self->{ua};
75             my $target = $self->{debug}
76 0 0       0 ? 'https://www.google-analytics.com/debug/collect'
77             : 'https://www.google-analytics.com/collect'
78             ;
79              
80             # Compatibility layer for LWP::UserAgent
81 0 0       0 my $res = $ua->post( $target, $ua->isa('Furl') ? undef : (), $args );
82              
83 0 0       0 return $self->{debug} ? $res : $res->is_success;
84             }
85              
86             sub _build_user_agent {
87 0     0   0 my ($ua) = @_;
88 0         0 require Furl;
89 0         0 return Furl->new( agent => $ua, timeout => 5 );
90             }
91              
92             # UUID v4 (pseudo-random) generator based on UUID::Tiny
93             sub _gen_uuid_v4 {
94 3     3   13 my $uuid = '';
95 3         10 for ( 1 .. 4 ) {
96 12         43 my $v1 = int(rand(65536)) % 65536;
97 12         11 my $v2 = int(rand(65536)) % 65536;
98 12         23 my $rand_32bit = ($v1 << 16) | $v2;
99 12         28 $uuid .= pack 'I', $rand_32bit;
100             }
101 3         10 substr $uuid, 6, 1, chr( ord( substr( $uuid, 6, 1 ) ) & 0x0f | 0x40 );
102 3         8 substr $uuid, 8, 1, chr( ord( substr( $uuid, 8, 1 ) ) & 0x3f | 0x80 );
103              
104             # uuid is created. Convert to string:
105             return join '-',
106 15         40 map { unpack 'H*', $_ }
107 3         8 map { substr $uuid, 0, $_, '' }
  15         23  
108             ( 4, 2, 2, 2, 6 );
109             }
110              
111             1;
112             __END__