File Coverage

blib/lib/Weather/Google.pm
Criterion Covered Total %
statement 10 12 83.3
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 14 16 87.5


line stmt bran cond sub pod time code
1             package Weather::Google;
2              
3 2     2   24619 use strict;
  2         4  
  2         67  
4 2     2   11 use warnings;
  2         3  
  2         58  
5 2     2   1614 use LWP::Simple qw/get/;
  2         163733  
  2         23  
6 2     2   2876 use XML::Simple;
  0            
  0            
7             use Carp;
8              
9             our $ENCODE;
10             $ENCODE = 1 if eval { require Encode };
11              
12             our $ENCODING = 'utf-8';
13              
14             our $VERSION = 0.06;
15             our $AUTOLOAD;
16             use constant GAPI => 'http://www.google.com/ig/api?weather=';
17              
18             # Mapping of current supported encodings
19             my %DEFAULT_ENCODINGS = (
20             en => 'latin1',
21             da => 'latin1',
22             de => 'latin1',
23             es => 'latin1',
24             fi => 'latin1',
25             fr => 'latin1',
26             it => 'latin1',
27             ja => 'utf-8',
28             ko => 'utf-8',
29             nl => 'latin1',
30             no => 'latin1',
31             'pt-BR' => 'latin1',
32             ru => 'utf-8',
33             sv => 'latin1',
34             'zh-CN' => 'utf-8',
35             'zh-TW' => 'utf-8',
36             );
37              
38             sub new {
39             my ( $class, $area, $opt ) = @_;
40             carp "Weather::Google is deprecated. Please use a different weather provider.";
41             my $self = {};
42             bless ($self,$class);
43              
44             $self->{xs} = XML::Simple->new;
45              
46             $self->language($opt->{language}) if defined $opt->{language};
47             $self->encoding($opt->{encoding}) if defined $opt->{encoding};
48              
49             return $self unless $area;
50              
51             if ( $area =~ /^\d{5}?$/ ) {
52             $self->zip($area);
53             return $self;
54             }
55              
56             $self->city($area);
57             return $self;
58             }
59              
60             sub _location_url {
61             my ( $self, $loc ) = @_;
62             warn "Weather::Google is deprecated.";
63             return "";
64             # TODO This should be modified to support, i.e., a hash of parameters.
65             my $url = GAPI . $loc;
66             my $lang = $self->language;
67             $url .= "&hl=$lang" if $lang;
68             return $url;
69             }
70              
71             sub zip {
72             my $self = shift;
73             my $zip = shift;
74             unless ( $zip =~ /\d{5}?$/ ) {
75             $self->err("Not a zip code");
76             return;
77             }
78              
79             my $xml = $self->_decode( get( $self->_location_url($zip) ) );
80             my $w = $self->{xs}->xml_in($xml) or return;
81              
82             $self->_parse($w);
83             return 1;
84             }
85              
86             sub city {
87             my $self = shift;
88             my $loc = shift;
89              
90             # Encode the location for URL
91             $loc =~ s/([^\w()’*~!.-])/sprintf '%%%02x', ord $1/eg;
92              
93             my $xml = $self->_decode( get( $self->_location_url($loc) ) );
94             my $w = $self->{xs}->xml_in($xml) or return;
95              
96             $self->_parse($w);
97             return 1;
98             }
99              
100             sub language {
101             my $self = shift;
102              
103             return $self->{lang} unless @_;
104             my $lang = shift;
105              
106             # List of supported languages according to
107             # http://toolbar.google.com/buttons/apis/howto_guide.html#multiplelanguages
108             my %languages = map { $_ => 1 } qw/
109             en da de es fi fr it ja ko nl no pt-BR ru sv zh-CN zh-TW
110             /;
111              
112             unless (defined $languages{$lang}) {
113             warn qq|"$lang" is not a supported ISO language code.\n|;
114             return $self->{lang};
115             }
116              
117             $self->{lang} = $lang;
118             $self->{encoding} ||= $DEFAULT_ENCODINGS{$lang};
119             }
120              
121             sub encoding {
122             my $self = shift;
123              
124             return ( $self->{encoding} ||= $ENCODING ) unless @_;
125             my $encoding = shift;
126              
127             # TODO Check valid encoding
128              
129             $self->{encoding} = $encoding;
130             }
131              
132             sub current_conditions {
133             my $self = shift;
134             return $self->{current} unless @_;
135             my @conds = @_;
136             my @out;
137             foreach my $cond (@conds) {
138             if (defined($self->{current}->{$cond})) {
139             push (@out, $self->{current}->{$cond});
140             } else {
141             $self->err("No current condition $cond");
142             push (@out, undef);
143             }
144             }
145             return $out[0] unless $#out;
146             return @out;
147             }
148              
149             sub forecast_conditions {
150             my $self = shift;
151             return $self->{forecast} unless @_;
152             my $day = shift;
153              
154             $day = 0 if $day =~ /today/i;
155             $day = 1 if $day =~ /tomorrow/i;
156             unless ($day =~ /^\d+$/) {
157             # Only take the first three letters
158             if ($day =~ /^(\w{3})\w*day$/i) {
159             $day = $1;
160             }
161             # Check to see if we have a day that matches
162             for ( my $i = 0; $i <= $#{ $self->{forecast} }; $i++ ) {
163             if ($self->{forecast}->[$i]->{day_of_week} =~ /^$day/i) {
164             $day = $i;
165             last;
166             }
167             }
168             unless ($day =~ /^\d+$/) {
169             # Give up...
170             $self->err("Can't find info for the day $day");
171             return;
172             }
173             }
174             return $self->{forecast}->[$day] unless @_;
175             my @conds = @_;
176             my @out;
177             foreach my $cond (@conds) {
178             if (defined($self->{forecast}->[$day]->{$cond})) {
179             push (@out, $self->{forecast}->[$day]->{$cond});
180             } else {
181             $self->err("No forecast condition $cond for day $day");
182             push (@out, undef);
183             }
184             }
185             return $out[0] unless $#out;
186             return @out;
187             }
188              
189             sub forecast_information {
190             my $self = shift;
191             return $self->{info} unless @_;
192             my @conds = @_;
193              
194             my @out;
195             foreach my $cond (@conds) {
196             if (defined($self->{info}->{$cond})) {
197             push (@out, $self->{info}->{$cond});
198             } else {
199             $self->err("No info condition $cond");
200             push (@out, undef);
201             }
202             }
203             return $out[0] unless $#out;
204             return @out;
205             }
206              
207             sub err {
208             my $self = shift;
209             $self->{ERR} = shift if @_;
210             return $self->{ERR};
211             }
212              
213             sub _decode {
214             my ( $self, $xml ) = @_;
215             if ($ENCODE) {
216             if ( Encode::is_utf8($xml) ) {
217             $xml = Encode::decode_utf8( $xml, $Encode::FB_DEFAULT );
218             }
219             else {
220             $xml = Encode::decode( $self->encoding, $xml, $Encode::FB_DEFAULT );
221             }
222             }
223             else {
224             $xml =~ s/[01[:^ascii:]%]//g;
225             }
226             return $xml;
227             }
228              
229             sub _parse {
230             my $self = shift;
231             my $w = shift;
232              
233             $self->{version} = $w->{version};
234             $w = $w->{weather};
235              
236             $self->{current} = $w->{current_conditions};
237             $self->{forecast} = $w->{forecast_conditions};
238             $self->{info} = $w->{forecast_information};
239              
240             # Make these a bit more readable:
241             foreach my $key ( keys ( %{ $self->{current} } ) ) {
242             $self->{current}->{$key} = $self->{current}->{$key}->{data};
243             }
244             foreach my $key ( keys ( %{ $self->{info} } ) ) {
245             $self->{info}->{$key} = $self->{info}->{$key}->{data};
246             }
247             foreach my $day ( @{ $self->{forecast} } ) {
248             foreach my $key ( keys ( %{ $day } ) ) {
249             $day->{$key} = $day->{$key}->{data};
250             }
251             }
252             }
253              
254             sub DESTROY {
255             }
256              
257             sub AUTOLOAD {
258             my $self = shift;
259              
260             # Alias some things
261              
262             my $name = $AUTOLOAD;
263             $name =~ s/.+:://;
264              
265             # This should prevent warnings of undefined @_
266             @_ = () unless @_;
267              
268             return $self->current_conditions(@_) if $name eq 'current';
269             return $self->forecast_conditions(@_) if $name eq 'forecast';
270             return $self->forecast_information(@_) if $name eq 'info';
271              
272             # Day of week shortcut
273             return $self->forecast_conditions($name,@_) if
274             $name =~ /^(Today|Tomorrow)|((Mon|Tue|Wed|Thu|Fri|Sat|Sun)(\w*day)?)$/i;
275              
276             # Others are considered access methods to current_conditions
277             return $self->current($name);
278             }
279              
280             1;
281              
282             __END__