File Coverage

blib/lib/App/TimeClock/Weekly/Report.pm
Criterion Covered Total %
statement 31 46 67.3
branch 8 20 40.0
condition 7 9 77.7
subroutine 9 12 75.0
pod 2 2 100.0
total 57 89 64.0


line stmt bran cond sub pod time code
1             package App::TimeClock::Weekly::Report;
2              
3 2     2   42572 use strict;
  2         3  
  2         55  
4 2     2   10 use warnings;
  2         9  
  2         67  
5              
6 2     2   628 use POSIX qw(difftime strftime);
  2         7597  
  2         11  
7 2     2   2612 use Time::Local;
  2         2992  
  2         1459  
8              
9             my $EOL_RE = qr/[\r\n]+\z/;
10              
11             =head1 NAME
12              
13             App::TimeClock::Weekly::Report
14              
15             =head1 DESCRIPTION
16              
17             Can parse the timelog and generate a report using an instance of a
18             L.
19              
20             =head2 METHODS
21              
22             =over
23              
24             =item new($timelog, $printer)
25              
26             Initializes a new L object.
27              
28             Two parameters are required:
29              
30             =over
31              
32             =item B<$timelog>
33              
34             Must point to a timelog file. Will die if not.
35              
36             =item B<$printer>
37              
38             An object derived from L. Will die if not.
39              
40             =back
41              
42             =cut
43             sub new {
44 9 100   9 1 1417 die "must supply (timelog, printer) arguments to constructor" if $#_ != 2;
45 7         9 my $class = shift;
46 7         18 my $self = {
47             timelog => shift,
48             printer => shift,
49             };
50 7 100 66     178 die "timelog ($self->{timelog}) does not exist" unless -f $self->{timelog} and -r $self->{timelog};
51             die "printer is not a PrinterInterface" unless ref $self->{printer} and
52 6 100 100     73 UNIVERSAL::can($self->{printer},'isa') and $self->{printer}->isa("App::TimeClock::Weekly::PrinterInterface");
      66        
53 4         35 bless $self, $class;
54             };
55              
56              
57             =item _timelocal()
58              
59             Returns a time (seconds since epoch) from a date and time.
60              
61             =cut
62             sub _timelocal {
63 1     1   2 my ($self, $date, $time) = @_;
64 1         5 my ($year, $mon, $mday) = split(/\//, $date);
65 1         4 my ($hours, $min, $sec ) = split(/:/, $time);
66              
67 1         8 return timelocal($sec, $min, $hours, $mday, $mon-1, $year);
68             };
69              
70              
71             =item _get_report_time()
72              
73             Returns the time when the report was executed.
74              
75             =cut
76 0 0   0   0 sub _get_report_time { $_[0]->{_report_time} || time }
77              
78              
79             =item _set_report_time()
80              
81             Sets the time when the report is executed.
82              
83             =cut
84 1     1   10 sub _set_report_time { $_[0]->{_report_time} = $_[0]->_timelocal($_[1], $_[2]) }
85              
86              
87             =item _read_lines()
88              
89             Reads a set of check in and check out lines.
90              
91             If end of file is reached after reading the check in line, then
92             reading of the check out line is skipped.
93              
94             =cut
95             sub _read_lines {
96              
97 0     0   0 my ($self, $file) = (@_);
98 0         0 my ($iline, $oline) = (undef, undef);
99              
100 0 0       0 die "Prematurely end of file." if eof($file);
101              
102 0         0 ($iline = <$file>) =~ s/$EOL_RE//g;
103              
104 0 0       0 die "Expected check in in line $." unless $iline =~ /^i /;
105            
106 0 0       0 if (not eof($file)) {
107 0         0 ($oline = <$file>) =~ s/$EOL_RE//g;
108 0 0       0 die "Excepted check out in line $." unless $oline =~ /^o /;
109             }
110              
111 0         0 return ($iline, $oline);
112             }
113              
114              
115             =item _parse_lines()
116              
117             Parses a set of check in and check out lines.
118              
119             The lines are split on space and should contain the following four
120             fields:
121              
122             =over
123              
124             =item state
125              
126             is either 'i' - check in or 'o' - check out.
127              
128             =cut
129              
130             =item date
131              
132             is formatted as YYYY/MM//DD
133              
134             =cut
135              
136             =item time
137              
138             is formatted as HH:MM:SS
139              
140             =cut
141              
142             =item project
143              
144             is then name of the project/task and is only required when checking in.
145              
146             =cut
147              
148             =back
149              
150             =cut
151             sub _parse_lines {
152 0     0   0 my ($self, $file) = (@_);
153 0         0 my ($iline, $oline) = $self->_read_lines($file);
154              
155 0         0 my ($idate, $itime, $iproject) = (split(/ /, $iline, 4))[1..3];
156 0 0       0 my ($odate, $otime, $oproject) = (defined $oline) ? (split(/ /, $oline, 4))[1..3] :
157             (strftime("%Y/%m/%d", localtime($self->_get_report_time)),
158             strftime("%H:%M:%S", localtime($self->_get_report_time)), "DANGLING");
159            
160 0         0 return ($idate, $itime, $iproject, $odate, $otime, $oproject);
161             }
162              
163              
164             =item execute()
165              
166             Opens the timelog file starts parsing it, looping over each day and
167             calling print_day() for each.
168              
169             =cut
170             sub execute {
171 2     2 1 135 my $self = shift;
172              
173 2 100   2   31 open (my $file, "<:encoding(UTF-8)", $self->{timelog}) or die "$!\n";
  2         2  
  2         13  
  2         77  
174              
175 1         8107 $self->{printer}->print_header;
176              
177 1         4 $self->{printer}->print_week();
178              
179 1         3 $self->{printer}->print_footer();
180             };
181             1;
182              
183             =back
184              
185             =for text
186             =encoding utf-8
187             =end
188              
189             =head1 AUTHOR
190              
191             Søren Lund, C<< >>
192              
193             =head1 SEE ALSO
194              
195             L
196              
197             =head1 COPYRIGHT
198              
199             Copyright (C) 2012-2014 Søren Lund
200              
201             This file is part of App::TimeClock.
202              
203             App::TimeClock is free software: you can redistribute it and/or modify
204             it under the terms of the GNU General Public License as published by
205             the Free Software Foundation, either version 3 of the License, or
206             (at your option) any later version.
207              
208             App::TimeClock is distributed in the hope that it will be useful,
209             but WITHOUT ANY WARRANTY; without even the implied warranty of
210             MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
211             GNU General Public License for more details.
212              
213             You should have received a copy of the GNU General Public License
214             along with App::TimeClock. If not, see .