Projekt

Allgemein

Profil

« Zurück | Weiter » 

Revision 4180aaea

Von Moritz Bunkus vor fast 12 Jahren hinzugefügt

  • ID 4180aaea33e9ff3bb35f3fa6cf91651a6225f7ad
  • Vorgänger e3aa3f5b
  • Nachfolger ee62bdab

AttrDuration-Helfer

Unterschiede anzeigen:

SL/DB/Helper/AttrDuration.pm
package SL::DB::Helper::AttrDuration;
use strict;
use parent qw(Exporter);
our @EXPORT = qw(attr_duration);
use Carp;
sub attr_duration {
my ($package, @attributes) = @_;
_make($package, $_) for @attributes;
}
sub _make {
my ($package, $attribute) = @_;
no strict 'refs';
*{ $package . '::' . $attribute . '_as_hours' } = sub {
my ($self, $value) = @_;
$self->$attribute(int($value) + ($self->$attribute - int($self->$attribute))) if @_ > 1;
return int($self->$attribute // 0);
};
*{ $package . '::' . $attribute . '_as_minutes' } = sub {
my ($self, $value) = @_;
$self->$attribute(int($self->$attribute) * 1.0 + ($value // 0) / 60.0) if @_ > 1;
return int(($self->$attribute // 0) * 60.0 + 0.5) % 60;
};
*{ $package . '::' . $attribute . '_as_duration_string' } = sub {
my ($self, $value) = @_;
$self->$attribute(defined($value) ? $::form->parse_amount(\%::myconfig, $value) * 1 : undef) if @_ > 1;
return defined($self->$attribute) ? $::form->format_amount(\%::myconfig, $self->$attribute // 0, 2) : undef;
};
*{ $package . '::' . $attribute . '_as_man_days' } = sub {
my ($self, $value) = @_;
if (@_ > 1) {
return undef if !defined $value;
$self->$attribute($value);
}
$value = $self->$attribute // 0;
return $value >= 8.0 ? $value / 8.0 : $value;
};
*{ $package . '::' . $attribute . '_as_man_days_unit' } = sub {
my ($self, $unit) = @_;
if (@_ > 1) {
return undef if !defined $unit;
croak "Unknown unit '${unit}'" if $unit !~ m/^(?:h|hour|man_day)$/;
$self->$attribute(($self->$attribute // 0) * 8.0) if $unit eq 'man_day';
}
return ($self->$attribute // 0) >= 8.0 ? 'man_day' : 'h'
};
*{ $package . '::' . $attribute . '_as_man_days_string' } = sub {
my ($self, $value) = @_;
my $method = "${attribute}_as_man_days";
if (@_ > 1) {
return undef if !defined $value;
$self->$method($::form->parse_amount(\%::myconfig, $value));
}
return $::form->format_amount(\%::myconfig, $self->$method // 0, 2);
};
}
1;
__END__
=pod
=encoding utf8
=head1 NAME
SL::DB::Helper::AttrDuration - Attribute helper for duration stored in
numeric columns
=head1 SYNOPSIS
# In a Rose model:
use SL::DB::Helper::AttrDuration;
__PACKAGE__->attr_duration('time_estimation');
# Read access:
print "Minutes: " . $obj->time_estimation_as_minutes . " hours: " . $obj->time_estimation_as_hours . "\n";
# Use formatted strings in input fields in templates:
<form method="post">
...
[% L.input_tag('time_estimation_as_duration_string', SELF.obj.time_estimation_as_duration_string) %]
</form>
=head1 OVERVIEW
This is a helper for columns that store a duration as a numeric or
floating point number representing a number of hours. So the value
1.75 would stand for "1 hour, 45 minutes".
The helper methods created are:
=over 4
=item C<attribute_as_minutes [$new_value]>
Access only the minutes. Return values are in the range [0 - 59].
=item C<attribute_as_hours [$new_value]>
Access only the hours. Returns an integer value.
=item C<attribute_as_duration_string [$new_value]>
Access the full value as a formatted string according to the user's
locale settings.
=item C<attribute_as_man_days [$new_value]>
Access the attribute as a number of man days which are assumed to be 8
hours long. If the underlying attribute is less than 8 then the value
itself will be returned. Otherwise the value divided by 8 is returned.
If used as a setter then the underlying attribute is simply set to
C<$new_value>. Intentional use is to set the man days first and the
unit later, e.g.
$obj->attribute_as_man_days($::form->{attribute_as_man_days});
$obj->attribute_as_man_days_unit($::form->{attribute_as_man_days_unit});
Note that L<SL::DB::Object/assign_attributes> is aware of this and
handles this case correctly.
=item C<attribute_as_man_days_unit [$new_unit]>
Returns the unit that the number returned by L</attribute_as_man_days>
represents. This can be either C<h> if the underlying attribute is
less than 8 and C<man_day> otherwise.
If used as a setter then the underlying attribute is multiplied by 8
if C<$new_unit> equals C<man_day>. Otherwise the underlying attribute
is not modified. Intentional use is to set the man days first and the
unit later, e.g.
$obj->attribute_as_man_days($::form->{attribute_as_man_days});
$obj->attribute_as_man_days_unit($::form->{attribute_as_man_days_unit});
Note that L<SL::DB::Object/assign_attributes> is aware of this and
handles this case correctly.
=back
=head1 FUNCTIONS
=over 4
=item C<attr_duration @attributes>
Package method. Call with the names of attributes for which the helper
methods should be created.
=back
=head1 BUGS
Nothing here yet.
=head1 AUTHOR
Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt>
=cut
SL/DB/Object.pm
my %types = map { $_->name => $_->type } ref($self)->meta->columns;
# Special case for *_as_man_days/*_as_man_days_unit: the _unit
# variation must always be called after the non-unit method.
my @man_days_attributes = grep { m/_as_man_days$/ } keys %attributes;
foreach my $attribute (@man_days_attributes) {
my $value = delete $attributes{$attribute};
$self->$attribute(defined($value) && ($value eq '') ? undef : $value);
}
while (my ($attribute, $value) = each %attributes) {
my $type = lc($types{$attribute} || 'text');
$value = $type eq 'boolean' ? ($value ? 't' : 'f')
t/db_helper/attr_duration.t
package AttrDurationTestDummy;
use base qw(SL::DB::Object);
__PACKAGE__->meta->setup(
table => 'dummy',
columns => [ dummy => { type => 'numeric', precision => 2, scale => 12 }, ]
);
use SL::DB::Helper::AttrDuration;
__PACKAGE__->attr_duration('dummy');
package main;
use Test::More tests => 83;
use Test::Exception;
use strict;
use lib 't';
use utf8;
use Data::Dumper;
use Support::TestSetup;
sub new_item {
return AttrDurationTestDummy->new(@_);
}
Support::TestSetup::login();
my $item;
# Wenn das Attribut undef ist:
is(new_item->dummy, undef, 'uninitialized: raw');
is(new_item->dummy_as_hours, 0, 'uninitialized: as_hours');
is(new_item->dummy_as_minutes, 0, 'uninitialized: as_minutes');
is(new_item->dummy_as_duration_string, undef, 'uninitialized: as_duration_string');
is(new_item->dummy_as_man_days, 0, 'uninitialized: as_man_days');
is(new_item->dummy_as_man_days_unit, 'h', 'uninitialized: as_man_days_unit');
is(new_item->dummy_as_man_days_string, '0,00', 'uninitialized: as_man_days_string');
# Auslesen kleiner 8 Stunden:
is(new_item(dummy => 2.75)->dummy, 2.75, 'initialized < 8: raw');
is(new_item(dummy => 2.75)->dummy_as_hours, 2, 'initialized < 8: as_hours');
is(new_item(dummy => 2.75)->dummy_as_minutes, 45, 'initialized < 8: as_minutes');
is(new_item(dummy => 2.75)->dummy_as_duration_string, '2,75', 'initialized < 8: as_duration_string');
is(new_item(dummy => 2.75)->dummy_as_man_days, 2.75, 'initialized < 8: as_man_days');
is(new_item(dummy => 2.75)->dummy_as_man_days_unit, 'h', 'initialized < 8: as_man_days_unit');
is(new_item(dummy => 2.75)->dummy_as_man_days_string, '2,75', 'initialized < 8: as_man_days_string');
# Auslesen größer 8 Stunden:
is(new_item(dummy => 12.5)->dummy, 12.5, 'initialized > 8: raw');
is(new_item(dummy => 12.5)->dummy_as_hours, 12, 'initialized > 8: as_hours');
is(new_item(dummy => 12.5)->dummy_as_minutes, 30, 'initialized > 8: as_minutes');
is(new_item(dummy => 12.5)->dummy_as_duration_string, '12,50', 'initialized > 8: as_duration_string');
is(new_item(dummy => 12.5)->dummy_as_man_days, 1.5625, 'initialized > 8: as_man_days');
is(new_item(dummy => 12.5)->dummy_as_man_days_unit, 'man_day', 'initialized > 8: as_man_days_unit');
is(new_item(dummy => 12.5)->dummy_as_man_days_string, '1,56', 'initialized > 8: as_man_days_string');
$item = new_item(dummy => 2.25); $item->dummy_as_duration_string(undef);
is($item->dummy, undef, 'write as_duration_string undef read raw');
is($item->dummy_as_minutes, 0, 'write as_duration_string undef read as_minutes');
is($item->dummy_as_hours, 0, 'write as_duration_string undef read as_hours');
is($item->dummy_as_duration_string, undef, 'write as_duration_string undef read as_duration_string');
$item = new_item(dummy => 2.25); $item->dummy_as_duration_string("4,80");
is($item->dummy, 4.8, 'write as_duration_string 4,80 read raw');
is($item->dummy_as_minutes, 48, 'write as_duration_string 4,80 read as_minutes');
is($item->dummy_as_hours, 4, 'write as_duration_string 4,80 read as_hours');
is($item->dummy_as_duration_string, "4,80", 'write as_duration_string 4,80 read as_duration_string');
$item = new_item(dummy => 2.25); $item->dummy_as_minutes(12);
is($item->dummy, 2.2, 'write as_minutes 12 read raw');
is($item->dummy_as_minutes, 12, 'write as_minutes 12 read as_minutes');
is($item->dummy_as_hours, 2, 'write as_minutes 12 read as_hours');
is($item->dummy_as_duration_string, "2,20", 'write as_minutes 12 read as_duration_string');
$item = new_item(dummy => 2.25); $item->dummy_as_hours(5);
is($item->dummy, 5.25, 'write as_hours 5 read raw');
is($item->dummy_as_minutes, 15, 'write as_hours 5 read as_minutes');
is($item->dummy_as_hours, 5, 'write as_hours 5 read as_hours');
is($item->dummy_as_duration_string, "5,25", 'write as_hours 5 read as_duration_string');
$item = new_item(dummy => undef);
is($item->dummy, undef, 'write raw undef read raw');
is($item->dummy_as_man_days, 0, 'write raw undef read as_man_days');
is($item->dummy_as_man_days_unit, 'h', 'write raw undef read as_man_days_unit');
is($item->dummy_as_man_days_string, '0,00', 'write raw undef read as_man_days_string');
$item = new_item(dummy => 4);
is($item->dummy, 4, 'write raw 4 read raw');
is($item->dummy_as_man_days, 4, 'write raw 4 read as_man_days');
is($item->dummy_as_man_days_unit, 'h', 'write raw 4 read as_man_days_unit');
is($item->dummy_as_man_days_string, '4,00', 'write raw 4 read as_man_days_string');
$item = new_item(dummy => 18);
is($item->dummy, 18, 'write raw 18 read raw');
is($item->dummy_as_man_days, 2.25, 'write raw 18 read as_man_days');
is($item->dummy_as_man_days_unit, 'man_day', 'write raw 18 read as_man_days_unit');
is($item->dummy_as_man_days_string, '2,25', 'write raw 18 read as_man_days_string');
$item = new_item(dummy => 4);
is($item->dummy, 4, 'should not change anything when writing undef: write raw 4 read raw');
is($item->dummy_as_man_days(undef), undef, 'should not change anything when writing undef: write as_man_days undef return undef');
is($item->dummy, 4, 'should not change anything when writing undef: read raw 2');
is($item->dummy_as_man_days_unit(undef), undef, 'should not change anything when writing undef: write as_man_days_unit undef return undef');
is($item->dummy, 4, 'should not change anything when writing undef: read raw 3');
is($item->dummy_as_man_days_string(undef), undef, 'should not change anything when writing undef: write as_man_days_string undef return undef');
is($item->dummy, 4, 'should not change anything when writing undef: read raw 4');
$item = new_item;
is($item->dummy(2), 2, 'parse less than a man day: write raw 2 read raw');
is($item->dummy_as_man_days(0.75), 0.75, 'parse less than a man day: write as_man_days 0.75 read as_man_days');
is($item->dummy_as_man_days_string('0,5'), '0,50', 'parse less than a man day: write as_man_days_string 0,5 read read as_man_days_string');
$item = new_item;
is($item->dummy(12), 12, 'parse more than a man day: write raw 12 read raw');
is($item->dummy_as_man_days(13.25), 1.65625, 'parse more than a man day: write as_man_days 13.25 read as_man_days');
is($item->dummy_as_man_days_string('13,5'), '1,69', 'parse more than a man day: write as_man_days_string 13,5 read read as_man_days_string');
$item = new_item;
is($item->dummy(3.25), 3.25, 'parse less than a man day with unit h: write raw 3.25 read raw');
is($item->dummy_as_man_days_unit('h'), 'h', 'parse less than a man day with unit h: write as_man_days_unit h read as_man_days_unit');
is($item->dummy, 3.25, 'parse less than a man day with unit h: read raw');
$item = new_item;
is($item->dummy(3.25), 3.25, 'parse less than a man day with unit hour: write raw 3.25 read raw');
is($item->dummy_as_man_days_unit('hour'), 'h', 'parse less than a man day with unit hour: write as_man_days_unit hour read as_man_days_unit');
is($item->dummy, 3.25, 'parse less than a man day with unit hour: read raw');
$item = new_item;
is($item->dummy(3.25), 3.25, 'parse more than a man day with unit man_day: write raw 3.25 read raw');
is($item->dummy_as_man_days_unit('man_day'), 'man_day', 'parse more than a man day with unit man_day: write as_man_days_unit man_day read as_man_days_unit');
is($item->dummy, 26, 'parse more than a man day with unit man_day: read raw');
is(new_item->assign_attributes(dummy_as_man_days => 3, dummy_as_man_days_unit => 'h')->dummy, 3, 'assign_attributes hash 3h');
is(new_item->assign_attributes(dummy_as_man_days_unit => 'h', dummy_as_man_days => 3 )->dummy, 3, 'assign_attributes hash h3');
is(new_item->assign_attributes(dummy_as_man_days => 3, dummy_as_man_days_unit => 'man_day')->dummy, 24, 'assign_attributes hash 3man_day');
is(new_item->assign_attributes(dummy_as_man_days_unit => 'man_day', dummy_as_man_days => 3 )->dummy, 24, 'assign_attributes hash man_day3');
is(new_item->assign_attributes('dummy_as_man_days', 3, 'dummy_as_man_days_unit', 'h')->dummy, 3, 'assign_attributes array 3h');
is(new_item->assign_attributes('dummy_as_man_days_unit', 'h', 'dummy_as_man_days', 3 )->dummy, 3, 'assign_attributes array h3');
is(new_item->assign_attributes('dummy_as_man_days', 3, 'dummy_as_man_days_unit', 'man_day')->dummy, 24, 'assign_attributes array 3man_day');
is(new_item->assign_attributes('dummy_as_man_days_unit', 'man_day', 'dummy_as_man_days', 3 )->dummy, 24, 'assign_attributes array man_day3');
# Parametervalidierung
throws_ok { new_item()->dummy_as_man_days_unit('invalid') } qr/unknown.*unit/i, 'unknown unit';
lives_ok { new_item()->dummy_as_man_days_unit('h') } 'known unit h';
lives_ok { new_item()->dummy_as_man_days_unit('hour') } 'known unit hour';
lives_ok { new_item()->dummy_as_man_days_unit('man_day') } 'known unit man_day';
done_testing();

Auch abrufbar als: Unified diff