The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.

NAME

Exception::Stringy - a Perl Exceptions module where exceptions are not objects but simple strings.

VERSION

version 0.11

SYNOPSIS

  use Exception::Stringy (
      'MyException',
   
      'YetAnotherException' => {
          isa         => 'AnotherException',
      },
   
      'ExceptionWithFields' => {
          isa    => 'YetAnotherException',
          fields => [ 'grandiosity', 'quixotic' ],
          alias  => 'throw_fields',
      },
  );
  
  ## with Try::Tiny
  
  use Try::Tiny;
   
  try {
      # throw an exception
      MyException->throw('I feel funny.');
  
      # or use an aliase
      throw_fields 'Error message', grandiosity => 1;

      # you can build exception step by step
      my $e = ExceptionWithFields->new("The error message");
      $e->$_x_field(quixotic => "some_value");
      $e->$_x_throw();
  
  }
  catch {
      if ( $_->$_x_isa('Exception::Stringy') ) {
          warn $_->$_x_error, "\n";
      }
  
      if ( $_->$_x_isa('ExceptionWithFields') ) {
          if ( $e->_x_field('quixotic') ) {
              handle_quixotic_exception();
          }
          else {
              handle_non_quixotic_exception();
          }
      }
      else {
          $_->$_x_rethrow;
      }
  };
   
  # without Try::Tiny
   
  eval {
      # ...
      MyException->throw('I feel funny.');
      1;
  } or do {
      my $e = $@;
      # .. same as above with $e instead of $_
  }

DESCRIPTION

This module allows you to declare exceptions, and provides a simple interface to declare, throw, and interact with them. It can be seen as a light version of Exception::Class, except that there is a catch: exceptions are not objects, they are normal strings, with a pattern that contains properties.

WHY WOULD YOU WANT SUCH THING ?

Having exceptions be objects is sometimes very annoying. What if some code is calling you, and isn't expecting objects exceptions ? Sometimes string overloading doesn't work. Sometimes, external code tamper with your exception. Consider:

  use Exception::Class ('MyException');
  use Scalar::Util qw( blessed );
  use Try::Tiny;

  $SIG{__DIE__} = sub { die "FATAL: $_[0]" };

  try {
    MyException->throw("foo");
  } catch {
    die "this is not a Class::Exception" unless blessed $_ && $_->can('rethrow');
    if ($_->isa('MyException')) { ... }
  };

In this example, the exception thrown is a Class::Exception instance, but it gets forced to a string by the signal handler. When in the catch block, it's not an object, it's a regular string, and the code fails to see that it's a 'MyException'.

BUT THIS NEVER HAPPENS

Well, don't use this module then :)

BASIC USAGE

Declaring exception types

throwing exceptions

  ExceptionWithFields->throw("error message", grandiosity => 42);

catching and checking exceptions

  eval { ... 1; } or do {
    my $e = $@;
    if ($e->$_x_isa('Exception::Stringy')) {
      if ($e->$_x_isa('ExceptionWithFields')) {
        ...
      } elsif ($e->$_x_isa('YetAnotherException')) {
        ...
      }
    } else {
      # this works on anything, even objects or bare strings
      e->$_x_rethrow;
    }
  };

CLASS METHODS

raise, throw

  # both are exactly the same
  ExceptionWithFields->throw("error message", grandiosity => 42);
  ExceptionWithFields->raise("error message", grandiosity => 42);

Creates an string exception from the given class, with the error message and fields, then throws the exception. The exception is thrown using croak() from the Carp module.

The error message is always the first argument If ommited, it'll default to empty string. Optional fields are provided as flat key / value pairs.

new

  my $e = ExceptionWithFields->new("error message", grandiosity => 42);

Takes the same arguments as throw() but doesn't throw the exception. Instead, the exception is returned.

registered_fields

  my @fields = ExceptionWithFields->registered_fields;

Returns the possible fields that an exception of the given class can have.

registered_exception_classes

  my @class_names = Exception::Stringy->registered_exception_classes;

Returns the exceptions classes that have been registered.

METHODS

The syntax is a bit strange, but that's because exceptions are bare strings, and not blessed references, so we have to use a trick to have the arrow syntax working ( thanks to pokki for the hint ).

The _x_ prefix is used because x looks like exception.

$_x_throw(), $_x_rethrow(), $_x_raise()

  $exception->$_x_throw();
  $exception->$_x_rethrow();
  $exception->$_x_raise();

Throws the exception.

$_x_class()

  my $class = $exception->$_x_class();

Returns the exception class name.

$_x_isa()

  if ($exception->$_x_isa('ExceptionClass')) {... }

Returns true if the class of the given exception -isa()> the class given in parameter.

$_x_fields()

  my @fields = $exception->$_x_fields();

Returns the list of field names that are in the exception.

$_x_field()

  my $value = $exception->$_x_field('field_name');

  $exception->$_x_field(field_name => $value);

Set or get the given field. If the value contains one of these forbidden caracters, then it is transparently base64 encoded and decoded.

The list of forbidden caracters are:

:

the semicolon

|

the pipe

\034

\034, the 0x28 seperator ASCII caracter.

$_x_message(), $_x_error()

  my $text = $exception->$_x_message();
  my $text = $exception->$_x_error();

  $exception->$_x_message("Error message");
  $exception->$_x_error("Error message");

Set or get the error message of the exception

AUTHOR

Damien Krotkine <dams@cpan.org>

COPYRIGHT AND LICENSE

This software is Copyright (c) 2014 by Damien Krotkine.

This is free software, licensed under:

  The Artistic License 2.0 (GPL Compatible)