File Coverage

blib/lib/App/Sqitch/X.pm
Criterion Covered Total %
statement 32 32 100.0
branch 4 4 100.0
condition n/a
subroutine 11 11 100.0
pod 3 3 100.0
total 50 50 100.0


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