File Coverage

blib/lib/Time/Vector.pm
Criterion Covered Total %
statement 73 76 96.0
branch 10 16 62.5
condition 5 9 55.5
subroutine 18 18 100.0
pod 1 11 9.0
total 107 130 82.3


line stmt bran cond sub pod time code
1             package Time::Vector;
2              
3 1     1   29464 use strict;
  1         3  
  1         36  
4              
5 1     1   1180 use Time::Simple::Range;
  1         26920  
  1         7  
6 1     1   30 use Time::Seconds;
  1         7  
  1         71  
7 1     1   950 use Bit::Vector::Overload; # this thingy can't be subclassed :(
  1         22415  
  1         88  
8              
9 1     1   11 use base qw/ Class::Accessor::Fast /;
  1         3  
  1         979  
10              
11             use overload
12 1         9 'fallback' => 0,
13             '&' => 'and',
14             '|' => 'or',
15             '=' => 'clone',
16 1     1   517 '""' => 'stringify';
  1         2  
17              
18             our $VERSION = '1.1';
19              
20             __PACKAGE__->mk_accessors(qw/ vec first last /);
21              
22              
23 1     1   112 use constant BITS_PER_DAY => 1440; # 1 bit per minute
  1         2  
  1         909  
24              
25             sub new
26             {
27 9     9 1 36 my ($proto, $vec) = @_;
28 9   33     45 my $class = ref($proto) || $proto;
29              
30 9         46 my $self = bless $proto->SUPER::new(), $class;
31              
32 9 100       141 $self->vec(defined $vec ? $vec : Bit::Vector->new(BITS_PER_DAY));
33 9         188 $self->first(undef);
34 9         56 $self->last(undef);
35              
36 9         63 return bless $self, $class;
37             }
38              
39             sub new_range
40             {
41 5     5 0 4151 my ($proto, @range) = @_;
42            
43 5         14 my $self = new Time::Vector;
44              
45 5         15 while (scalar @range >= 2) {
46 6         37 my @r = splice(@range, 0, 2);
47 6         30 $self->add_range(Time::Simple::Range->new($r[0], $r[1]));
48             }
49              
50 5         64 return $self;
51             }
52              
53              
54             sub add_range
55             {
56 6     6 0 2301 my ($self, $range) = @_;
57              
58 6         16 my $start = $range->start->hours * 60 + $range->start->minutes;
59 6         374 my $end = $range->end->hours * 60 + $range->end->minutes;
60              
61 6 100       342 $end--
62             unless $range->end->seconds == 59;
63              
64 6 100 66     186 $self->first($range->start)
65             if not defined $self->first
66             or $range->start < $self->first;
67              
68 6 50 66     154 $self->last($range->end)
69             if not defined $self->last
70             or $range->end > $self->last;
71              
72             # Bitwise OR between old vector and range vector
73 6         160 my $nv = $self->vec | Bit::Vector->new_Enum(BITS_PER_DAY, "$start-$end");
74              
75 6         420 $self->vec($nv);
76             }
77              
78             sub after
79             {
80 1     1 0 2657 my $self = shift;
81 1 50       5 return undef unless defined $self->last;
82 1         12 return Time::Vector->new_range($self->last, Time::Simple->new('23:59:59'));
83             }
84              
85             sub before
86             {
87 1     1 0 2 my $self = shift;
88 1 50       5 return undef unless defined $self->first;
89 1         16 return Time::Vector->new_range(Time::Simple->new('00:00:00'), $self->first);
90             }
91              
92             sub range
93             {
94 3     3 0 5 my $self = shift;
95 3         5 my @range;
96              
97 3         11 my $base = Time::Simple->new('00:00:00');
98            
99 3         366 my $enum = $self->vec->to_Enum;
100 3         60 foreach my $r (split(/,/, $enum)) {
101 6 50       649 if ($r =~ /^(\d+)-(\d+)$/) {
    0          
102 6         27 my $s = $base + ($1 * 60);
103 6         91 my $e = $base + ($2 * 60) + 60;
104              
105 6         184 push(@range, Time::Simple::Range->new($s, $e));
106             } elsif ($r =~ /^(\d+)$/) {
107 0         0 my $s = $base + ($1 * 60);
108 0         0 my $e = $s + 60;
109 0         0 push(@range, Time::Simple::Range->new($s, $e));
110             }
111             }
112              
113 3         613 return @range;
114             }
115              
116             sub duration
117             {
118 2     2 0 1429 my $self = shift;
119 2         3 my $d = 0;
120              
121 2         6 foreach ($self->range) {
122 4         266 $d += $_->duration;
123             }
124              
125 2         163 return new Time::Seconds($d);
126             }
127              
128             sub and
129             {
130 1     1 0 567 my ($a, $b) = @_;
131 1         5 my $vec = $a->vec & $b->vec;
132 1         46 return Time::Vector->new($vec);
133             }
134              
135             sub or
136             {
137 1     1 0 6 my ($a, $b) = @_;
138 1         4 my $vec = $a->vec | $b->vec;
139 1         36 return Time::Vector->new($vec);
140             }
141              
142             sub stringify
143             {
144 2         156 return join(',', map {
145 1     1 0 5 $_->start->format('%H:%M')
146             . '-'
147             . $_->end->format('%H:%M')
148             } (shift)->range);
149             }
150              
151             sub clone
152             {
153 1     1 0 691 my $self = shift;
154 1         5 return Time::Vector->new($self->vec->Clone);
155             }
156              
157              
158             1;