File Coverage

blib/lib/App/JobLog/Vacation.pm
Criterion Covered Total %
statement 24 102 23.5
branch 4 36 11.1
condition 0 3 0.0
subroutine 8 14 57.1
pod 7 7 100.0
total 43 162 26.5


line stmt bran cond sub pod time code
1             package App::JobLog::Vacation;
2             $App::JobLog::Vacation::VERSION = '1.039';
3             # ABSTRACT: controller for the vacation model
4              
5              
6 2     2   1602 use Modern::Perl;
  2         4  
  2         17  
7 2     2   1686 use App::JobLog::Vacation::Period;
  2         6  
  2         84  
8 2         100 use App::JobLog::Config qw(
9             vacation
10             init_file
11 2     2   12 );
  2         4  
12 2     2   10 use Carp qw(carp);
  2         4  
  2         70  
13 2     2   11 use FileHandle;
  2         3  
  2         44  
14              
15              
16             sub new {
17 13     13 1 173 my $class = shift;
18 13 50       57 $class = ref $class if ref $class;
19 13         83 my $self = bless { changed => 0 }, $class;
20 13 50       73 if ( -e vacation ) {
21 0         0 my $fh = FileHandle->new(vacation);
22 0         0 my @data;
23 0         0 while ( my $line = <$fh> ) {
24 0         0 chomp $line;
25 0         0 my $v = App::JobLog::Vacation::Period->parse($line);
26 0         0 push @data, $v;
27             }
28 0         0 $self->{data} = [ sort { $a->cmp($b) } @data ];
  0         0  
29             }
30 13         90 return $self;
31             }
32              
33              
34 13 50   13 1 24 sub periods { @{ $_[0]->{data} || [] } }
  13         152  
35              
36              
37             sub close {
38 0     0 1 0 my ($self) = @_;
39 0 0       0 if ( $self->{changed} ) {
40 0         0 $self->{changed} = 0;
41 0 0       0 if ( @{ $self->{data} } ) {
  0 0       0  
42              
43             # something to save
44 0 0       0 init_file(vacation) unless -e vacation;
45 0         0 my $fh = FileHandle->new( vacation, 'w' );
46 0         0 for my $v ( @{ $self->{data} } ) {
  0         0  
47 0         0 print $fh $v, "\n";
48             }
49 0         0 $fh->close;
50             }
51             elsif ( -e vacation ) {
52 0         0 unlink(vacation);
53             }
54             }
55             }
56              
57             # make sure changes are written to the file
58             sub DESTROY {
59 13     13   25 my ($self) = @_;
60 13 50       114 $self->close if $self->{changed};
61             }
62              
63              
64             sub add {
65 0     0 1   my ( $self, %opts ) = @_;
66 0           my ( $end, $type, $repeats ) = @opts{qw(end type repeats)};
67 0           delete @opts{qw(end type repeats)};
68 0           my $ll = App::JobLog::Log::Line->new(%opts);
69 0           my $v = App::JobLog::Vacation::Period->new(
70             $ll,
71             end => $end,
72             type => $type,
73             repeats => $repeats
74             );
75 0 0         my @data = @{ $self->{data} || [] };
  0            
76              
77 0           for my $other (@data) {
78 0 0         if ( $other->conflicts($v) ) {
79 0           my $d1 = join ' ', $v->parts;
80 0           my $d2 = join ' ', $other->parts;
81 0           carp "$d1 conflicts with existing period $d2";
82             }
83             }
84 0           push @data, $v;
85 0           $self->{data} = [ sort { $a->cmp($b) } @data ];
  0            
86 0           $self->{changed} = 1;
87             }
88              
89              
90             sub remove {
91 0     0 1   my ( $self, $index ) = @_;
92 0 0         carp 'vacation date index must be non-negative' if $index < 0;
93 0           my $data = $self->{data};
94 0 0 0       carp "unknown vacation index: $index" unless $data && @$data >= $index;
95 0           splice @$data, $index - 1, 1;
96 0           $self->{changed} = 1;
97             }
98              
99              
100             sub show {
101 0     0 1   my ($self) = @_;
102 0           my @parts;
103             my $widths;
104 0           for my $v ( $self->periods ) {
105 0           my @p = $v->parts;
106 0           push @parts, \@p;
107 0           my $w = _widths( \@p );
108 0 0         if ($widths) {
109 0           for ( 0 .. $#$w ) {
110 0           my ( $l1, $l2 ) = ( $w->[$_], $widths->[$_] );
111 0 0         $widths->[$_] = $l1 if $l1 > $l2;
112             }
113             }
114             else {
115 0           $widths = $w;
116             }
117             }
118 0 0         return [] unless @parts;
119 0           my $format = sprintf "%%%dd) %%%ds %%-%ds %%-%ds %%-%ds\n",
120             length scalar(@parts),
121             @$widths;
122 0           for my $i ( 0 .. $#parts ) {
123 0           $parts[$i] = sprintf $format, $i + 1, @{ $parts[$i] };
  0            
124             }
125 0           return \@parts;
126             }
127              
128              
129             sub add_overlaps {
130 0     0 1   my ( $self, $events ) = @_;
131 0           my ( %day_map, @overlaps );
132 0           for my $e (@$events) {
133 0           for my $v ( @{ $self->{data} } ) {
  0            
134 0           my $o = $v->overlap($e);
135 0 0         if ($o) {
136 0           my $s = $o->start . ' ' . $o->end;
137 0 0         unless ( $day_map{$s} ) {
138 0           $day_map{$s} = 1;
139 0           push @overlaps, $o;
140             }
141             }
142             }
143             }
144 0 0         return $events unless @overlaps;
145 0           push @overlaps, @$events;
146 0           return [ sort { $a->cmp($b) } @overlaps ];
  0            
147             }
148              
149             # collect the widths of a list of strings
150             sub _widths {
151 0     0     my ($ar) = @_;
152 0           my @w;
153 0           push @w, length $_ for @$ar;
154 0           return \@w;
155             }
156              
157             1;
158              
159             __END__