File Coverage

blib/lib/Webservice/Shipment.pm
Criterion Covered Total %
statement 32 37 86.4
branch 7 12 58.3
condition 3 5 60.0
subroutine 7 7 100.0
pod 3 3 100.0
total 52 64 81.2


line stmt bran cond sub pod time code
1             package Webservice::Shipment;
2              
3 1     1   212060 use Mojo::Base -base;
  1         9  
  1         8  
4              
5             our $VERSION = '0.06';
6             $VERSION = eval $VERSION;
7              
8 1     1   193 use Scalar::Util 'blessed';
  1         2  
  1         102  
9              
10             has carriers => sub { [] };
11             has defaults => sub { {} };
12              
13 1     1   6 use Carp;
  1         2  
  1         500  
14              
15             sub AUTOLOAD {
16 2     2   5 my $self = shift;
17 2         14 my ($package, $method) = our $AUTOLOAD =~ /^(.+)::(.+)$/;
18 2         6 return $self->delegate($method, @_);
19             }
20              
21             sub add_carrier {
22 2     2 1 1146 my ($self, $carrier, $conf) = @_;
23 2   100     10 $conf ||= {};
24 2         4 $conf = { %{$self->defaults}, %$conf };
  2         6  
25              
26 2 50 33     26 if (blessed $carrier and $carrier->isa('Webservice::Shipment::Carrier')) {
27 0         0 push @{$self->carriers}, $carrier;
  0         0  
28 0         0 return $self;
29             }
30              
31 2         8 for my $class ("Webservice::Shipment::Carrier::$carrier", $carrier) {
32 2 50       130 next unless eval "require $class; 1";
33 2 50       26 next unless $class->isa('Webservice::Shipment::Carrier');
34 2 50       12 next unless my $inst = $class->new($conf);
35 2         27 push @{$self->carriers}, $inst;
  2         6  
36 2         12 return $self;
37             }
38              
39 0         0 croak "Unable to add carrier $carrier";
40             }
41              
42             sub delegate {
43 2     2 1 4 my ($self, $method) = (shift, shift);
44 2         3 my $id = $_[0];
45              
46 2 50       4 croak "No added carrier can handle $id"
47             unless my $carrier = $self->detect($id);
48              
49 2         9 return $carrier->$method(@_);
50             }
51              
52             sub detect {
53 4     4 1 2310 my ($self, $id) = @_;
54 4         10 my $carriers = $self->carriers;
55 4         21 for my $carrier (@$carriers) {
56 6 100       22 return $carrier if $carrier->validate($id);
57             }
58              
59 0           return undef;
60             }
61              
62             1;
63              
64             =head1 NAME
65              
66             Webservice::Shipment - Get common shipping information from supported carriers
67              
68             =head1 SYNOPSIS
69              
70             use strict;
71             use warnings;
72              
73             use Webservice::Shipment;
74              
75             my $ship = Webservice::Shipment->new(defaults => {date_format => '%m/%d/%y'});
76             $ship->add_carrier(UPS => {
77             api_key => 'MYAPIKEY_12345',
78             username => 'some_user',
79             password => 'passw0rd',
80             });
81             $ship->add_carrier(USPS => {
82             username => 'my_username',
83             password => 'p@ssword',
84             });
85              
86             use Data::Dumper;
87              
88             print Dumper $ship->track('9400105901096094290500'); # usps
89             print Dumper $ship->track('1Z584056NW00605000'); # ups
90              
91             # non-blocking with callback
92             $ship->track('1Z584056NW00605000', sub {
93             my ($carrier, $err, $info) = @_;
94             warn $err if $err;
95             print Dumper $info
96             });
97              
98             __END__
99             # sample output
100              
101             {
102             'status' => {
103             'description' => 'DELIVERED',
104             'date' => '12/24/14',
105             'delivered' => 1,
106             },
107             'destination' => {
108             'address1' => '',
109             'address2' => '',
110             'city' => 'BEVERLY HILLS',
111             'state' => 'CA',
112             'country' => '',
113             'postal_code' => '90210',
114             },
115             'weight' => '0.70 LBS',
116             'service' => 'UPS NEXT DAY AIR',
117             'human_url' => 'http://wwwapps.ups.com/WebTracking/track?trackNums=1Z584056NW00605000&track.x=Track',
118             }
119              
120             =head1 DESCRIPTION
121              
122             L is a central module for obtaining shipping information from supported carriers.
123             It is very lightweight, built on the L toolkit.
124             The fact that it is built on L does not restrict its utility in non-Mojolicious apps.
125              
126             L subclasses request information from that carrier's api and extract information from it.
127             The information is then returned in a standardized format for ease of use.
128             Futher, L itself tries to deduce which carrier to use based on the id number.
129             This makes it very easy to use, but also implies that it will only ever report common information.
130             More detailed API interfaces already exist and are mentioned L.
131              
132             Note that this is a very early release and will likely have bugs that need to be worked out.
133             It should be used for informative puposes only.
134             Please do not rely on this for mission critical code until this message is removed.
135              
136             =head1 ATTTRIBUTES
137              
138             L inherits all of the attributes from L and implements the following new ones.
139              
140             =head2 carriers
141              
142             An array refence of added L objects.
143             You probably want to use L instead.
144              
145             =head2 defaults
146              
147             A hash reference of default values to be merged with per-carrier constructor arguments when using L.
148             This defaults can be overridden by passing in an explicity parameter of the same name to L.
149             This is especially useful for C parameters and possibly for C and/or C if those are consistent between carriers.
150              
151             =head1 METHODS
152              
153             L inherits all of the methods from L and implements the following new ones.
154              
155             =head2 add_carrier
156              
157             $ship = $ship->add_carrier(UPS => { username => '...', password => '...', api_key => '...', ... });
158             $ship = $ship->add_carrier($carrier_object);
159              
160             Adds an instance of L to L.
161             If passed an object, the object is verified to be a subclass of that module and added.
162             Otherwise, the first argument is assumed to be a class name, first attempted relative to C then as absolute.
163             If the class can be loaded, its parentage is checked as before and then an instace is created, using an optional hash as constructor arguments.
164             If provided, those arguments should conform to the documented constructor arguments for that class.
165              
166             If these conditions fail, and no carrier is added, the method throws an exception.
167              
168             =head2 delegate
169              
170             $ship->delegate('method_name', $id, @addl_args);
171              
172             Attempts to call C on an carrier instance in L which corresponds to the given C<$id>.
173             This is done via the L method.
174             In the above example if the detected instance was C<$carrier> it would then be called as:
175              
176             $carrier->method_name($id, @addl_args);
177              
178             Clearly this only is only useful for carrier methods that take an id as a leading argument.
179             If no carrier is detected, an exception is thrown.
180              
181             This method is used to implement C for this class.
182             This allows the very simple usage:
183              
184             $ship->add_carrier($c1)->add_carrier($c2);
185             $info = $ship->track($id);
186              
187             =head2 detect
188              
189             $carrier = $ship->detect($id);
190              
191             Returns the first carrier in L that validates the given id as something that it can handle, via L.
192             Returns undef if no carrier matches.
193              
194             =head1 SEE ALSO
195              
196             =over
197              
198             =item L
199              
200             =item L
201              
202             =item L
203              
204             =item L
205              
206             =back
207              
208             =head1 SPECIAL THANKS
209              
210             Pharmetika Software, L
211              
212             =head1 AUTHOR
213              
214             Joel Berger, Ejoel.a.berger@gmail.comE
215              
216             =head1 CONTRIBUTORS
217              
218             Ryan Perry
219              
220             =head1 COPYRIGHT AND LICENSE
221              
222             Copyright (C) 2015 by L and L.
223              
224             This library is free software; you can redistribute it and/or modify
225             it under the same terms as Perl itself.
226