# You may distribute under the terms of either the GNU General Public License # or the Artistic License (the same terms as Perl itself) # # (C) Paul Evans, 2019 -- leonerd@leonerd.org.uk package Future::Exception; use v5.10; use strict; use warnings; our $VERSION = '0.50'; =head1 NAME C - an exception type for failed Ls =head1 SYNOPSIS use Scalar::Util qw( blessed ); use Syntax::Keyword::Try; try { my $f = ...; my @result = $f->result; ... } catch { if( blessed($@) and $@->isa( "Future::Exception" ) { print STDERR "The ", $@->category, " failed: ", $@->message, "\n"; } } =head1 DESCRIPTION The C method on a failed L instance will throw an exception to indicate that the future failed. A failed future can contain a failure category name and other details as well as the failure message, so in this case the exception will be an instance of C to make these values accessible. Users should not depend on exact class name matches, but instead rely on inheritence, as a later version of this implementation might dynamically create subclasses whose names are derived from the Future failure category string, to assist with type matching. Note the use of C<< ->isa >> in the SYNOPSIS example. =cut use overload '""' => "message", fallback => 1; =head1 CONSTRUCTOR =head2 from_future $e = Future::Exception->from_future( $f ) Constructs a new C wrapping the given failed future. =cut sub from_future { my $class = shift; my ( $f ) = @_; return $class->new( $f->failure ); } sub new { my $class = shift; bless [ @_ ], $class; } =head1 ACCESSORS $message = $e->message $category = $e->category @details = $e->details Additionally, the object will stringify to return the message value, for the common use-case of printing, regexp testing, or other behaviours. =cut sub message { shift->[0] } sub category { shift->[1] } sub details { my $self = shift; @{$self}[2..$#$self] } =head1 METHODS =cut =head2 throw Future::Exception->throw( $message, $category, @details ) I Constructs a new exception object and throws it using C. This method will not return, as it raises the exception directly. If C<$message> does not end in a linefeed then the calling file and line number are appended to it, in the same way C does. =cut sub throw { my $class = shift; my ( $message, $category, @details ) = @_; $message =~ m/\n$/ or $message .= sprintf " at %s line %d.\n", ( caller )[1,2]; die $class->new( $message, $category, @details ); } # TODO: consider a 'croak' method that uses Carp::shortmess to find a suitable # file/linenumber =head2 as_future $f = $e->as_future Returns a new C object in a failed state matching the exception. =cut sub as_future { my $self = shift; return Future->fail( $self->message, $self->category, $self->details ); } =head1 AUTHOR Paul Evans =cut 0x55AA;