Revision ae87c27e
Von Moritz Bunkus vor mehr als 9 Jahren hinzugefügt
SL/DB/Helper/AttrDuration.pm | ||
---|---|---|
3 | 3 |
use strict; |
4 | 4 |
|
5 | 5 |
use parent qw(Exporter); |
6 |
our @EXPORT = qw(attr_duration); |
|
6 |
our @EXPORT = qw(attr_duration attr_duration_minutes);
|
|
7 | 7 |
|
8 | 8 |
use Carp; |
9 | 9 |
|
... | ... | |
13 | 13 |
_make($package, $_) for @attributes; |
14 | 14 |
} |
15 | 15 |
|
16 |
sub attr_duration_minutes { |
|
17 |
my ($package, @attributes) = @_; |
|
18 |
|
|
19 |
_make_minutes($package, $_) for @attributes; |
|
20 |
} |
|
21 |
|
|
16 | 22 |
sub _make { |
17 | 23 |
my ($package, $attribute) = @_; |
18 | 24 |
|
... | ... | |
75 | 81 |
}; |
76 | 82 |
} |
77 | 83 |
|
84 |
sub _make_minutes { |
|
85 |
my ($package, $attribute) = @_; |
|
86 |
|
|
87 |
no strict 'refs'; |
|
88 |
|
|
89 |
*{ $package . '::' . $attribute . '_as_hours' } = sub { |
|
90 |
my ($self, $value) = @_; |
|
91 |
|
|
92 |
$self->$attribute($value * 60 + ($self->$attribute % 60)) if @_ > 1; |
|
93 |
return int(($self->$attribute // 0) / 60); |
|
94 |
}; |
|
95 |
|
|
96 |
*{ $package . '::' . $attribute . '_as_minutes' } = sub { |
|
97 |
my ($self, $value) = @_; |
|
98 |
|
|
99 |
$self->$attribute(int($self->$attribute) - (int($self->$attribute) % 60) + ($value // 0)) if @_ > 1; |
|
100 |
return ($self->$attribute // 0) % 60; |
|
101 |
}; |
|
102 |
|
|
103 |
*{ $package . '::' . $attribute . '_as_duration_string' } = sub { |
|
104 |
my ($self, $value) = @_; |
|
105 |
|
|
106 |
if (@_ > 1) { |
|
107 |
if (!defined($value) || ($value eq '')) { |
|
108 |
$self->$attribute(undef); |
|
109 |
} else { |
|
110 |
croak $::locale->text("Invalid duration format") if $value !~ m{^(?:(\d*):)?(\d+)$}; |
|
111 |
$self->$attribute(($1 // 0) * 60 + ($2 // 0)); |
|
112 |
} |
|
113 |
} |
|
114 |
|
|
115 |
my $as_hours = "${attribute}_as_hours"; |
|
116 |
my $as_minutes = "${attribute}_as_minutes"; |
|
117 |
return defined($self->$attribute) ? sprintf('%d:%02d', $self->$as_hours, $self->$as_minutes) : undef; |
|
118 |
}; |
|
119 |
} |
|
120 |
|
|
78 | 121 |
1; |
79 | 122 |
__END__ |
80 | 123 |
|
... | ... | |
92 | 135 |
# In a Rose model: |
93 | 136 |
use SL::DB::Helper::AttrDuration; |
94 | 137 |
__PACKAGE__->attr_duration('time_estimation'); |
138 |
__PACKAGE__->attr_duration_minutes('hours'); |
|
95 | 139 |
|
96 | 140 |
# Read access: |
97 | 141 |
print "Minutes: " . $obj->time_estimation_as_minutes . " hours: " . $obj->time_estimation_as_hours . "\n"; |
... | ... | |
104 | 148 |
|
105 | 149 |
=head1 OVERVIEW |
106 | 150 |
|
107 |
This is a helper for columns that store a duration as a numeric or |
|
108 |
floating point number representing a number of hours. So the value |
|
109 |
1.75 would stand for "1 hour, 45 minutes". |
|
151 |
This is a helper for columns that store a duration in one of two formats: |
|
110 | 152 |
|
111 |
The helper methods created are: |
|
153 |
=over 2 |
|
154 |
|
|
155 |
=item 1. as a numeric or floating point number representing a number |
|
156 |
of hours |
|
157 |
|
|
158 |
=item 2. as an integer presenting a number of minutes |
|
159 |
|
|
160 |
=back |
|
161 |
|
|
162 |
In the first case the value 1.75 would stand for "1 hour, 45 |
|
163 |
minutes". In the second case the value 105 represents the same |
|
164 |
duration. |
|
165 |
|
|
166 |
The helper methods created depend on the mode. Calling |
|
167 |
C<attr_duration> makes the following methods available: |
|
112 | 168 |
|
113 | 169 |
=over 4 |
114 | 170 |
|
... | ... | |
160 | 216 |
|
161 | 217 |
=back |
162 | 218 |
|
219 |
With C<attr_duration_minutes> the following methods are available: |
|
220 |
|
|
221 |
=over 4 |
|
222 |
|
|
223 |
=item C<attribute_as_minutes [$new_value]> |
|
224 |
|
|
225 |
Access only the minutes. Return values are in the range [0 - 59]. |
|
226 |
|
|
227 |
=item C<attribute_as_hours [$new_value]> |
|
228 |
|
|
229 |
Access only the hours. Returns an integer value. |
|
230 |
|
|
231 |
=item C<attribute_as_duration_string [$new_value]> |
|
232 |
|
|
233 |
Access the full value as a formatted string in the form C<h:mm>, |
|
234 |
e.g. C<1:30> for the value 90 minutes. Parsing such a string is |
|
235 |
supported, too. |
|
236 |
|
|
237 |
=back |
|
238 |
|
|
163 | 239 |
=head1 FUNCTIONS |
164 | 240 |
|
165 | 241 |
=over 4 |
... | ... | |
169 | 245 |
Package method. Call with the names of attributes for which the helper |
170 | 246 |
methods should be created. |
171 | 247 |
|
248 |
=item C<attr_duration_minutes @attributes> |
|
249 |
|
|
250 |
Package method. Call with the names of attributes for which the helper |
|
251 |
methods should be created. |
|
252 |
|
|
172 | 253 |
=back |
173 | 254 |
|
174 | 255 |
=head1 BUGS |
t/db_helper/attr_duration.t | ||
---|---|---|
4 | 4 |
|
5 | 5 |
__PACKAGE__->meta->setup( |
6 | 6 |
table => 'dummy', |
7 |
columns => [ dummy => { type => 'numeric', precision => 2, scale => 12 }, ] |
|
7 |
columns => [ |
|
8 |
dummy => { type => 'numeric', precision => 2, scale => 12 }, |
|
9 |
inty => { type => 'integer' }, |
|
10 |
] |
|
8 | 11 |
); |
9 | 12 |
|
10 | 13 |
use SL::DB::Helper::AttrDuration; |
11 | 14 |
|
12 | 15 |
__PACKAGE__->attr_duration('dummy'); |
16 |
__PACKAGE__->attr_duration_minutes('inty'); |
|
13 | 17 |
|
14 | 18 |
package main; |
15 | 19 |
|
16 |
use Test::More tests => 91; |
|
20 |
use Test::More; # tests => 91;
|
|
17 | 21 |
use Test::Exception; |
18 | 22 |
|
19 | 23 |
use strict; |
... | ... | |
31 | 35 |
Support::TestSetup::login(); |
32 | 36 |
my $item; |
33 | 37 |
|
38 |
### attr_duration |
|
39 |
|
|
34 | 40 |
# Wenn das Attribut undef ist: |
35 | 41 |
is(new_item->dummy, undef, 'uninitialized: raw'); |
36 | 42 |
is(new_item->dummy_as_hours, 0, 'uninitialized: as_hours'); |
... | ... | |
165 | 171 |
lives_ok { new_item()->dummy_as_man_days_unit('hour') } 'known unit hour'; |
166 | 172 |
lives_ok { new_item()->dummy_as_man_days_unit('man_day') } 'known unit man_day'; |
167 | 173 |
|
174 |
### attr_duration_minutes |
|
175 |
|
|
176 |
# Wenn das Attribut undef ist: |
|
177 |
is(new_item->inty, undef, 'uninitialized: raw'); |
|
178 |
is(new_item->inty_as_hours, 0, 'uninitialized: as_hours'); |
|
179 |
is(new_item->inty_as_minutes, 0, 'uninitialized: as_minutes'); |
|
180 |
is(new_item->inty_as_duration_string, undef, 'uninitialized: as_duration_string'); |
|
181 |
|
|
182 |
# Auslesen kleiner 60 Minuten: |
|
183 |
is(new_item(inty => 37)->inty, 37, 'initialized < 60: raw'); |
|
184 |
is(new_item(inty => 37)->inty_as_hours, 0, 'initialized < 60: as_hours'); |
|
185 |
is(new_item(inty => 37)->inty_as_minutes, 37, 'initialized < 60: as_minutes'); |
|
186 |
is(new_item(inty => 37)->inty_as_duration_string, '0:37', 'initialized < 60: as_duration_string'); |
|
187 |
|
|
188 |
# Auslesen größer 60 Minuten: |
|
189 |
is(new_item(inty => 145)->inty, 145, 'initialized > 60: raw'); |
|
190 |
is(new_item(inty => 145)->inty_as_hours, 2, 'initialized > 60: as_hours'); |
|
191 |
is(new_item(inty => 145)->inty_as_minutes, 25, 'initialized > 60: as_minutes'); |
|
192 |
is(new_item(inty => 145)->inty_as_duration_string, '2:25', 'initialized > 60: as_duration_string'); |
|
193 |
|
|
194 |
$item = new_item(inty => 145); $item->inty_as_duration_string(undef); |
|
195 |
is($item->inty, undef, 'write as_duration_string undef read raw'); |
|
196 |
is($item->inty_as_minutes, 0, 'write as_duration_string undef read as_minutes'); |
|
197 |
is($item->inty_as_hours, 0, 'write as_duration_string undef read as_hours'); |
|
198 |
is($item->inty_as_duration_string, undef, 'write as_duration_string undef read as_duration_string'); |
|
199 |
|
|
200 |
$item = new_item(inty => 145); $item->inty_as_duration_string(''); |
|
201 |
is($item->inty, undef, 'write as_duration_string "" read raw'); |
|
202 |
is($item->inty_as_minutes, 0, 'write as_duration_string "" read as_minutes'); |
|
203 |
is($item->inty_as_hours, 0, 'write as_duration_string "" read as_hours'); |
|
204 |
is($item->inty_as_duration_string, undef, 'write as_duration_string "" read as_duration_string'); |
|
205 |
|
|
206 |
$item = new_item(inty => 145); $item->inty_as_duration_string("3:21"); |
|
207 |
is($item->inty, 201, 'write as_duration_string 3:21 read raw'); |
|
208 |
is($item->inty_as_minutes, 21, 'write as_duration_string 3:21 read as_minutes'); |
|
209 |
is($item->inty_as_hours, 3, 'write as_duration_string 3:21 read as_hours'); |
|
210 |
is($item->inty_as_duration_string, "3:21", 'write as_duration_string 3:21 read as_duration_string'); |
|
211 |
|
|
212 |
$item = new_item(inty => 145); $item->inty_as_duration_string("03:1"); |
|
213 |
is($item->inty, 181, 'write as_duration_string 03:1 read raw'); |
|
214 |
is($item->inty_as_minutes, 1, 'write as_duration_string 03:1 read as_minutes'); |
|
215 |
is($item->inty_as_hours, 3, 'write as_duration_string 03:1 read as_hours'); |
|
216 |
is($item->inty_as_duration_string, "3:01", 'write as_duration_string 03:1 read as_duration_string'); |
|
217 |
|
|
218 |
# Parametervalidierung |
|
219 |
throws_ok { new_item()->inty_as_duration_string('invalid') } qr/invalid.*format/i, 'invalid duration format'; |
|
220 |
|
|
168 | 221 |
done_testing(); |
Auch abrufbar als: Unified diff
AttrDuration: Implementation für Spalten, die Dauer in Minuten speichern