Skip to content

Commit

Permalink
Switch from Params::Validate to Params::CheckCompiler & Specio
Browse files Browse the repository at this point in the history
  • Loading branch information
autarch committed Jun 18, 2016
1 parent b9bb8cf commit 3308e9e
Show file tree
Hide file tree
Showing 9 changed files with 485 additions and 261 deletions.
470 changes: 264 additions & 206 deletions lib/DateTime.pm

Large diffs are not rendered by default.

90 changes: 53 additions & 37 deletions lib/DateTime/Duration.pm
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ our $VERSION = '1.29';
use Carp ();
use DateTime;
use DateTime::Helpers;
use Params::Validate qw( validate SCALAR );
use DateTime::Types;
use Params::CheckCompiler qw( compile );

use overload (
fallback => 1,
Expand All @@ -23,54 +24,69 @@ use constant MAX_NANOSECONDS => 1_000_000_000; # 1E9 = almost 32 bits

my @all_units = qw( months days minutes seconds nanoseconds );

# XXX - need to reject non-integers but accept infinity, NaN, &
# 1.56e+18
sub new {
my $class = shift;
my %p = validate(
@_, {
years => { type => SCALAR, default => 0 },
months => { type => SCALAR, default => 0 },
weeks => { type => SCALAR, default => 0 },
days => { type => SCALAR, default => 0 },
hours => { type => SCALAR, default => 0 },
minutes => { type => SCALAR, default => 0 },
seconds => { type => SCALAR, default => 0 },
nanoseconds => { type => SCALAR, default => 0 },
{
my %units = map {
$_ => {

# XXX - what we really want is to accept an integer, Inf, -Inf,
# and NaN, but I can't figure out how to accept NaN since it never
# compares to anything.
type => t('Defined'),
default => 0,
}
} qw(
years
months
weeks
days
hours
minutes
seconds
nanoseconds
);

my $check = compile(
params => {
%units,
end_of_month => {
type => SCALAR, default => undef,
regex => qr/^(?:wrap|limit|preserve)$/
type => t('EndOfMonthMode'),
optional => 1,
},
}
},
);

my $self = bless {}, $class;
sub new {
my $class = shift;
my %p = $check->(@_);

$self->{months} = ( $p{years} * 12 ) + $p{months};
my $self = bless {}, $class;

$self->{days} = ( $p{weeks} * 7 ) + $p{days};
$self->{months} = ( $p{years} * 12 ) + $p{months};

$self->{minutes} = ( $p{hours} * 60 ) + $p{minutes};
$self->{days} = ( $p{weeks} * 7 ) + $p{days};

$self->{seconds} = $p{seconds};
$self->{minutes} = ( $p{hours} * 60 ) + $p{minutes};

if ( $p{nanoseconds} ) {
$self->{nanoseconds} = $p{nanoseconds};
$self->_normalize_nanoseconds;
}
else {
$self->{seconds} = $p{seconds};

# shortcut - if they don't need nanoseconds
$self->{nanoseconds} = 0;
}
if ( $p{nanoseconds} ) {
$self->{nanoseconds} = $p{nanoseconds};
$self->_normalize_nanoseconds;
}
else {

$self->{end_of_month} = (
defined $p{end_of_month} ? $p{end_of_month}
: $self->{months} < 0 ? 'preserve'
: 'wrap'
);
# shortcut - if they don't need nanoseconds
$self->{nanoseconds} = 0;
}

return $self;
$self->{end_of_month} = (
defined $p{end_of_month} ? $p{end_of_month}
: $self->{months} < 0 ? 'preserve'
: 'wrap'
);

return $self;
}
}

# make the signs of seconds, nanos the same; 0 < abs(nanos) < MAX_NANOS
Expand Down
150 changes: 150 additions & 0 deletions lib/DateTime/Types.pm
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
package DateTime::Types;

use strict;
use warnings;

use parent 'Specio::Exporter';

use Specio 0.18;
use Specio::Declare;
use Specio::Library::Builtins -reexport;
use Specio::Library::Numeric -reexport;
use Specio::Library::String;

any_can_type(
'ConvertibleObject',
methods => ['utc_rd_values'],
);

declare(
'DayOfMonth',
parent => t('Int'),
inline => sub {
$_[0]->parent->inline_check( $_[1] )
. " && $_[1] >= 1 && $_[1] <= 31";
},
);

declare(
'DayOfYear',
parent => t('Int'),
inline => sub {
$_[0]->parent->inline_check( $_[1] )
. " && $_[1] >= 1 && $_[1] <= 366";
},
);

object_isa_type(
'Duration',
class => 'DateTime::Duration',
);

enum(
'EndOfMonthMode',
values => [qw( wrap limit preserve )],
);

any_can_type(
'Formatter',
methods => ['format_datetime'],
);

my $locale_object = declare(
'LocaleObject',
parent => t('Object'),
inline => sub {
<<"EOF";
(
$_[1]->isa('DateTime::Locale::FromData')
|| $_[1]->isa('DateTime::Locale::Base')
)
EOF
},
);

union(
'Locale',
of => [ t('NonEmptySimpleStr'), $locale_object ],
);

my $time_zone_object = object_can_type(
'TZObject',
methods => [
qw(
is_floating
is_utc
name
offset_for_datetime
short_name_for_datetime
)
],
);

declare(
'TimeZone',
of => [ t('NonEmptySimpleStr'), $time_zone_object ],
);

declare(
'Hour',
parent => t('PositiveOrZeroInt'),
inline => sub {
$_[0]->parent->inline_check( $_[1] )
. " && $_[1] >= 0 && $_[1] <= 23";
},
);

declare(
'Minute',
parent => t('PositiveOrZeroInt'),
inline => sub {
$_[0]->parent->inline_check( $_[1] )
. " && $_[1] >= 0 && $_[1] <= 59";
},
);

declare(
'Month',
parent => t('PositiveInt'),
inline => sub {
$_[0]->parent->inline_check( $_[1] )
. " && $_[1] >= 1 && $_[1] <= 12";
},
);

declare(
'Nanosecond',
parent => t('PositiveOrZeroInt'),
);

declare(
'Second',
parent => t('PositiveOrZeroInt'),
inline => sub {
$_[0]->parent->inline_check( $_[1] )
. " && $_[1] >= 0 && $_[1] <= 61";

This comment has been minimized.

Copy link
@atoomic

atoomic Apr 22, 2019

I guess there is a good reason why a second can be 60 or 61 ?

This comment has been minimized.

Copy link
@autarch

This comment has been minimized.

Copy link
@arodland

arodland via email Apr 22, 2019

},
);

enum(
'TruncationLevel',
values => [
qw(
year
month
day hour
minute
second
nanosecond
week
local_week
)
],
);

declare(
'Year',
parent => t('Int'),
);

1;
6 changes: 3 additions & 3 deletions t/04epoch.t
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use strict;
use warnings;

use Test::More;
use Test::Fatal;

use DateTime;

Expand Down Expand Up @@ -217,10 +218,9 @@ use DateTime;
);

for my $test (@tests) {
eval { DateTime->from_epoch( epoch => $test ); };

like(
$@, qr/did not pass regex check/,
exception { DateTime->from_epoch( epoch => $test ) },
qr/Validation failed for type named Num/,
qq{'$test' is not a valid epoch value}
);
}
Expand Down
2 changes: 1 addition & 1 deletion t/16truncate.t
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ my %vals = (
for my $bad (qw( seconds minutes year_foo month_bar )) {
like(
exception { $dt->truncate( to => $bad ) },
qr/\QThe 'to' parameter/,
qr/Validation failed for type named TruncationLevel/,
"bad truncate parameter ($bad) throws an error"
);
}
Expand Down
8 changes: 4 additions & 4 deletions t/21bad-params.t
Original file line number Diff line number Diff line change
Expand Up @@ -19,27 +19,27 @@ foreach my $p (
) {
eval { DateTime->new(%$p) };
like(
$@, qr/did not pass/,
$@, qr/Validation failed/,
"Parameters outside valid range should fail in call to new()"
);

eval { DateTime->new( year => 2000 )->set(%$p) };
like(
$@, qr/did not pass/,
$@, qr/Validation failed/,
"Parameters outside valid range should fail in call to set()"
);
}

{
eval { DateTime->last_day_of_month( year => 2000, month => 13 ) };
like(
$@, qr/did not pass/,
$@, qr/Validation failed/,
"Parameters outside valid range should fail in call to last_day_of_month()"
);

eval { DateTime->last_day_of_month( year => 2000, month => 0 ) };
like(
$@, qr/did not pass/,
$@, qr/Validation failed/,
"Parameters outside valid range should fail in call to last_day_of_month()"
);
}
Expand Down
2 changes: 1 addition & 1 deletion t/23storable.t
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ unless ( eval { require Storable; 1 } ) {
hour => 1,
nanosecond => 1,
time_zone => 'America/Chicago',
language => 'German'
locale => 'de'
),
DateTime::Infinite::Past->new,
DateTime::Infinite::Future->new,
Expand Down
Loading

0 comments on commit 3308e9e

Please sign in to comment.