• Home
  • History
  • Annotate
Name Date Size #Lines LOC

..03-May-2022-

lib/X/H17-Sep-2019-495113

t/H17-Sep-2019-231151

.appveyor.ymlH A D22-Mar-2019889 3830

.gitignoreH A D25-Feb-2017197 2221

.travis.ymlH A D16-Sep-20191.6 KiB6560

ChangesH A D17-Sep-20191.4 KiB5137

LICENSEH A D25-Aug-201820.1 KiB384309

MANIFESTH A D17-Sep-2019408 2019

META.jsonH A D17-Sep-20191.4 KiB6362

META.ymlH A D17-Sep-2019778 3332

Makefile.PLH A D16-Sep-20191.1 KiB4232

README.mdH A D17-Sep-20194.9 KiB15299

README.md

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