Skip to content

Commit

Permalink
Update the docs for exceptions (including the manual)
Browse files Browse the repository at this point in the history
  • Loading branch information
autarch committed Oct 21, 2014
1 parent 610fcf3 commit 90893cd
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 79 deletions.
4 changes: 2 additions & 2 deletions lib/Moose/Exception.pm
Expand Up @@ -126,8 +126,8 @@ This method returns the stack trace for the given exception.
This method returns a stringified form of the exception, including a stack
trace. By default, this method skips Moose-internal stack frames until it sees
a caller outside of the Moose core. If the C<MOOSE_FULL_EXCEPTION> env var is
true, these frames are included.
a caller outside of the Moose core. If the C<MOOSE_FULL_EXCEPTION> environment
variable is true, these frames are included.
=head1 SEE ALSO
Expand Down
162 changes: 85 additions & 77 deletions lib/Moose/Manual/Exceptions.pod
Expand Up @@ -5,24 +5,34 @@ __END__

=pod

=head1 Exceptions in Moose
=head1 EXCEPTIONS IN MOOSE

Moose will throw an instance of C<Moose::Exception> when it encounters an error condition.
There are many specific subclasses of L<Moose::Exception>, each designed specifically for
its particular error condition. These subclasses have attributes that contain
relevant information, such as a stack trace, related metaclass objects, etc.
Moose will throw an exception for all error conditions. This applies both to
code in the Moose core I<as well> as to all code generatedwhen a class is made
immutable. All exceptions are subclasses of the C<Moose::Exception> class.

=head1 Handling Moose Exceptions
Each type of error has its own unique subclass, and many subclasses have
additional attributes to provide more information about the error's context,
such as what classes or roles were involved.

Because Moose's exceptions use the standard C<die> mechanism, you are free to catch and handle
errors however you like. You could use Perl's builtin C<eval> to catch Moose exceptions.
However due to the subtle problems C<eval> can introduce into
your programs, the Moose team strongly recommends using L<Try::Tiny> instead. Please refer
to L<Try::Tiny>'s documentation for a discussion of how C<eval> is dangerous.
=head2 Exception Stringification

The following example demonstrates how to catch and inspect a L<Moose::Exception>. For the
sake of simplicity, we will cause a very simple error. The C<extends> keywords expects a list
of superclass names. If we pass no superclass names, Moose will throw an instance of
By default, Moose exceptions remove Moose internals from the stack trace. If
you set the C<MOOSE_FULL_EXCEPTION> environment variable to a true value, then
the Moose internals will be included in the trace.

=head2 HANDLING MOOSE EXCEPTIONS

Because Moose's exceptions use the standard C<die> mechanism, you are free to
catch and handle errors however you like. You could use an C<eval> block to
catch Moose exceptions. However, the Moose team strongly recommends using
L<Try::Tiny> instead. Please refer to L<Try::Tiny>'s documentation for a
discussion of how C<eval> is dangerous.

The following example demonstrates how to catch and inspect a
L<Moose::Exception>. For the sake of simplicity, we will cause a very simple
error. The C<extends> keywords expects a list of superclass names. If we pass
no superclass names, Moose will throw an instance of
L<Moose::Exception::ExtendsMissingArgs>.

