Parsing JSON With Perl 6

Aside from my usual meanderings about in C++ land I’ve been playing with Perl 6. I used to use Perl 5 back in the day, so I’m not totally lost when it comes to sprinkling sigils around everywhere in my code. From first impressions, however, Perl 6 really does feel like a much cleaner, more consistent language than its older sister.

It’s raining tonight in Windsor, Ontario (across from Detroit, Michigan for those of you who don’t know your Canadian geography), and I thought it would be a nice evening to build a program that interfaces with the Weather Underground Developer API. I have some code I’ve written previously in Haskell that does this, but I thought I’d give it a whirl in Perl to see how it handles downloading and parsing JSON files.

Here we go.

The first thing we do is tell the interpreter that we’re using Perl 6. This declaration is optional, but it’s helpful to prevent your code from being treated as Perl 5 if you happen to run it through the wrong interpreter.

use v6

We next introduce a function for fetching the raw JSON from the Weather Underground web service. Notice that my parameters are all of type Str, which is Perl 6’s string type. Perl 6 is a gradually typed language, but declarations such as these can help you catch errors earlier.

sub get-json(Str $key, Str $state, Str $city)
{
    use HTTP::Tinyish;
    use JSON::Tiny;

    my $url = "http://api.wunderground.com/api/$key/conditions/"
            ~ "q/$state/$city.json";

    my $http = HTTP::Tinyish.new: agent => 'Mozilla/4.0';
    my %res = $http.get: $url;
    from-json %res<content>;
}

Also of note is a local import statement. The first two lines of the function state that I am using the modules HTTP::Tinyish and JSON::Tiny. These statements can also be placed at the top of the file, but since I’m only using their provided functionality in one function, I figured I’d just place them here.

The next line creates a scalar variable storing the URL to fetch. It uses string interpolation to place the API key, city and state into the string.

We then fetch the data via an HTTP get request. First we create an object capable of sending requests, then we get the result and store it in the hash map %res. We then pass the string data stored under the key “content” to the from-json function, which returns another hash map representing the parsed JSON object.

The next function isn’t too exciting: it takes in a hash map of data as a parameter, and then by using the say function, it outputs some of the values to standard out.

sub print-weather(%data)
{
    my %obs = %data<current_observation>;

    say "Current weather for {%obs<display_location><full>}";
    say "--------------------------------------------------";

    say "Station ID:\t{%obs<station_id>}";
    say "Weather:\t{%obs<weather>}";
    say "Temperature:\t{%obs<temperature_string>}";
    say "Feels Like:\t{%obs<feelslike_string>}";
    say "Rel. Humidity:\t{%obs<relative_humidity>}";
    say "Dewpoint:\t{%obs<dewpoint_string>}";
}

Finally we tie it all together with a main function. A main function is not required in Perl as it is in, say, C or C++. But I do prefer having one as to not have too many statements sitting at the file level.

sub main
{
    my $key = 'insert-key-here';
    my $state = 'Michigan';
    my $city = 'Detroit';

    my %data = get-json $key, $state, $city;
    print-weather %data;
}

You will need an API key from Weather Underground to execute this, of course. Running this program will output something along these lines:

Current weather for Detroit, MI
--------------------------------------------------
Station ID:	KMIDETRO27
Weather:	Light Rain
Temperature:	59.9 F (15.5 C)
Feels Like:	59.9 F (15.5 C)
Rel. Humidity:	99%
Dewpoint:	60 F (15 C)

All in all, I really like Perl 6. It makes getting simple things done easy. It took me no more than 10 minutes to go from searching for modules to implementing my program. It’s a very flexible language that supports programming in many different paradigms, so I can write functional code with maps, folds, and all that, but still reach for objects with inheritance and polymorphism if I need them. If you haven’t yet looked at Perl 6, what are you waiting for?