# 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; }