=head2 Catching with Try::Tiny
Expand All @@ -34,29 +44,35 @@ L<Moose::Exception::ExtendsMissingArgs>.
try {
package Example::Exception;
use Moose;
extends; # <-- error!
} catch {
# $_ contains the instance of the exception thrown by the above try block
# $_ may get clobbered, so we should copy its value to another variable
my $exception = $_;

# exception objects are not ubiquitous in Perl, so we must check whether $exception is blessed
# we also need to ensure that $exception is actually the kind of exception we were expecting
if ( blessed $exception && $exception->isa("Moose::Exception::ExtendsMissingArgs") ) {
# fetch attributes from the $exception object and display a friendly error to the user
my $class_name = $exception->class_name;
warn "You forgot to specify the superclass of $class_name, dummy!";
} else {
# you've got some other kind of exception, so just print it
# note: all Moose::Exception objects will stringify to a useful error message
warn "$exception\n";
extends; # <-- error!
}
catch {
# $_ contains the instance of the exception thrown by the above try
# block, but $_ may get clobbered, so we should copy its value to
# another variable.
my $e = $_;

# Exception objects are not ubiquitous in Perl, so we must check
# whether $e is blessed. We also need to ensure that $e is actually
# the kind of exception we were expecting.
if ( blessed $e
&& $e->isa('Moose::Exception::ExtendsMissingArgs') ) {

my $class_name = $e->class_name;
warn "You forgot to specify a superclass for $class_name, silly!";
}

# It's either another type of an object or not an object at all.
else {
warn "$e\n";
}
}

=head2 Example of catching ValidationFailedForTypeConstraint

use warnings;
use strict;

use Try::Tiny;

{
Expand All @@ -65,53 +81,57 @@ L<Moose::Exception::ExtendsMissingArgs>.
use Moose::Util::TypeConstraints;

subtype 'NameStr',
as 'Str',
where { $_ =~ /^[a-zA-Z]+$/; };
as 'Str',
where { $_ =~ /^[a-zA-Z]+$/; };

has 'age' => (
has age => (
is => 'ro',
isa => 'Int',
required => 1
);

has 'name' => (
has name => (
is => 'ro',
isa => 'NameStr',
required => 1
);
}

my $person;
while( !$person ) {
while ( !$person ) {
try {
print "Enter your age : ";
print 'Enter your age : ';
my $age = <STDIN>;
chomp $age;
print "Enter your name : ";
print 'Enter your name : ';
my $name = <STDIN>;
chomp $name;
$person = Person->new( age => $age,
name => $name
);
$person = Person->new(
age => $age,
name => $name
);
my $person_name = $person->name;
my $person_age = $person->age;
print "$person_name is $person_age years old\n";
} catch {
my $exception = $_;

if ( blessed $exception && $exception->isa("Moose::Exception::ValidationFailedForTypeConstraint") ) {
}
catch {
my $e = $_;

# fetch attributes from the $exception object and display a friendly error to the user
my $attribute_name = $exception->attribute->name;
my $type_name = $exception->type->name;
my $value = $exception->value;
if (
blessed $e
&& $e->isa(
'Moose::Exception::ValidationFailedForTypeConstraint')
) {

warn "You entered $value for $attribute_name, which is not $type_name!";
} else {
my $attribute_name = $e->attribute->name;
my $type_name = $e->type->name;
my $value = $e->value;

# you've got some other kind of exception, so just print it
# note: all Moose::Exception objects will stringify to a useful error message
warn "$exception\n";
warn
"You entered $value for $attribute_name, which is not a $type_name!";
}
else {
warn "$e\n";
}
}
}
Expand All @@ -126,7 +146,7 @@ L<Moose::Exception::ExtendsMissingArgs>.
package Example::RequiredAttribute;
use Moose;

has 'required_attribute' => (
has required_attribute => (
is => 'ro',
isa => 'Int',
required => 1
Expand All @@ -136,30 +156,18 @@ L<Moose::Exception::ExtendsMissingArgs>.
try {
# we're not passing required_attribute, so it'll throw an exception
my $object = Example::RequiredAttribute->new();
} catch {
my $exception = $_;
if ( blessed $exception && $exception->isa("Moose::Exception::AttributeIsRequired") ) {

# fetch attributes from the $exception object and display only
# the topmost frame of the stack trace
my $attribute_name = $exception->attribute->name;
my $trace = $exception->trace;

my $frame = $trace->frame(0);

my $message = $exception->message;
my $file = $frame->{filename};
my $line = $frame->{line};

warn "$message at $file $line\n";
} else {

# you've got some other kind of exception, so just print it
# note: all Moose::Exception objects will stringify to a useful error message
warn "$exception\n";
}
catch {
my $e = $_;
if ( blessed $e && $e->isa('Moose::Exception::AttributeIsRequired') )
{
warn $e->message, "\n";
}
else {
warn "$e\n";
}
};

=head1 Moose Exception Types
=head2 Moose Exception Classes

These are documented in L<Moose::Manual::Exceptions::Manifest>.
All the exception classes are listed in L<Moose::Manual::Exceptions::Manifest>.

0 comments on commit 90893cd

Please sign in to comment.