File Coverage

blib/lib/Mojolicious/Command/donuts.pm
Criterion Covered Total %
statement 12 50 24.0
branch 0 16 0.0
condition 0 6 0.0
subroutine 4 13 30.7
pod 1 1 100.0
total 17 86 19.7


line stmt bran cond sub pod time code
1             package Mojolicious::Command::donuts;
2 1     1   595 use Mojo::Base 'Mojolicious::Command';
  1         2  
  1         7  
3              
4 1     1   101703 use Mojo::JSON qw(encode_json);
  1         2377  
  1         59  
5 1     1   14 use Mojo::Util qw(dumper);
  1         1  
  1         35  
6 1     1   821 use Getopt::Long qw(GetOptionsFromArray);
  1         9000  
  1         5  
7              
8             our $VERSION = 0.03;
9              
10             has description => 'Find fresh donuts near you!';
11              
12             has usage => <
13             USAGE:
14              
15             mojo donuts [OPTIONS]
16              
17             OPTIONS:
18              
19             --geo, -g Specify geo to be used for search (recommended)
20             --fresh, -f Filter results by stores serving fresh donuts
21             --raw, -r Print raw data structure returned from search response
22              
23             EOF
24              
25             has ua => sub { Mojo::UserAgent->new() };
26              
27             has [qw( geo fresh raw )];
28              
29             sub _mk_request {
30 0     0     my ($self, $url, $form) = @_;
31 0 0         my $tx = $form ? $self->ua->get($url) : $self->ua->post($url => form => $form);
32              
33 0 0         unless ($tx->success) {
34 0           my $err = $tx->error;
35 0           die join(
36             '', #
37             'Trouble finding IP address.',
38             'If problem persists, you might have to provide geo.',
39             "$url error code and response:",
40             $err->{code}, $err->{response},
41             );
42             }
43 0           return $tx->res;
44             }
45              
46             sub _ip2geo {
47 0     0     my ($self, $ip) = @_;
48              
49             # fetch latitude and longitude from geocodeip.com
50             my $geo = $self->_mk_request('http://www.geocodeip.com/', {IP => $ip})
51             ->dom->find('div#data_display > table.table > tr > td')
52 0     0     ->grep(sub { $_->text =~ /\b(?:Latitude|Longitude)\b/; })
53 0     0     ->map(sub { $_->following->first->text })->to_array;
  0            
54              
55 0 0 0       die 'Failed to scape geo from geocodeip.com. You may need to provide geo instead.'
      0        
56             unless $geo
57             && $geo->[0]
58             && $geo->[1];
59              
60 0           return $geo;
61             }
62              
63             sub _geocode_ip {
64 0     0     my $self = shift;
65              
66 0 0         return if $self->geo;
67              
68 0           my $ip = $self->_mk_request('http://icanhazip.com')->body;
69 0           return $self->_ip2geo($ip);
70             }
71              
72             sub run {
73 0     0 1   my ($self, @args) = @_;
74              
75             GetOptionsFromArray(
76             \@args, #
77 0     0     'geo|g=s' => sub { $self->geo([split ',', $_[1]]) },
78 0     0     'fresh|f' => sub { $self->fresh(1) },
79 0     0     'raw|r' => sub { $self->raw(1) },
80 0           );
81              
82 0           my $base_url = 'http://krispykreme.com/Locate/Location-Search';
83 0           my $hotlight_url = 'http://services.krispykreme.com/api/locationsearchresult/';
84              
85             # user may not provide geo
86 0 0         $self->geo($self->_geocode_ip) unless $self->geo;
87              
88             # get Krispy Kreme stores
89 0           my $tx = $self->ua->get(
90             $hotlight_url => {Referer => $base_url} => form => {
91             responseType => 'Full',
92             lat => $self->geo->[0],
93             lng => $self->geo->[1],
94             search => encode_json(
95             { Where => {
96             LocationTypes => [qw(Store Commissary Franchise)],
97             OpeningDate => {"ComparisonType" => 0},
98             },
99             Take => {Min => 3, DistanceRadius => 100},
100             PropertyFilters => {Attributes => [qw(FoursquareVenueId OpeningType)]},
101             }
102             )
103             }
104             );
105              
106             # pull out the Location key of each store returned
107 0 0         my @locations =
108 0           grep { $self->fresh ? $_->{Hotlight} : 1 }
109 0           map { $_->{Location} } @{$tx->res->json};
  0            
110              
111 0 0         if ($self->raw) {
112 0           say dumper \@locations;
113 0           exit 1;
114             }
115              
116             # print out some info for each store
117 0           for my $loc (@locations) {
118 0           my $addr = join ', ', grep { s/\s+$//; 1 } #
  0            
  0            
119             $loc->{Address1}, $loc->{City}, $loc->{Province};
120              
121 0 0         $addr .= ' [HOTLIGHT ON]' if $loc->{Hotlight};
122              
123 0           say $addr;
124             }
125             }
126              
127             1;
128             __END__