-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adapted Weather::WWO to Weather::Underground::Forecast
- Loading branch information
Showing
6 changed files
with
254 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
.project | ||
.includepath | ||
.build | ||
Weather-Underground-Forecast* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
{{$NEXT}} | ||
- Initial Release |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
name = Weather-Underground-Forecast | ||
abstract = Weather Underground Forecast Data | ||
|
||
[VersionFromModule] | ||
|
||
[NextRelease] | ||
|
||
[@Git] | ||
|
||
[@Basic] | ||
|
||
[PodSyntaxTests] | ||
[PodCoverageTests] | ||
[CriticTests] | ||
|
||
[AutoPrereqs] | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,199 @@ | ||
package Weather::Underground::Forecast; | ||
use Moose; | ||
use namespace::autoclean; | ||
use LWP::Simple; | ||
use XML::Simple; | ||
|
||
use Data::Dumper::Concise; | ||
|
||
our $VERSION = '0.01'; | ||
|
||
=head1 Name | ||
Weather::Underground::Forecast - Simple API to Weather Underground Forecast Data | ||
=head1 Synopsis | ||
Get the weather forecast: | ||
my $forecast = Weather::Underground::Forecast->new( | ||
location => $location, | ||
temperature_units => 'fahrenheit', # or 'celsius' | ||
); | ||
Where the $location can be: | ||
* city,state (Bloomington,IN) | ||
* zip code (47401) | ||
* latitude,longitude (46,-113) | ||
my ($highs, $lows) = $forecast->temperatures; | ||
NOTE: I<location> is the only required parameter to C<new()> | ||
=cut | ||
|
||
has 'location' => ( | ||
is => 'rw', | ||
isa => 'Str', | ||
required => 1, | ||
writer => 'set_location', | ||
); | ||
has 'temperature_units' => ( | ||
is => 'ro', | ||
isa => 'Str', | ||
'default' => 'fahrenheit', | ||
); | ||
has 'data' => ( | ||
is => 'rw', | ||
isa => 'ArrayRef[HashRef]', | ||
lazy_build => 1, | ||
); | ||
has 'source_URL' => ( | ||
is => 'ro', | ||
isa => 'Any', | ||
lazy_build => 1, | ||
); | ||
|
||
# When the location changes, we want to clear the data to insure a new data fetch will happen. | ||
# We need this since data is lazily built, and we used a distinct name for the writer | ||
# so we only clear data when we set the location anytime after initial object construction. | ||
after 'set_location' => sub { | ||
my $self = shift; | ||
$self->clear_data; | ||
}; | ||
|
||
=head1 Methods | ||
=head2 temperatures | ||
Get the high and low temperatures for the number of days specified. | ||
Returns: Array of two ArrayRefs being the high and low temperatures | ||
Example: my ($highs, $lows) = $wunder->forecast_temperaures; | ||
=cut | ||
|
||
sub temperatures { | ||
my $self = shift; | ||
return ( $self->highs, $self->lows ); | ||
} | ||
|
||
=head2 highs | ||
Get an ArrayRef[Int] of the forecasted high temperatures. | ||
=cut | ||
|
||
sub highs { | ||
my $self = shift; | ||
|
||
my $key1 = 'high'; | ||
my $key2 = $self->temperature_units; | ||
return $self->get_forecast_data_by_two_keys( $key1, $key2 ); | ||
} | ||
|
||
=head2 lows | ||
Get an ArrayRef[Int] of the forecasted low temperatures. | ||
=cut | ||
|
||
sub lows { | ||
my $self = shift; | ||
|
||
my $key1 = 'low'; | ||
my $key2 = $self->temperature_units; | ||
return $self->get_forecast_data_by_two_keys( $key1, $key2 ); | ||
} | ||
|
||
=head2 precipitation | ||
Get an ArrayRef[Int] of the forecasted chance of precipitation. | ||
=cut | ||
|
||
sub precipitation { | ||
my $self = shift; | ||
|
||
return $self->get_forecast_data_by_one_key('pop'); | ||
} | ||
|
||
=head2 get_forecast_data_by_one_key | ||
Get the values for a single forecast metric that is | ||
only one key deep. An examples is: 'pop' (prob. of precip.) | ||
NOTE: One can dump the data attribute to see | ||
the exact data structure and keys available. | ||
=cut | ||
|
||
sub get_forecast_data_by_one_key { | ||
my ( $self, $key ) = @_; | ||
|
||
return [ map { $_->{$key} } @{ $self->data } ]; | ||
} | ||
|
||
=head2 get_forecast_data_by_two_keys | ||
Like the one_key method above but for values that are | ||
two keys deep in the data structure. | ||
=cut | ||
|
||
sub get_forecast_data_by_two_keys { | ||
my ( $self, $key1, $key2 ) = @_; | ||
|
||
return [ map { $_->{$key1}->{$key2} } @{ $self->data } ]; | ||
} | ||
|
||
sub _query_URL { | ||
my $self = shift; | ||
return $self->source_URL . $self->location; | ||
} | ||
|
||
# Builders | ||
|
||
sub _build_data { | ||
my $self = shift; | ||
|
||
my $content = get( $self->_query_URL ); | ||
die "Couldn't get URL: ", $self->_query_URL unless defined $content; | ||
|
||
my $xml = XML::Simple->new; | ||
my $data_ref = $xml->XMLin($content); | ||
my $forecasts = $data_ref->{simpleforecast}->{forecastday}; | ||
|
||
return $forecasts; | ||
} | ||
|
||
sub _build_source_URL { | ||
my $self = shift; | ||
return | ||
'http://api.wunderground.com/auto/wui/geo/ForecastXML/index.xml?query='; | ||
} | ||
|
||
__PACKAGE__->meta->make_immutable; | ||
1 | ||
|
||
__END__ | ||
=head1 Limitations | ||
It is possible that location could have more than one forecast. | ||
The behavior of that possibility has not been tested. | ||
=head1 Authors | ||
Mateu Hunter C<hunter@missoula.org> | ||
=head1 Copyright | ||
Copyright 2010, Mateu Hunter | ||
=head1 License | ||
You may distribute this code under the same terms as Perl itself. | ||
=cut |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
use strict; | ||
use warnings; | ||
use Test::More; | ||
use Weather::Underground::Forecast; | ||
use LWP::Simple; | ||
use Data::Dumper::Concise; | ||
|
||
my $wunder_forecast = Weather::Underground::Forecast->new( | ||
location => 'Missoula,MT', | ||
temperature_units => 'fahrenheit', # or 'celsius' | ||
); | ||
|
||
isa_ok( $wunder_forecast, 'Weather::Underground::Forecast' ); | ||
can_ok( 'Weather::Underground::Forecast', ( 'temperatures', 'precipitation' ) ); | ||
|
||
SKIP: | ||
{ | ||
|
||
# Test internet connection | ||
my $source_URL = $wunder_forecast->_query_URL; | ||
my $content = get($source_URL); | ||
skip( 'Skipping live test using Internet', 3 ) if !$content; | ||
|
||
my ( $highs, $lows ) = $wunder_forecast->temperatures; | ||
my $chance_of_precip = $wunder_forecast->precipitation; | ||
is( ref($highs), 'ARRAY', 'highs data structure' ); | ||
is( ref($lows), 'ARRAY', 'lows data structure' ); | ||
is( ref($chance_of_precip), 'ARRAY', 'precips data structure' ); | ||
} | ||
|
||
done_testing(); |