File Coverage

blib/lib/Dallycot/Value/Duration.pm
Criterion Covered Total %
statement 42 102 41.1
branch 2 12 16.6
condition 3 11 27.2
subroutine 12 22 54.5
pod 0 11 0.0
total 59 158 37.3


line stmt bran cond sub pod time code
1             package Dallycot::Value::Duration;
2             our $AUTHORITY = 'cpan:JSMITH';
3              
4             # ABSTRACT: Date and time values
5              
6 23     23   29398 use strict;
  23         2079  
  23         5570  
7 23     23   2083 use warnings;
  23         30  
  23         4413  
8 23     23   1709 use experimental qw(switch);
  23         31  
  23         148  
9              
10 23     23   2563 use utf8;
  23         1674  
  23         132  
11 23     23   541 use parent 'Dallycot::Value::Any';
  23         29  
  23         127  
12              
13 23     23   1408 use Carp qw(croak);
  23         39  
  23         1284  
14 23     23   105 use DateTime;
  23         40  
  23         563  
15              
16 23     23   104 use List::Util qw(any);
  23         23  
  23         1371  
17 23     23   103 use Scalar::Util qw(blessed);
  23         28  
  23         1065  
18              
19 23     23   113 use Promises qw(deferred);
  23         29  
  23         130  
20              
21             sub new {
22 8     8 0 235 my($class, %options) = @_;
23              
24 8   33     41 $class = ref $class || $class;
25              
26 8         21 for my $k (keys %options) {
27 30 50 33     80 $options{$k} = $options{$k} -> value -> numify if blessed($options{$k}) && $options{$k}->isa('Dallycot::Value::Numeric');
28             }
29              
30 8         18 my $duration_class = delete $options{'class'};
31 8   50     31 $duration_class //= 'DateTime::Duration';
32              
33 8 50       18 if($options{object}) {
34 0         0 return bless [
35             $options{object}->clone
36             ] => $class;
37             }
38             else {
39 11         52 return bless [
40             $duration_class->new(
41 8         16 map { $_ => $options{$_} } grep { $options{$_} } keys %options
  30         39  
42             )
43             ] => $class;
44             }
45             }
46              
47             sub to_rdf {
48 0     0 0 0 my($self, $model) = @_;
49              
50             # we need to record the date/time as represented in RDF, but might want to
51             # record the calendar type as well
52 0         0 my $literal = RDF::Trine::Node::Literal->new(
53             $self -> as_text,
54             '',
55             $model -> meta_uri('xsd:duration')
56             );
57              
58 0         0 return $literal;
59             }
60              
61             sub as_text {
62 0     0 0 0 my($self) = @_;
63              
64 0 0       0 if($self -> [0] -> is_zero) {
65 0         0 return 'P0Y';
66             }
67              
68 0         0 my %amounts;
69              
70 0         0 my $duration = $self -> [0];
71 0         0 my $string = '';
72 0 0       0 if($duration -> is_negative) {
73 0         0 $duration = $duration -> clone -> inverse;
74 0         0 $string = '-';
75             }
76 0         0 $string .= 'P';
77              
78 0         0 @amounts{qw(Y M D h m s)} = $duration -> in_units('years', 'months', 'days', 'hours', 'minutes', 'seconds');
79              
80 0         0 my $days = join("",
81 0         0 map { $amounts{$_} . $_ }
82 0         0 grep { $amounts{$_} > 0 }
83             qw(Y M D)
84             );
85              
86 0         0 my $hours = join("",
87 0         0 map { $amounts{$_} . uc($_) }
88 0         0 grep { $amounts{$_} > 0 }
89             qw(h m s)
90             );
91              
92 0         0 $string .= $days;
93              
94 0 0       0 $string .= 'T' . $hours if $hours ne '';
95              
96 0         0 return $string;
97             }
98              
99             sub value {
100 8     8 0 2177 my($self) = @_;
101              
102 8         37 return $self->[0];
103             }
104              
105             sub negated {
106 0     0 0   my($self) = @_;
107              
108 0           return $self->new( object => $self->[0] -> inverse );
109             }
110              
111             sub is_equal {
112 0     0 0   my ( $self, $engine, $other ) = @_;
113              
114 0           my $d = deferred;
115              
116 0           $d->resolve( 0 == DateTime::Duration->compare( $self->value, $other->value ) );
117              
118 0           return $d->promise;
119             }
120              
121             sub is_less {
122 0     0 0   my ( $self, $engine, $other ) = @_;
123              
124 0           my $d = deferred;
125              
126 0           $d->resolve( 0 > DateTime::Duration->compare( $self->value, $other->value ) );
127              
128 0           return $d->promise;
129             }
130              
131             sub is_less_or_equal {
132 0     0 0   my ( $self, $engine, $other ) = @_;
133              
134 0           my $d = deferred;
135              
136 0           $d->resolve( 0 >= DateTime::Duration->compare( $self->value, $other->value ) );
137              
138 0           return $d->promise;
139             }
140              
141             sub is_greater {
142 0     0 0   my ( $self, $engine, $other ) = @_;
143              
144 0           my $d = deferred;
145              
146 0           $d->resolve( 0 < DateTime::Duration->compare( $self->value, $other->value ) );
147              
148 0           return $d->promise;
149             }
150              
151             sub is_greater_or_equal {
152 0     0 0   my ( $self, $engine, $other ) = @_;
153              
154 0           my $d = deferred;
155              
156 0           $d->resolve( 0 <= DateTime::Duration->compare( $self->value, $other->value ) );
157              
158 0           return $d->promise;
159             }
160              
161             sub prepend {
162 0     0 0   my( $self, @things ) = @_;
163              
164             # if durations, we add
165             # if numeric, we add as seconds
166             # otherwise, we can't prepend
167 0 0 0 0     if(any { !$_->isa('Dallycot::Value::Numeric') && !$_->isa('Dallycot::Value::Duration') } @things) {
  0            
168 0           croak 'Only durations and numeric values may be added to durations';
169             }
170              
171 0           my @durations = map {
172 0           my $v = $_;
173 0           given(blessed $v) {
174 0           when('Dallycot::Value::Numeric') {
175 0           DateTime::Duration->new(
176             seconds => $v->value->numify
177             );
178             }
179 0           when('Dallycot::Value::Duration') {
180 0           $v -> value;
181             }
182             }
183             } @things;
184              
185 0           my $accumulator = $self->value;
186 0           $accumulator = $accumulator + $_ for @durations;
187 0           return $self -> new(object => $accumulator, class => blessed($accumulator));
188             }
189              
190             1;