# Remove this line and fix the line below
# #!/usr/bin/perl
use strict;
use warnings;
use File::Temp qw/tempfile/;
use Getopt::Long;
use POSIX qw/strftime/;
use Time::Local qw/timelocal/;
my $FORECAST_URL = 'http://www.ssec.wisc.edu/cgi-bin/lc?mad_for';
GetOptions('test' => \&run_tests);
# fetch_forecast() => HTML string
#
# Fetches the current forecast web page from $FORECAST_URL and returns it as a
# single string. Returns "undef" upon failure.
sub fetch_forecast {
my $forecast = `curl --fail --silent $FORECAST_URL`;
return undef if $? != 0;
return $forecast;
}
# extract_timestamp(html) => timestamp string
#
# Extracts the timestamp (date and time) of the given forecast web page and
# returns it as a string (with no surrounding whitespace). Returns "undef" upon
# failure.
sub extract_timestamp {
my $html_string = shift;
if ($html_string =~ /Local Madison Forecast\n(.*?)\n
/) {
return $1;
}
return undef;
}
# convert_timestamp(string) => Unix time
#
# Extracts date and time information from the forecast timestamp and converts it
# to a Unix timestamp value. Returns the (integer) Unix timestamp upon success,
# or "undef" otherwise.
sub convert_timestamp {
# WRITE THIS SUBROUTINE!
}
# extract_temperature_prediction(html, period) => prediction
#
# Examines the given HTML for a temperature prediction for the given period
# (which should be 'today' or 'tonight'). If found, returns the temperature
# prediction string from the forecast, but with all whitespace normalized to
# single space characters. Returns "undef" upon failure.
sub extract_temperature_prediction {
my ($html, $day) = @_;
$day = uc($day);
my $keyword = ($day eq 'TODAY') ? 'HIGHS' : 'LOWS';
return undef unless $html =~ m,(?:REST OF )?$day\.+(.+?)\s*
,ms;
(my $forecast = $1) =~ s/\s+/ /gm;
return undef unless $forecast =~ /\b(?:${keyword}|NEAR STEADY TEMPERATURE) (.*?)\./;
my $phrase = $1;
$phrase =~ s/^IN THE //;
return $phrase;
}
# write_file(filename, contents) => status
#
# Writes the given string contents to the given file safely. Returns true upon
# success or false otherwise.
sub write_file {
# WRITE THIS SUBROUTINE!
}
# ==============================================================================
my $forecast = fetch_forecast()
or die "$0: failed to download forecast from '$FORECAST_URL'\n";
my $timestamp_string = extract_timestamp($forecast)
or die "$0: could not extract timestamp -- check format!\n";
my $unix_timestamp = convert_timestamp($timestamp_string)
or die "$0: could not parse timestamp -- check format!\n";
my $high_text = extract_temperature_prediction($forecast, 'today')
or die "$0: could not get prediction from 'TODAY' section\n";
my $low_text = extract_temperature_prediction($forecast, 'tonight')
or die "$0: could not get prediction from 'TONIGHT' section\n";
my @time = localtime($unix_timestamp);
my $date_string = strftime('%Y-%m-%d', @time);
my $time_string = strftime('%H:%M', @time);
write_file("wx-$date_string.txt", "$date_string\t$time_string\t$high_text\t$low_text\n")
or die "$0: could not save forecast file: $!\n";
# ==============================================================================
sub run_tests {
require Test::More;
Test::More->import;
plan(tests => 7);
# extract_timestamp
my $sample_html = <
Madison Forecast
Local Madison Forecast
800 PM CDT THU JUL 28 2011
TONIGHT...MOSTLY CLOUDY. CHANCE OF SHOWERS AND SLIGHT CHANCE OF
EOF
is(extract_timestamp($sample_html), '800 PM CDT THU JUL 28 2011', 'extract ts from real data');
is(extract_timestamp('not a valid HTML string'), undef, 'extract ts fail');
# convert_timestamp -- http://www.epochconverter.com/
is(convert_timestamp('1034 AM CDT THU JUL 29 2010'), 1280417640, 'ts 2d am');
is(convert_timestamp('1241 PM CDT SAT JUL 31 2010'), 1280598060, 'ts 2d pm 12');
# extract_temperature_prediction
my $sample_forecast_1 = <Madison Forecast
Local Madison Forecast
647 AM CDT FRI JUL 29 2011
TODAY...SUNNY. HIGHS IN THE UPPER 80S. NORTHWEST WINDS UP TO
5 MPH.
TONIGHT...CLEAR. AREAS OF FOG AFTER MIDNIGHT. LOWS IN THE LOWER
60S. WEST WINDS UP TO 5 MPH THROUGH AROUND MIDNIGHT BECOMING
CALM.
SATURDAY...SUNNY. AREAS OF FOG IN THE MORNING. HIGHS IN THE
UPPER 80S. SOUTHWEST WINDS UP TO 5 MPH.
EOF
is(extract_temperature_prediction($sample_forecast_1, 'today'), 'UPPER 80S', 'real predict 1');
is(extract_temperature_prediction($sample_forecast_1, 'tonight'), 'LOWER 60S', 'real predict 2');
my $sample_forecast_2 = "REST OF TODAY...MOSTLY CLOUDY WITH ISOLATED THUNDERSTORMS. NEAR STEADY TEMPERATURE IN THE UPPER 70S. NORTH WINDS UP TO 10 MPH.\nCHANCE OF THUNDERSTORMS 20 PERCENT.\n
";
is(extract_temperature_prediction($sample_forecast_2, 'today'), 'UPPER 70S', 'predict near steady');
exit 0;
}