File Coverage

blib/lib/App/Sqitch/X.pm
Criterion Covered Total %
statement 29 29 100.0
branch 4 4 100.0
condition n/a
subroutine 10 10 100.0
pod 2 2 100.0
total 45 45 100.0


line stmt bran cond sub pod time code
1              
2             use 5.010;
3 55     55   180879 use utf8;
  55         178  
4 55     55   306 use Moo;
  55         130  
  55         375  
5 55     55   25595 use Types::Standard qw(Str Int);
  55         400271  
  55         269  
6 55     55   94271 use Sub::Exporter::Util ();
  55         3375743  
  55         1760  
7 55     55   71430 use Throwable 0.200009;
  55         470630  
  55         1610  
8 55     55   24776 use Sub::Exporter -setup => [qw(hurl)];
  55         1200705  
  55         2752  
9 55     55   513 use overload '""' => 'as_string';
  55         106  
  55         415  
10 55     55   22403  
  55         121  
  55         336  
11             our $VERSION = 'v1.3.1'; # VERSION
12              
13             has message => (
14             is => 'ro',
15             isa => Str,
16             required => 1,
17             );
18              
19             has exitval => (
20             is => 'ro',
21             isa => Int,
22             default => 2,
23             );
24              
25              
26             with qw(
27             Throwable
28             StackTrace::Auto
29             );
30              
31             has ident => (
32             is => 'ro',
33             isa => Str,
34             default => 'DEV'
35             );
36              
37             has '+previous_exception' => (init_arg => 'previous_exception')
38             if Throwable->VERSION < 0.200007;
39              
40             @_ = (
41             __PACKAGE__,
42             # Always pass $@, as Throwable is unreliable about getting it thanks
43             # to hash randomization. Its workaround in v0.200006:
44             # https://github.com/rjbs/throwable/commit/596dfbafed970a30324dc21539d4edf2cbda767a
45             previous_exception => $@,
46             ref $_[0] ? %{ $_[0] }
47             : @_ == 1 ? (message => $_[0])
48 477 100   477 1 63105 : (ident => $_[0], message => $_[1])
  28 100       180  
49             );
50             goto __PACKAGE__->can('throw');
51             }
52 477         4977  
53             my $self = shift;
54             join "\n", grep { defined } (
55             $self->message,
56 54     54 1 83239 $self->previous_exception,
57 54         1014 $self->stack_trace
  162         797  
58             );
59             }
60              
61             1;
62              
63              
64             =head1 Name
65              
66             App::Sqitch::X - Sqitch Exception class
67              
68             =head1 Synopsis
69              
70             use Locale::TextDomain;
71             use App::Sqitch::X qw(hurl);
72             open my $fh, '>', 'foo.txt' or hurl {
73             ident => 'io',
74             message => __x 'Cannot open {file}: {err}", file => 'foo.txt', err => $!,
75             };
76              
77             Developer:
78              
79             hurl 'Odd number of arguments passed to burf()' if @_ % 2;
80              
81             =head1 Description
82              
83             This module provides implements Sqitch exceptions. Exceptions may be thrown by
84             any part of the code, and, as long as a command is running, they will be
85             handled, showing the error message to the user.
86              
87             =head1 Interface
88              
89             =head2 Function
90              
91             =head3 C<hurl>
92              
93             Throws an exception. Pass the parameters as a hash reference, like so:
94              
95             use App::Sqitch::X qw(hurl);
96             open my $fh, '>', 'foo.txt' or hurl {
97             ident => 'io',
98             message => __x 'Cannot open {file}: {err}", file => 'foo.txt', err => $!,
99             };
100              
101             More simply, if all you need to pass are the C<ident> and C<message>
102             parameters, you can pass them as the only arguments to C<hurl()>:
103              
104             open my $fh, '>', 'foo.txt'
105             or hurl io => __x 'Cannot open {file}: {err}", file => 'foo.txt', err => $!
106              
107             For errors that should only happen during development (e.g., an invalid
108             parameter passed by some other library that should know better), you can omit
109             the C<ident>:
110              
111             hurl 'Odd number of arguments passed to burf()' if @_ % 2;
112              
113             In this case, the C<ident> will be C<DEV>, which you should not otherwise use.
114             Sqitch will emit a more detailed error message, including a stack trace, when
115             it sees C<DEV> exceptions.
116              
117             The supported parameters are:
118              
119             =over
120              
121             =item C<ident>
122              
123             A non-localized string identifying the type of exception.
124              
125             =item C<message>
126              
127             The exception message. Use L<Locale::TextDomain> to craft localized messages.
128              
129             =item C<exitval>
130              
131             Suggested exit value to use. Defaults to 2. This will be used if Sqitch
132             handles an exception while a command is running.
133              
134             =back
135              
136             =head2 Methods
137              
138             =head3 C<as_string>
139              
140             my $errstr = $x->as_string;
141              
142             Returns the stringified representation of the exception. This value is also
143             used for string overloading of the exception object, which means it is the
144             output shown for uncaught exceptions. Its contents are the concatenation of
145             the exception message, the previous exception (if any), and the stack trace.
146              
147             =head1 Handling Exceptions
148              
149             use L<Try::Tiny> to do exception handling, like so:
150              
151             use Try::Tiny;
152             try {
153             # ...
154             } catch {
155             die $_ unless eval { $_->isa('App::Sqitch::X') };
156             $sqitch->vent($x_->message);
157             if ($_->ident eq 'DEV') {
158             $sqitch->vent($_->stack_trace->as_string);
159             } else {
160             $sqitch->debug($_->stack_trace->as_string);
161             }
162             exit $_->exitval;
163             };
164              
165             Use the C<ident> attribute to determine what category of exception it is, and
166             take changes as appropriate.
167              
168             =head1 Author
169              
170             David E. Wheeler <david@justatheory.com>
171              
172             =head1 License
173              
174             Copyright (c) 2012-2022 iovation Inc., David E. Wheeler
175              
176             Permission is hereby granted, free of charge, to any person obtaining a copy
177             of this software and associated documentation files (the "Software"), to deal
178             in the Software without restriction, including without limitation the rights
179             to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
180             copies of the Software, and to permit persons to whom the Software is
181             furnished to do so, subject to the following conditions:
182              
183             The above copyright notice and this permission notice shall be included in all
184             copies or substantial portions of the Software.
185              
186             THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
187             IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
188             FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
189             AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
190             LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
191             OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
192             SOFTWARE.
193              
194             =cut
195