File Coverage

blib/lib/Geo/StormTracker/Parser.pm
Criterion Covered Total %
statement 15 136 11.0
branch 0 32 0.0
condition n/a
subroutine 5 14 35.7
pod 4 4 100.0
total 24 186 12.9


line stmt bran cond sub pod time code
1             package Geo::StormTracker::Parser;
2 1     1   5 use strict;
  1         2  
  1         26  
3 1     1   4 use Carp;
  1         2  
  1         52  
4 1     1   1064 use Time::Local;
  1         8024  
  1         95  
5 1     1   12 use vars qw($VERSION @ISA);
  1         2  
  1         56  
6 1     1   618 use Geo::StormTracker::Advisory;
  1         11  
  1         1797  
7              
8             $VERSION = '0.02';
9              
10             #-------------------------------------------------------------
11             sub new {
12 0     0 1   my $HR={};
13 0           bless $HR,'Geo::StormTracker::Parser';
14 0           return $HR;
15             }#new
16             #-------------------------------------------------------------
17             sub read {
18 0     0 1   my $self=shift;
19 0           my $fh=shift;
20              
21 0           my @all_lines=<$fh>;
22 0           my $advisory=join('',@all_lines);
23              
24 0           return $self->read_data($advisory);
25             }#read
26             #--------------------------------------------------------------
27             sub read_file {
28 0     0 1   my $self=shift;
29 0           my $filename=shift;
30              
31 0           my ($io,$file,$adv_obj,$msg)=undef;
32              
33 0           $io=IO::File->new();
34 0 0         unless ($io->open("<$filename")){
35 0           $msg="Couldn't open file $filename for reading!";
36 0           carp $msg, "\n";
37 0           return undef;
38             }
39              
40 0           $adv_obj=$self->read_data(join('',($io->getlines)));
41              
42 0           return $adv_obj;
43             }#read_file
44             #--------------------------------------------------------------
45             sub read_data {
46 0     0 1   my $self=shift;
47 0           my $data=shift;
48              
49 0           my ($head,$body)=undef;
50            
51 0           my $adv_obj=Geo::StormTracker::Advisory->new();
52            
53 0           $head=$self->_extract_head($data);
54 0           $adv_obj->stringify_header($head);
55            
56 0           $body=$self->_extract_body($data);
57 0           $adv_obj->stringify_body($body);
58            
59 0           $adv_obj=$self->_grab_head_information($adv_obj,$head);
60            
61 0           $adv_obj=$self->_grab_body_information($adv_obj,$body);
62              
63 0           return $adv_obj;
64             }#read_data
65             #---------------------------------------------------------------
66             sub _extract_head {
67 0     0     my $self=shift;
68 0           my $advisory=shift;
69              
70 0           $advisory =~ s!^[\s*\n]*!!is;
71 0           $advisory =~ m!^(([^\n]*\n){7})!is;
72              
73 0           return $1;
74             }#_extract_head
75             #---------------------------------------------------------------
76             sub _extract_body {
77 0     0     my $self=shift;
78 0           my $advisory=shift;
79              
80 0           $advisory =~ s!^[\s*\n]*!!is;
81 0           $advisory =~ s!^(([^\n]*\n){7})!!is;
82 0           $advisory =~ s!^[\s*\n]*!!is;
83 0           $advisory =~ s!\n[\s*\n]*$!\n!is;
84            
85 0           return $advisory;
86             }#_extract_body
87             #---------------------------------------------------------------
88             sub _grab_head_information{
89 0     0     my $self=shift;
90 0           my $adv_obj=shift;
91 0           my $head=shift;
92              
93 0           my ($name, $advisory_number, $epoch_date)=undef;
94              
95 0           my @head=split("\n",$head);
96 0           chomp(@head);
97              
98 0           $adv_obj->wmo_header($head[1]);
99              
100             #$head[4] =~ m!(^.*\S)\s+ADVISORY!;
101 0           $head[4] =~ m!(^.*?\S)(\s+INTERMEDIATE)?\s+ADVISORY!i;
102 0           $name=$1;
103 0           $adv_obj->name($name);
104              
105 0 0         if ($name =~ m!^TROPICAL DEPRESSION!is){
    0          
    0          
106 0           $adv_obj->event_type('TROPICAL DEPRESSION');
107             }
108             elsif ($name =~ m!^TROPICAL STORM!is){
109 0           $adv_obj->event_type('TROPICAL STORM');
110             }
111             elsif ($name =~ m!^HURRICANE!is){
112 0           $adv_obj->event_type('HURRICANE');
113             }
114             else {
115 0           $adv_obj->event_type('OTHER');
116             }
117              
118             #The advisory number occasionally has a letter as its last character.
119 0           $head[4] =~ m!^.*ADVISORY\s+NUMBER\s+(\d+)([A-Za-z]?)\s*$!i;
120              
121 0           $advisory_number=$1;
122 0 0         if ($2){
123 0           $advisory_number .= uc $2; #make sure letter is upper cased
124             }#if
125              
126 0           $adv_obj->advisory_number($advisory_number);
127            
128 0           $adv_obj->weather_service($head[5]);
129              
130 0           $adv_obj->release_time($head[6]);
131              
132 0           $epoch_date=$self->_extract_epoch_date($head[6]);
133              
134 0           $adv_obj->epoch_date($epoch_date);
135              
136 0           return $adv_obj;
137              
138             }#_grab_head_information
139             #---------------------------------------------------------------
140             sub _extract_epoch_date {
141 0     0     my $self=shift;
142 0           my $release_time=shift;
143            
144 0           my ($match, $month,$mon,$mday,$year, $time)=undef;
145            
146 0 0         return undef unless (defined $release_time);
147            
148 0           my %month_hash=(
149             'JAN'=>0,
150             'FEB'=>1,
151             'MAR'=>2,
152             'APR'=>3,
153             'MAY'=>4,
154             'JUN'=>5,
155             'JUL'=>6,
156             'AUG'=>7,
157             'SEP'=>8,
158             'OCT'=>9,
159             'NOV'=>10,
160             'DEC'=>11,
161             );
162            
163 0           $match=($release_time =~ m!\s(\w{3})\s+(\d+)\s+(\d{4})$!i);
164            
165 0 0         if ($match){
166 0           $month=$1;
167 0           $mday=$2;
168 0           $year=$3;
169            
170 0           $mon=$month_hash{(uc $month)};
171            
172             #$time = timegm($sec,$min,$hours,$mday,$mon,$year);
173 0           $time = timegm(0,0,0,$mday,$mon,$year);
174            
175 0           return $time;
176             }
177             else {
178 0           return undef;
179             }#if/else
180             }#_extract_epoch_date
181             #---------------------------------------------------------------
182             sub _grab_body_information{
183 0     0     my $self=shift;
184 0           my $adv_obj=shift;
185 0           my $body=shift;
186              
187 0           my ($success,$repeating,$lat_digit,$lat_dir,$long_digit,$long_dir)=undef;
188 0           my ($min_central_pressure,$matches,$max_winds,$movement_toward_dir,$movement_toward_speed)=undef;
189            
190 0           $success = ($body =~ m!\n(REPEATING[^\n]*\n(\S[^\n]+\n)+)!is);
191            
192             #If repeating block was found
193 0 0         if ($success) {
194 0           $repeating=$1;
195            
196             #going after position
197 0           $matches=($repeating =~ m!POSITION\s{0,5}\.{0,5}\s{0,5}(\d+\.\d+)\s{0,3}([NS])\s{0,5}\.{0,5}\s{0,5}(\d+\.\d+)\s{0,3}([WE])[\s\.]!is);
198 0 0         if ($matches){
199 0           $lat_digit=$1;
200 0           $lat_dir=$2;
201 0           $long_digit=$3;
202 0           $long_dir=$4;
203 0           $adv_obj->position([$lat_digit,$lat_dir,$long_digit,$long_dir]);
204             }
205            
206             #going after minimum central pressure
207 0           $matches=($repeating =~ m!MINIMUM[\s\n]+CENTRAL[\s\n]+PRESSURE\s{0,5}\.{0,5}\s{0,5}(\d+)\s+MB!is);
208 0 0         if ($matches){
209 0           $adv_obj->min_central_pressure($1);
210             }
211            
212             #going after maximum sustained winds
213 0           $matches=($repeating =~ m!MAXIMUM[\s\n]+SUSTAINED[\s\n]+WINDS\s{0,5}\.{0,5}\s{0,5}(\d+)\s+MPH!is);
214 0 0         if ($matches){
215 0           $adv_obj->max_winds($1);
216             }
217            
218             # #going after movement toward
219             # $matches=($repeating =~ m!MOVEMENT[\s\n]+TOWARD\s{0,5}\.{0,5}\s{0,5}(\S+)[\n\s]+(\d+)\s+MPH!is);
220             # if ($matches){
221             # $movement_toward_dir=$1;
222             # $movement_toward_speed=$2;
223             # $adv_obj->movement_toward([$movement_toward_speed,$movement_toward_dir]);
224             # }
225             }
226             #If repeating block was not found then
227             #look for the information elsewhere in the body.
228             else {
229             #going after position
230 0           $matches=($body =~ m!LATITUDE[^\d]{1,10}(\d+\.\d+)[\s\n]+(NORTH|N|SOUTH|S)!is);
231 0 0         if ($matches){
232 0           $lat_digit=$1;
233 0           $lat_dir=substr($2,0,1);
234             }#if
235 0           $matches=($body =~ m!LONGITUDE[^\d]{1,10}(\d+\.\d+)[\s\n]+(WEST|W|EAST|E)!is);
236 0 0         if ($matches){
237 0           $long_digit=$1;
238 0           $long_dir=substr($2,0,1);
239             }#if
240 0           $adv_obj->position([$lat_digit,$lat_dir,$long_digit,$long_dir]);
241              
242             #going after minimum central pressure
243 0           $matches=($body =~ m!MINIMUM[\s\n]+CENTRAL[\s\n]+PRESSURE[^\d]{0,10}(\d+)\s+MB!is);
244 0 0         if ($matches){
245 0           $adv_obj->min_central_pressure($1);
246             }
247            
248             #going after maximum sustained winds
249 0           $matches=($body =~ m!MAXIMUM[\s\n]+SUSTAINED[\s\n]+WINDS[^\d]{0,20}(\d+)\s+MPH!is);
250 0 0         if ($matches){
251 0           $adv_obj->max_winds($1);
252             }
253            
254             # #going after movement toward
255             # $matches=($body =~ m!MOVING[\s\n]+([\S\n]+)[^\d]{0,20}(\d+)\s+MPH!is);
256             # if ($matches){
257             # $movement_toward_dir=$1;
258             # $movement_toward_speed=$2;
259             # $movement_toward_dir =~ s!\n!!igs;
260             # $adv_obj->movement_toward([$movement_toward_speed,$movement_toward_dir]);
261             # }
262            
263             }#if/else
264              
265             #going after a final advisory notice.
266 0           $matches=($body =~ m!THIS\s*[\s\n]WILL\s*[\s\n]BE\s*[\s\n]THE\s*[\s\n]LAST\s*[\s\n]PUBLIC\s*[\s\n]ADVISORY!is);
267 0 0         if ($matches){
268 0           $adv_obj->is_final(1);
269             }
270             else {
271 0           $adv_obj->is_final(0);
272             }
273              
274 0           return $adv_obj; #Wasn't that painfull
275              
276             }#_grab_body_information
277             #---------------------------------------------------------------
278              
279             1;
280             __END__