File Coverage

blib/lib/Bank/Holidays.pm
Criterion Covered Total %
statement 64 73 87.6
branch 23 34 67.6
condition 2 6 33.3
subroutine 9 9 100.0
pod 0 3 0.0
total 98 125 78.4


line stmt bran cond sub pod time code
1             package Bank::Holidays;
2              
3 3     3   1589 use 5.006001;
  3         8  
  3         95  
4 3     3   13 use strict;
  3         4  
  3         80  
5 3     3   16 use warnings;
  3         12  
  3         110  
6 3     3   1807 use HTML::TableExtract;
  3         34279  
  3         20  
7 3     3   2142 use LWP::UserAgent;
  3         234233  
  3         93  
8 3     3   2717 use DateTime;
  3         370024  
  3         2242  
9              
10             require Exporter;
11              
12             our @ISA = qw(Exporter);
13              
14             # Items to export into callers namespace by default. Note: do not export
15             # names by default without a very good reason. Use EXPORT_OK instead.
16             # Do not simply export all your public functions/methods/constants.
17              
18             # This allows declaration use Bank::Holidays ':all';
19             # If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
20             # will save memory.
21             our %EXPORT_TAGS = (
22             'all' => [
23             qw( is_holiday reserve_holidays
24              
25             )
26             ]
27             );
28              
29             our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
30              
31             our @EXPORT = qw(
32              
33             );
34              
35             our $VERSION = '0.81';
36              
37             sub new {
38 8     8 0 5271 my ( $package, %params ) = @_;
39              
40 8         9 my $param;
41 8 50       37 $param->{dt} =
    100          
42             $params{dt}
43             ? $params{dt}
44             : $params{date}
45             ? $params{date}
46             : DateTime->now;
47 8         289 $param->{holidays} = reserve_holidays();
48 8         50 bless $param, $package;
49             }
50              
51             sub reserve_holidays() {
52 8     8 0 40 my $te = HTML::TableExtract->new();
53              
54 8         855 my $ua = new LWP::UserAgent;
55              
56 8         5604 $ua->timeout(120);
57              
58 8   33     96 my $home = $ENV{HOME} || $ENV{LOCALAPPDATA};
59              
60 8 50       170 unless ( -d $home . "/.bankholidays" ) {
61 0         0 mkdir( $home . "/.bankholidays" );
62             }
63              
64 8         18 my $cache = $home . "/.bankholidays/frbholidays.html";
65              
66             # Cache the content from the FRB since holdays are unlikely to
67             # change from day to day (or year to year)
68              
69 8         7 my $content;
70              
71 8 50 33     160 if ( -f $cache && ( time() - ( stat($cache) )[9] ) < 86400 ) {
72 8 50       254 open( my $fh, "<", $cache ) or die $!;
73 8         32 local $/ = undef;
74 8         243 $content = <$fh>;
75 8         116 close $fh;
76             }
77             else {
78 0         0 my $url = 'http://www.federalreserve.gov/aboutthefed/k8.htm';
79              
80 0         0 my $request = new HTTP::Request( 'GET', $url );
81              
82 0         0 my $response = $ua->request($request);
83              
84 0         0 $content = $response->content();
85              
86 0 0       0 open( my $fh, ">", $cache ) or die $!;
87 0         0 print $fh $content;
88 0         0 close $fh;
89             }
90              
91 8         36 $te->parse($content);
92              
93 8         88992 my $months = {
94             'January' => 1,
95             'February' => 2,
96             'March' => 3,
97             'April' => 4,
98             'May' => 5,
99             'June' => 6,
100             'July' => 7,
101             'August' => 8,
102             'September' => 9,
103             'October' => 10,
104             'November' => 11,
105             'December' => 12
106             };
107              
108 8         14 my $holidays;
109              
110 8         24 foreach my $ts ( $te->tables ) {
111 24 100       175 next if ( $ts->coords ) != 2;
112 8         38 my @colyears;
113 8         25 foreach my $row ( $ts->rows ) {
114              
115 88 50       4802 next unless @$row;
116 88 50       96 map { s/\r|\n//g if $_ } @$row;
  528         2460  
117 88         70 my $colcount = 0;
118 88         92 foreach my $col (@$row) {
119 528 50       651 if ($col) {
120 528 100       1598 if ( $col =~ /(\d{4})/ ) {
    100          
121 40         69 $colyears[$colcount] = $1;
122             }
123             elsif ( $col =~ /(\w+)\s(\d{1,2})(\*?)/ ) {
124 400         323 push @{ $holidays->{ $colyears[$colcount] }->{ $months->{$1} } },
  400         1463  
125             {
126             day => $2,
127             satflag => $3
128             };
129              
130             }
131             }
132 528         607 $colcount++;
133             }
134             }
135             }
136 8         790 return $holidays;
137             }
138              
139             sub is_holiday {
140 12     12 0 1629 my ( $param, %opts ) = @_;
141              
142 12 50       36 if ( $opts{date} ) {
143 0         0 $param->{dt} = $opts{date};
144             }
145              
146 12 100       32 if ( $opts{Tomorrow} ) {
    100          
147 4         25 $param->{dt}->add( days => 1 );
148             }
149             elsif ( $opts{Yesterday} ) {
150 4         21 $param->{dt}->subtract( days => 1 );
151             }
152 12 50       4954 return 1 if $param->{dt}->dow == 7;
153 12         63 foreach my $holiday ( @{ $param->{holidays}->{ $param->{dt}->year }->{ int( $param->{dt}->month ) } } ) {
  12         46  
154 12 100       140 return 1 if int( $param->{dt}->day ) == $holiday->{day};
155             }
156 6         54 return undef;
157             }
158              
159             # Preloaded methods go here.
160              
161             1;
162             __END__