File Coverage

blib/lib/X/Tiny.pm
Criterion Covered Total %
statement 20 20 100.0
branch 2 2 100.0
condition n/a
subroutine 6 6 100.0
pod 1 1 100.0
total 29 29 100.0


line stmt bran cond sub pod time code
1             package X::Tiny;
2              
3 2     2   69482 use strict;
  2         12  
  2         55  
4 2     2   9 use warnings;
  2         7  
  2         106  
5              
6             our $VERSION = '0.17-TRIAL1';
7              
8             =encoding utf-8
9              
10             =head1 NAME
11              
12             X::Tiny - Base class for a bare-bones exception factory
13              
14             =head1 SYNOPSIS
15              
16             package My::Module::X;
17              
18             use parent qw( X::Tiny );
19              
20             #----------------------------------------------------------------------
21              
22             package My::Module::X::Base;
23              
24             use parent qw( X::Tiny::Base );
25              
26             #----------------------------------------------------------------------
27              
28             package My::Module::X::IO;
29              
30             use parent qw( My::Module::X::Base );
31              
32             #----------------------------------------------------------------------
33              
34             package My::Module::X::Blah;
35              
36             use parent qw( My::Module::X::Base );
37              
38             sub _new {
39             my ($class, @args) = @_;
40              
41             my $self = $class->SUPER::_new('Blah blah', @args);
42              
43             return bless $self, $class;
44             }
45              
46             #----------------------------------------------------------------------
47              
48             package main;
49              
50             local $@; #always!
51             eval {
52             die My::Module::X->create('IO', 'The message', key1 => val1, … );
53             };
54              
55             if ( my $err = $@ ) {
56             print $err->get('key1');
57             }
58              
59             die My::Module::X->create('Blah', key1 => val1, … );
60              
61             =head1 DESCRIPTION
62              
63             This stripped-down exception framework provides a baseline
64             of functionality for distributions that want to expose exception
65             hierarchies with minimal fuss. It’s a pattern that I implemented in some
66             other distributions I created and didn’t want to copy/paste around.
67              
68             =head1 BENEFITS OF EXCEPTIONS
69              
70             Exceptions are better for error reporting in Perl than the
71             C-style “return in failure” pattern. In brief,
72             you should use exceptions because they are a logical, natural way to report
73             failures: if you’re given a set of instructions, and something goes wrong
74             in one of those instructions, it makes sense to stop and go back to see what
75             to do in response to the problem.
76              
77             Perl’s built-ins unwisely make the caller responsible for error checking—as
78             a result of which much Perl code fails to check for failures from those
79             built-ins, which makes for far more difficult debugging when some code down
80             the line just mysteriously produces an unexpected result.
81             The more sensible pattern is for an exception to be thrown at the spot where
82             the error occurred.
83              
84             Perl’s default exceptions are just scalars. A more useful pattern is to throw
85             exception objects whose type and attributes can facilitate meaningful
86             error checking; for example, you may not care if a call to C fails
87             with C, so you can just ignore that failure. Or, you might care, but
88             you might prefer just to C rather than to stop what you’re doing.
89              
90             X::Tiny is one of many CPAN modules that facilitates this pattern. What
91             separates X::Tiny from other such modules is its light weight: the only
92             “heavy” dependency is L, which is (in my experience) a reasonable
93             trade-off for the helpfulness of having stack traces on uncaught exceptions.
94             (The stack trace is custom logic, much lighter than L.)
95              
96             =head1 FEATURES
97              
98             =over
99              
100             =item * Super-lightweight: No exceptions are loaded until they’re needed.
101              
102             =item * Simple, flexible API
103              
104             =item * String overload with stack trace
105              
106             =item * Minimal code necessary
107              
108             =back
109              
110             =head1 USAGE
111              
112             You’ll first create a factory class that subclasses C.
113             (In the SYNOPSIS’s example, this module is C.) All of your
114             exceptions B exist under that factory class’s namespace.
115              
116             You’ll then create a base exception class for your distribution.
117             In the SYNOPSIS’s example, this module is C.
118             Your distribution’s other exceptions should all subclass this one.
119              
120             =head1 METHODS
121              
122             There’s only one method in the factory class:
123              
124             =head2 I->create( TYPE, ARG1, ARG2, .. )
125              
126             To create an exception, call the C method of your factory class.
127             This will load the exception class if it’s not already in memory.
128             The TYPE you pass in is equivalent to the exception class’s module name but
129             with the factory class’s name chopped off the left part. So, if you call:
130              
131             My::Module::X->create('BadInput', 'foo', 'bar')
132              
133             … this will instantiate and return an instance of C,
134             with the arguments C and C.
135              
136             =head1 EXCEPTION OBJECTS
137              
138             See L for more information about the features that that
139             module exposes to subclasses.
140              
141             =head1 DESIGN CONSIDERATIONS
142              
143             Admittedly, the lazy-loading behavior here embodies a generally-unwise
144             practice of doing failure-prone work (i.e., loading a module at runtime)
145             in the process of reporting a failure.
146             In my own experience, though, that’s a reasonable tradeoff for the
147             expressiveness of typed exceptions.
148              
149             Do be sure that any failure-prone work you do as part of exception
150             instantiation has its own failure-checking mechanism. There really are not
151             meant to be “sub-failures” here!
152              
153             =cut
154              
155 2     2   10 use strict;
  2         2  
  2         79  
156 2     2   11 use warnings;
  2         4  
  2         51  
157              
158 2     2   982 use Module::Load ();
  2         2330  
  2         186  
159              
160             sub create {
161 5     5 1 25307 my ( $class, $type, @args ) = @_;
162              
163 5         23 my $x_package = "${class}::$type";
164              
165 5 100       66 if (!$x_package->can('new')) {
166 1         15 Module::Load::load($x_package);
167             }
168              
169 5         175 return $x_package->new(@args);
170             }
171              
172             1;
173              
174             #----------------------------------------------------------------------
175              
176             =head1 REPOSITORY
177              
178             L
179              
180             =head1 AUTHOR
181              
182             Felipe Gasper (FELIPE)
183              
184             =head1 COPYRIGHT
185              
186             Copyright 2017 by L
187              
188             =head1 LICENSE
189              
190             This distribution is released under the same license as Perl.