Skip to content

Instantly share code, notes, and snippets.

@avar
Created May 2, 2012 15:46
Show Gist options
  • Save avar/2577642 to your computer and use it in GitHub Desktop.
Save avar/2577642 to your computer and use it in GitHub Desktop.
MooseX::Attribute::TypeConstraint::CustomizeFatal
package MooseX::Attribute::TypeConstraint::CustomizeFatal;
use Moose::Role;
use MooseX::Types::Moose ':all';
use Carp qw(confess);
use MooseX::Types -declare => [ qw(
TypeConstraintCustomizeFatalAction
) ];
use Data::Dumper;
use Try::Tiny;
enum TypeConstraintCustomizeFatalAction, [ qw(
error
warning
default
default_no_warning
) ];
has on_typeconstraint_failure => (
is => 'ro',
isa => TypeConstraintCustomizeFatalAction,
default => 'error',
documentation => "What should we do when a typeconstraint fails? Possible values: " . join(", ", @{ TypeConstraintCustomizeFatalAction->values }),
);
around _coerce_and_verify => sub {
my $orig = shift;
my $self = shift;
my $val = shift;
my @args = @_;
try {
$self->$orig($val => @args);
} catch {
my $error = $_;
if ($error =~ /does not pass the type constraint/) {
my $action = $self->on_typeconstraint_failure;
if ($action eq 'error') {
# Just die like Moose does by default
die $error;
} elsif ($action eq 'warning') {
# Warn but keep the current value.
warn $error;
return $val;
} elsif ($action eq 'default' or
$action eq 'default_no_warning') {
warn $error unless $action eq 'default_no_warning';
if ($self->has_default) {
return $self->default;
} else {
confess(
"Attribute ("
. $self->name
. ") does not have a default value to fall back to"
);
}
} else {
die "PANIC: Unknown action <$action>";
}
return $val;
} else {
die $error;
}
};
};
package Moose::Meta::Attribute::Custom::Trait::TypeConstraint::CustomizeFatal;
sub register_implementation { 'MooseX::Attribute::TypeConstraint::CustomizeFatal' }
1;
__END__
=encoding utf8
=head1 NAME
MooseX::Attribute::TypeConstraint::CustomizeFatal - Control how failed type constraint checks are handled
=head1 SYNOPSIS
package Class;
use Moose;
use MooseX::Types::Moose ':all';
use MooseX::Attribute::TypeConstraint::CustomizeFatal;
my %attributes = (
a => "warning",
b => "default",
c => "default_no_warning",
d => "error",
);
while (my ($attribute, $on_typeconstraint_failure) = each %attributes) {
has $attribute => (
is => 'ro',
isa => Int,
default => 12345,
traits => ['TypeConstraint::CustomizeFatal'],
on_typeconstraint_failure => $on_typeconstraint_failure,
);
}
package main;
use Data::Dumper;
Class->new(
a => "foo", # will be "foo" but will warn
b => "foo", # will be 12345 but will warn
c => "foo", # will be 12345 but won't warn
# d => "foo", # will die, just like Moose does by default
);
=head1 DESCRIPTION
By default Moose will just die if you give an attribute a
typeconstraint that fails. This trait allows you to customize that
behavior to make failures either issue an error like Moose does by
default (this is the default), a warning and keep the invalid value,
or falling back to the default value either silently or with a
warning.
=head1 ACKNOWLEDGMENT
This module was originally developed at and for Booking.com. With
approval from Booking.com, this module was generalized and put on
CPAN, for which the authors would like to express their gratitude.
=head1 AUTHOR
Ævar Arnfjörð Bjarmason <[email protected]>
=cut
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment