File Coverage

blib/lib/WWW/Purolator/TrackingInfo.pm
Criterion Covered Total %
statement 38 47 80.8
branch 4 6 66.6
condition 0 2 0.0
subroutine 10 10 100.0
pod 2 2 100.0
total 54 67 80.6


line stmt bran cond sub pod time code
1             package WWW::Purolator::TrackingInfo;
2              
3 2     2   289486 use warnings;
  2         5  
  2         70  
4 2     2   11 use strict;
  2         3  
  2         92  
5              
6             our $VERSION = '1.0105';
7 2     2   55 use 5.006;
  2         12  
  2         77  
8 2     2   11 use LWP::UserAgent;
  2         4  
  2         46  
9 2     2   1550 use JSON::PP qw//;
  2         16321  
  2         53  
10 2     2   15 use base 'Class::Accessor::Grouped';
  2         5  
  2         1784  
11             __PACKAGE__->mk_group_accessors( simple => qw/
12             error
13             _ua
14             /);
15              
16             sub new {
17 1     1 1 16 my $class = shift;
18 1         4 my %options = @_;
19 1         4 my $self = bless {}, $class;
20              
21 1         15 $self->_ua(
22             LWP::UserAgent->new(
23             agent => 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:26.0) '
24             . 'Gecko/20100101 Firefox/26.0', timeout => 30 ),
25             );
26              
27 1         3905 return $self;
28             }
29              
30             sub track {
31 3     3 1 705836 my ( $self, $pin ) = @_;
32              
33 3         26 $self->error(undef);
34              
35 3         425 my $res = $self->_ua->get(
36             'http://www.purolator.com/en/ship-track/tracking-details.page?pin='
37             . $pin,
38             );
39              
40 3 50       6346514 $res->is_success
41             or return $self->_set_error('Network error: ' . $res->status_line);
42              
43 3         59 return $self->_parse( $pin, $res->decoded_content );
44             }
45              
46             sub _parse {
47 3     3   48963 my ( $self, $pin, $content ) = @_;
48              
49 3         24 my %info = ( pin => $pin );
50              
51 3 100       125 $content =~ /Our online tracking system is currently unavailable/
52             and return $self->_set_error(
53             'Tracking system is currently unavailable'
54             );
55              
56 1         37 my ( $z ) = $content =~ m{var jsHistoryTable = (\[.+?\]);}s;
57              
58 1         3 my $history_table = eval {
59 1         12 JSON::PP->new->allow_singlequote->decode( $z );
60             };
61 1 50       770 $@
62             and return $self->_set_error(
63             'Error parsing Purolator\'s data: ' . $@
64             . '. Perhaps you supplied an invalid PIN/tracking number?'
65             );
66              
67 0         0 for ( @$history_table ) {
68 0         0 my %data;
69 0         0 @data{qw/scan_date scan_time location comment/} = @$_;
70 0         0 $_ = \%data;
71             }
72              
73 0         0 $info{history} = $history_table;
74              
75              
76 0         0 my ( $status_code ) = $content =~ m{
77             var \s+ detailsData \s+ =
78             \s+
79             \{
80             \s+ "trackingNumber" .+?
81             "status": \s+ '([^']+)'
82             }six;
83              
84 0         0 my %possible_statuses = (
85             InTransit => 'in transit',
86             Pickup => 'package picked up',
87             DataReceived => 'shipping label created',
88             Attention => 'attention',
89             Delivered => 'delivered',
90             );
91              
92 0   0     0 $info{status}
93             = $possible_statuses{ $status_code } || 'unknown status code';
94              
95 0         0 return \%info;
96             }
97              
98             sub _set_error {
99 3     3   10 my ( $self, $error ) = @_;
100              
101 3         24 $self->error( $error );
102              
103 3         227 return;
104             }
105              
106             q|
107             I'd like to make the world a better place,
108             but they won't give me the source code.
109             |;
110             __END__