2018-05-25

OpenWeatherMapのAPIで東京の天気を取得して、翌日の最高気温、最低気温を摂氏で表示する。

■メインコード

package Indicate_TEMP;

use Exporter 'import';
our @EXPORT = qw/get_date_temp get_api_data return_temp print_temp/;
our $VERSION = "0.0.1";

use LWP::UserAgent;
use strict;
use warnings;
use utf8;
use Encode;
use JSON::XS 'decode_json';
use Data::Dumper;
use DateTime;



#API Key、URLの代入。
my $date = $ARGV[0];

&get_date_temp($date);

sub get_date_temp{
    my ($date) = @_;
    if (!$date){
        my $dt = DateTime->now(time_zone => 'Asia/Tokyo');
        $dt->add( days => 1 );
        $date = $dt->ymd('-');
    }
    unless ($date =~ /\d{4}-\d{2}-\d{2}/){
        print "Please enter the correct date format.\n";
        return undef;
    }


    my $api_data = &get_api_data;
    my $temp_ref = &return_temp($api_data, $date);
    &print_temp($temp_ref, $date);

    return 1;
}




#apiからのデータの取得処理を行うサブルーチンを作成。
sub get_api_data{
    my $api_key = 'ed0e5aec8d17204480f7bde57279e1af';
    my $base_url = 'http://api.openweathermap.org/data/2.5/forecast';

    my $ua = LWP::UserAgent->new;
    my $res = $ua->get(
            "$base_url?q=tokyo,jp&appid=$api_key&units=metric" # http://api.openweathermap.org/data/2.5/forecast?q=tokyo,jp&appid=ed0e5aec8d17204480f7bde57279e1af&units=metric
            );

    my $file = "{}";
    if ($res->is_success) {
        $file = $res->content;
    } else {
        print "Failed to acquire web data.\n";
        return undef;
    }


    my $api_data = decode_json($file);
    return $api_data;
}


#指定された日の12時の気温、最高気温、最低気温が入ったハッシュリファレンスを返すためのサブルーチンを作成。
sub return_temp{
    my ($api_data, $date) = @_;
    unless (defined($api_data)){
        print "API data is not defined.\n";
        return undef;
    }
    my $date_12pm = $date." 12:00:00";
    my $key;


#12時の気温の取得。
    my $temp_12 = 'undef';
    foreach $key(keys $api_data->{'list'}){
        my $dt_txt_phr = $api_data->{'list'}->[$key]->{'dt_txt'};
        if ($dt_txt_phr) {
            if ($dt_txt_phr =~ /$date_12pm/){
                $temp_12 = $api_data->{'list'}->[$key]->{'main'}->{'temp'};
            }
        }
    }

#最高気温と最低気温の取得。
    my $max;
    my $min;
    my $temp_max;
    my $temp_min;
    foreach $key (keys $api_data->{'list'}) {
        my $dt_txt_phr = $api_data->{'list'}->[$key]->{'dt_txt'};

        if ($dt_txt_phr) {
            if ($dt_txt_phr =~ /$date/){
                $temp_max = $api_data->{'list'}->[$key]->{'main'}->{'temp_max'};
                $temp_min = $api_data->{'list'}->[$key]->{'main'}->{'temp_min'};

                unless (defined($max)){
                    $max = $temp_max;
                }
                unless (defined($min)){
                    $min = $temp_min;
                }

                if ($max < $temp_max) {
                    $max = $temp_max;
                }
                if ($min > $temp_min) {
                    $min = $temp_min;
                }
            }
        }
    }

    unless (defined($max)) {
        $max = 'undef';
    }
    unless (defined($min)) {
        $min = 'undef';
    }

    my %temp = ("12pm_temp" => "$temp_12", "temp_max" => "$max", "temp_min" => "$min") ;
#print %temp;
    if (%temp){
        return \%temp;
    } else {
        return undef;
    }
}


#指定された日の12時の気温、最高気温、最低気温をprintするためのサブルーチンを作成。
sub print_temp{
    my ($temp_ref, $date) = @_;
    my $str_1 = sprintf (qq/%sの12:00の気温は%s°cです。\n/, $date, $temp_ref->{"12pm_temp"});
    my $str_2 = sprintf (qq/%sの最高気温は%s°cです。\n/, $date, $temp_ref->{"temp_max"});
    my $str_3 = sprintf (qq/%sの最低気温は%s°cです。\n/, $date, $temp_ref->{"temp_min"});

    my $enc_str_1 = encode('utf-8', $str_1);
    my $enc_str_2 = encode('utf-8', $str_2);
    my $enc_str_3 = encode('utf-8', $str_3);

    print $enc_str_1;
    print $enc_str_2;
    print $enc_str_3;
}




1;




■テストコード

use strict;
use warnings;
use JSON::XS 'decode_json';
use Test::More;

BEGIN {
    use_ok('Indicate_TEMP') || BAIL_OUT();
}

diag("Testing Indicate_TEMP $Indicate_TEMP::VERSION, Perl $], $^X");



# サブルーチンが定義されているかのテスト。
ok( defined &Indicate_TEMP::get_date_temp, 'Indicate_TEMP::get_date_temp is defined' );

ok( defined &Indicate_TEMP::get_api_data, 'Indicate_TEMP::get_api_data is defined' );
ok( defined &Indicate_TEMP::return_temp,  'Indicate_TEMP::return_temp is defined' );
ok( defined &Indicate_TEMP::print_temp,   'Indicate_TEMP::print_temp is defined' );




{
    use Indicate_TEMP;

#関数get_date_tempのテスト。
    {
        my $api_data = {'list' => [
            {
                'dt_txt' => '2018-05-24 12:00:00',
                    'main' => {
                        'temp_max' => '18.74',
                        'temp' => '18.74',
                        'temp_min' => '17.61',
                    }
            }
        ]
        };
        my $date = "2018-05-24";
        is( get_date_temp($date), 1);

        $date = "22222222222222";
        is( get_date_temp($date), undef);

        $date = ();
        is( get_date_temp($date), 1);
    }


#関数get_api_dataのテスト
    {
        my $api_data = {'list' => [
            {
                'dt_txt' => '2018-05-24 12:00:00',
                    'main' => {
                        'temp_max' => '18.74',
                        'temp' => '18.74',
                        'temp_min' => '17.61',

                    }
            }
        ]
        };
        ok( get_api_data, $api_data);

        my $file = "";
        ok( get_api_data, undef);

        my $api_key = "";
        ok( get_api_data, undef);

        my $base_url = "";
        ok( get_api_data, undef);

    }

#関数return_tempのテスト
    {
        my $api_data = {'list' => [
            {
                'dt_txt' => '2018-05-24 12:00:00',
                    'main' => {
                        'temp_max' => '18.74',
                        'temp' => '18.74',
                        'temp_min' => '17.61',

                    }
            }
        ]
        };
        my $date = "2018-05-24";

        $api_data = undef;
        is( return_temp($api_data, $date), undef);

    }
}


done_testing;