diff --git a/lib/Specio/Constraint/Role/Interface.pm b/lib/Specio/Constraint/Role/Interface.pm index 6a92e46..cfe40ca 100644 --- a/lib/Specio/Constraint/Role/Interface.pm +++ b/lib/Specio/Constraint/Role/Interface.pm @@ -133,6 +133,7 @@ sub has_coercions { scalar keys %{ $_[0]->{_coercions} } } sub validate_or_die { my $self = shift; my $value = shift; + my $context = shift; return if $self->value_is_valid($value); @@ -140,6 +141,7 @@ sub validate_or_die { message => $self->_message_generator->($value), type => $self, value => $value, + ($context ? (context => $context) : ()), ); } @@ -381,13 +383,17 @@ sub inline_coercion_and_check { sub inline_assert { my $self = shift; + my $context = shift; my $type_var_name = '$_Specio_Constraint_Interface_type' . $counter; my $message_generator_var_name = '$_Specio_Constraint_Interface_message_generator' . $counter; + my $context_var_name + = '$_Specio_Constraint_Interface_context' . $counter; my %env = ( $type_var_name => \$self, $message_generator_var_name => \( $self->_message_generator ), + ($context ? ($context_var_name => \$context) : ()), %{ $self->inline_environment }, ); @@ -396,7 +402,8 @@ sub inline_coercion_and_check { $source .= $self->_inline_throw_exception( $_[0], $message_generator_var_name, - $type_var_name + $type_var_name, + ($context ? $context_var_name : ()), ); $source .= ';'; @@ -445,12 +452,15 @@ sub _inline_throw_exception { my $value_var = shift; my $message_generator_var_name = shift; my $type_var_name = shift; + my $context_var_name = shift; #<<< return 'Specio::Exception->throw( ' . ' message => ' . $message_generator_var_name . '->(' . $value_var . '),' . ' type => ' . $type_var_name . ',' - . ' value => ' . $value_var . ' )'; + . ' value => ' . $value_var . ',' + . ($context_var_name ? ' context => ' . $context_var_name . ',' : '') + . ')'; #>>> } diff --git a/lib/Specio/Exception.pm b/lib/Specio/Exception.pm index d2ab0b1..77700bf 100644 --- a/lib/Specio/Exception.pm +++ b/lib/Specio/Exception.pm @@ -29,6 +29,9 @@ use Specio::OO; stack_trace => { init_arg => undef, }, + context => { + isa => 'HashRef', + }, }; ## no critic (Subroutines::ProhibitUnusedPrivateSubroutines) @@ -50,6 +53,12 @@ sub as_string { my $self = shift; my $str = $self->message; + if ($self->context and my %context = %{$self->context}) { + $str + .= ' (' + . join(', ', map { "$_: $context{$_}" } sort keys %context) + . ')'; + } $str .= "\n\n" . $self->stack_trace->as_string; return $str; diff --git a/t/exception.t b/t/exception.t index c422a66..0565497 100644 --- a/t/exception.t +++ b/t/exception.t @@ -31,6 +31,16 @@ use Specio::Library::Builtins; qr/Validation failed for type named Str .+ with value \[\s*\]/, 'exception contains expected error' ); + + $e = exception { + $str->validate_or_die( [], { attribute => 'foo' } ); + }; + + like( + $e->as_string, + qr/Validation failed for type named Str .+ with value \[\s*\] \(attribute: foo\)/, + 'exception contains expected error' + ); } done_testing();