1custom::failures(3) User Contributed Perl Documentation custom::failures(3)
2
3
4
6 custom::failures - Minimalist, customized exception hierarchy generator
7
9 version 0.004
10
12 package MyApp::failure;
13
14 use custom::failures qw/io::file io::network/;
15
16 # customize failure methods…
17
19 This module works like failures but lets you define a customized
20 exception hierarchy if you need a custom namespace, additional
21 attributes, or customized object behaviors.
22
23 Because failure classes have an @ISA chain and Perl by default uses
24 depth-first-search to resolve method calls, you can override behavior
25 anywhere in the custom hierarchy and it will take precedence over
26 default "failure" behaviors.
27
28 There are two methods that might be useful to override:
29
30 • message
31
32 • throw
33
34 Both are described further, below.
35
37 Defining a custom failure hierarchy
38 package MyApp::failure;
39
40 use custom::failures qw/foo::bar/;
41
42 This will define a failure class hierarchy under the calling package's
43 namespace. The following diagram show the classes that will be created
44 (arrows denote 'is-a' relationships):
45
46 MyApp::failure::foo::bar --> failure::foo::bar
47 | |
48 V V
49 MyApp::failure::foo --> failure::foo
50 | |
51 V V
52 MyApp::failure --> failure
53
54 Alternatively, if you want a different namespace for the hierarchy, do
55 it this way:
56
57 use custom::failures 'MyApp::Error' => [ 'foo::bar' ];
58
59 That will create the following classes and relationships:
60
61 MyApp::Error::foo::bar --> failure::foo::bar
62 | |
63 V V
64 MyApp::Error::foo --> failure::foo
65 | |
66 V V
67 MyApp::Error --> failure
68
69 By having custom classes also inherit from a standard namespace, you
70 can throw a custom error class that will still be caught in the
71 standard namespace:
72
73 use Safe::Isa; # for $_isa
74 try {
75 MyApp::failure::foo::bar->throw;
76 }
77 catch {
78 if ( $_->$_isa( "failure::foo" ) ) {
79 # handle it here
80 }
81 };
82
83 Adding custom attributes
84 Failure classes are implemented with Class::Tiny, so adding attributes
85 is trivially easy:
86
87 package MyApp::failure;
88
89 use custom::failures qw/foo::bar/;
90
91 use Class::Tiny qw/user/;
92
93 This adds a "user" attribute to "MyApp::failure" and all its subclasses
94 so it can be set in the argument to "throw":
95
96 MyApp::failure::foo->throw( { msg => "Ouch!", user => "me" } );
97
98 Be sure to load "Class::Tiny" after you load "custom::failures" so that
99 your @ISA is already set up.
100
101 Overriding the "message" method
102 Overriding "message" lets you modify how the error string is produced.
103 The "message" method takes a string (typically just the "msg" field)
104 and returns a string. It should not produce or append stack trace
105 information. That is done during object stringification.
106
107 Call "SUPER::message" if you want the standard error text prepended
108 ("Caught $class: ...").
109
110 For example, if you want to use String::Flogger to render messages:
111
112 package MyApp::failure;
113
114 use custom::failures qw/foo::bar/;
115 use String::Flogger qw/flog/;
116
117 sub message {
118 my ( $self, $msg ) = @_;
119 return $self->SUPER::message( flog($msg) );
120 }
121
122 Then you can pass strings or array references or code references as the
123 "msg" for "throw":
124
125 MyApp::failure->throw( "just a string" );
126 MyApp::failure->throw( [ "show some data %s", $ref ] );
127 MyApp::failure->throw( sub { call_expensive_sub() } );
128
129 Because the "message" method is only called during stringification
130 (unless you call it yourself), the failure class type can be checked
131 before any expensive rendering is done.
132
133 Overriding the "throw" method
134 Overriding "throw" lets you modify the arguments you can provide or
135 ensure that a trace is included. It can take whatever arguments you
136 want and should call "SUPER::throw" with a hash reference to actually
137 throw the error.
138
139 For example, to capture the filename associated with file errors:
140
141 package MyApp::failure;
142
143 use custom::failures qw/file/;
144
145 use Class::Tiny qw/filename/;
146
147 sub throw {
148 my ( $class, $msg, $file ) = @_;
149 my $args = {
150 msg => $msg,
151 filename => $file,
152 trace => failures->croak_trace,
153 };
154 $self->SUPER::throw( $args );
155 }
156
157 sub message {
158 # do something with 'msg' and 'filename'
159 }
160
161 Later you could use it like this:
162
163 MyApp::failure::file->throw( opening => $some_file );
164
165 Using BUILD
166 "Class::Tiny" supports "BUILD", so you can also use that to do things
167 with failure objects when thrown. This example logs exceptions as they
168 are built:
169
170 use Log::Any qw/$log/;
171
172 sub BUILD {
173 my ($self) = @_;
174 $log->error( $self->message );
175 }
176
177 By using "message" instead of stringifying $self, we log the message
178 but not the trace (if any).
179
181 David Golden <dagolden@cpan.org>
182
184 This software is Copyright (c) 2013 by David Golden.
185
186 This is free software, licensed under:
187
188 The Apache License, Version 2.0, January 2004
189
190
191
192perl v5.34.0 2021-07-23 custom::failures(3)