File Coverage

blib/lib/Data/Object/Exception.pm
Criterion Covered Total %
statement 64 64 100.0
branch 18 22 81.8
condition 6 10 60.0
subroutine 11 11 100.0
pod 3 5 60.0
total 102 112 91.0


line stmt bran cond sub pod time code
1             package Data::Object::Exception;
2              
3 1     1   37651 use 5.014;
  1         5  
4              
5 1     1   6 use strict;
  1         3  
  1         23  
6 1     1   5 use warnings;
  1         3  
  1         38  
7 1     1   7 use routines;
  1         2  
  1         8  
8              
9 1     1   1834 use Moo;
  1         2  
  1         7  
10              
11             use overload (
12 1         13 '""' => 'explain',
13             '~~' => 'explain',
14             fallback => 1
15 1     1   380 );
  1         3  
16              
17             our $VERSION = '2.02'; # VERSION
18              
19             has id => (
20             is => 'ro'
21             );
22              
23             has context => (
24             is => 'ro'
25             );
26              
27             has frames => (
28             is => 'ro'
29             );
30              
31             has message => (
32             is => 'ro',
33             default => 'Exception!'
34             );
35              
36             # BUILD
37              
38 13     13 0 195 fun BUILD($self, $args) {
  13         19  
39              
40             # build stack trace
41 13 100       65 return $self->trace(2) if !$self->frames;
42             }
43              
44 13     13 0 111815 fun BUILDARGS($class, @args) {
  13         23  
45              
46             # constructor arguments
47             return {
48             @args == 1
49             # ...
50             ? !ref($args[0])
51             # single non-ref argument
52             ? (message => $args[0])
53             # ...
54             : 'HASH' eq ref($args[0])
55             # single hash-based argument
56 13 50       210 ? %{$args[0]}
  3 100       56  
    100          
57             # non hash-based argument
58             : ()
59             # multiple arguments
60             : @args
61             };
62             }
63              
64             # FUNCTIONS
65              
66 3     3 1 20 fun throw($self, $message, $context, $offset) {
  3         5  
67 3         5 my $id;
68              
69 3   33     13 my $class = ref $self || $self;
70              
71 3         5 my $args = {};
72              
73 3 100       10 if (ref $message eq 'ARRAY') {
74 1         4 ($id, $message) = @$message;
75             }
76              
77 3 50       10 if (ref $self) {
78 3         11 for my $name (keys %$self) {
79 6         15 $args->{$name} = $self->{$name};
80             }
81             }
82              
83 3 100       9 $args->{id} = $id if $id;
84 3 100       9 $args->{message} = $message if $message;
85 3 50       7 $args->{context} = $context if $context;
86              
87 3         51 my $exception = $self->new($args);
88              
89 3         7 die $exception->trace($offset);
90             }
91              
92             # METHODS
93              
94 13     13 1 1472 method explain() {
  13         19  
95 13 50       39 $self->trace(1, 1) if !$self->{frames};
96              
97 13         37 my $frames = $self->{frames};
98              
99 13         26 my $file = $frames->[0][1];
100 13         20 my $line = $frames->[0][2];
101 13         22 my $pack = $frames->[0][0];
102 13         19 my $subr = $frames->[0][3];
103              
104 13   50     30 my $message = $self->{message} || 'Exception!';
105              
106 13         45 my @stacktrace = ("$message in $file at line $line");
107              
108 13         42 for (my $i = 1; $i < @$frames; $i++) {
109 155         232 my $pack = $frames->[$i][0];
110 155         202 my $file = $frames->[$i][1];
111 155         206 my $line = $frames->[$i][2];
112 155         208 my $subr = $frames->[$i][3];
113              
114 155         486 push @stacktrace, "\t$subr in $file at line $line";
115             }
116              
117 13         124 return join "\n", @stacktrace, "";
118             }
119              
120 16     16 1 35 method trace($offset, $limit) {
  16         30  
  16         26  
121 16         56 $self->{frames} = my $frames = [];
122              
123 16   100     171 for (my $i = $offset // 1; my @caller = caller($i); $i++) {
124 210         597 push @$frames, [@caller];
125              
126 210 100 66     1240 last if defined $limit && $i + 1 == $offset + $limit;
127             }
128              
129 16         274 return $self;
130             }
131              
132             1;
133              
134             =encoding utf8
135              
136             =head1 NAME
137              
138             Data::Object::Exception
139              
140             =cut
141              
142             =head1 ABSTRACT
143              
144             Exception Class for Perl 5
145              
146             =cut
147              
148             =head1 SYNOPSIS
149              
150             use Data::Object::Exception;
151              
152             my $exception = Data::Object::Exception->new;
153              
154             # $exception->throw
155              
156             =cut
157              
158             =head1 DESCRIPTION
159              
160             This package provides functionality for creating, throwing, and introspecting
161             exception objects.
162              
163             =cut
164              
165             =head1 SCENARIOS
166              
167             This package supports the following scenarios:
168              
169             =cut
170              
171             =head2 args-1
172              
173             use Data::Object::Exception;
174              
175             my $exception = Data::Object::Exception->new('Oops!');
176              
177             # $exception->throw
178              
179             The package allows objects to be instantiated with a single argument.
180              
181             =cut
182              
183             =head2 args-kv
184              
185             use Data::Object::Exception;
186              
187             my $exception = Data::Object::Exception->new(message => 'Oops!');
188              
189             # $exception->throw
190              
191             The package allows objects to be instantiated with key-value arguments.
192              
193             =cut
194              
195             =head1 ATTRIBUTES
196              
197             This package has the following attributes:
198              
199             =cut
200              
201             =head2 context
202              
203             context(Any)
204              
205             This attribute is read-only, accepts C<(Any)> values, and is optional.
206              
207             =cut
208              
209             =head2 id
210              
211             id(Str)
212              
213             This attribute is read-only, accepts C<(Str)> values, and is optional.
214              
215             =cut
216              
217             =head2 message
218              
219             message(Str)
220              
221             This attribute is read-only, accepts C<(Str)> values, and is optional.
222              
223             =cut
224              
225             =head1 METHODS
226              
227             This package implements the following methods:
228              
229             =cut
230              
231             =head2 explain
232              
233             explain() : Str
234              
235             The explain method returns an error message with stack trace.
236              
237             =over 4
238              
239             =item explain example #1
240              
241             use Data::Object::Exception;
242              
243             my $exception = Data::Object::Exception->new('Oops!');
244              
245             $exception->explain
246              
247             =back
248              
249             =cut
250              
251             =head2 throw
252              
253             throw(Tuple[Str, Str] | Str $message, Any $context, Maybe[Number] $offset) : Any
254              
255             The throw method throws an error with message (and optionally, an ID).
256              
257             =over 4
258              
259             =item throw example #1
260              
261             use Data::Object::Exception;
262              
263             my $exception = Data::Object::Exception->new;
264              
265             $exception->throw('Oops!')
266              
267             =back
268              
269             =over 4
270              
271             =item throw example #2
272              
273             use Data::Object::Exception;
274              
275             my $exception = Data::Object::Exception->new('Oops!');
276              
277             $exception->throw
278              
279             =back
280              
281             =over 4
282              
283             =item throw example #3
284              
285             use Data::Object::Exception;
286              
287             my $exception = Data::Object::Exception->new;
288              
289             $exception->throw(['E001', 'Oops!'])
290              
291             =back
292              
293             =cut
294              
295             =head2 trace
296              
297             trace(Int $offset, $Int $limit) : Object
298              
299             The trace method compiles a stack trace and returns the object. By default it
300             skips the first frame.
301              
302             =over 4
303              
304             =item trace example #1
305              
306             use Data::Object::Exception;
307              
308             my $exception = Data::Object::Exception->new('Oops!');
309              
310             $exception->trace(0)
311              
312             =back
313              
314             =over 4
315              
316             =item trace example #2
317              
318             use Data::Object::Exception;
319              
320             my $exception = Data::Object::Exception->new('Oops!');
321              
322             $exception->trace(1)
323              
324             =back
325              
326             =over 4
327              
328             =item trace example #3
329              
330             use Data::Object::Exception;
331              
332             my $exception = Data::Object::Exception->new('Oops!');
333              
334             $exception->trace(0,1)
335              
336             =back
337              
338             =cut
339              
340             =head1 AUTHOR
341              
342             Al Newkirk, C<awncorp@cpan.org>
343              
344             =head1 LICENSE
345              
346             Copyright (C) 2011-2019, Al Newkirk, et al.
347              
348             This is free software; you can redistribute it and/or modify it under the terms
349             of the The Apache License, Version 2.0, as elucidated in the L<"license
350             file"|https://github.com/iamalnewkirk/data-object-exception/blob/master/LICENSE>.
351              
352             =head1 PROJECT
353              
354             L<Wiki|https://github.com/iamalnewkirk/data-object-exception/wiki>
355              
356             L<Project|https://github.com/iamalnewkirk/data-object-exception>
357              
358             L<Initiatives|https://github.com/iamalnewkirk/data-object-exception/projects>
359              
360             L<Milestones|https://github.com/iamalnewkirk/data-object-exception/milestones>
361              
362             L<Contributing|https://github.com/iamalnewkirk/data-object-exception/blob/master/CONTRIBUTE.md>
363              
364             L<Issues|https://github.com/iamalnewkirk/data-object-exception/issues>
365              
366             =cut