File Coverage

blib/lib/Venus/Throw.pm
Criterion Covered Total %
statement 62 78 79.4
branch 16 20 80.0
condition 21 36 58.3
subroutine 13 16 81.2
pod 4 7 57.1
total 116 157 73.8


line stmt bran cond sub pod time code
1             package Venus::Throw;
2              
3 39     39   964 use 5.018;
  39         155  
4              
5 39     30   1562 use strict;
  30         80  
  30         764  
6 30     30   756 use warnings;
  30         93  
  30         1190  
7              
8 30     29   323 use Venus::Class 'attr', 'base', 'with';
  29         66  
  29         256  
9              
10             base 'Venus::Kind::Utility';
11              
12             with 'Venus::Role::Stashable';
13              
14             use overload (
15 36     36   1170 '""' => sub{$_[0]->catch('error')->explain},
16 0     0   0 '~~' => sub{$_[0]->catch('error')->explain},
17 29         483 fallback => 1,
18 29     29   236 );
  29         81  
19              
20             # ATTRIBUTES
21              
22             attr 'frame';
23             attr 'name';
24             attr 'message';
25             attr 'package';
26             attr 'parent';
27             attr 'context';
28              
29             # BUILDERS
30              
31             sub build_arg {
32 19     19 0 40 my ($self, $data) = @_;
33              
34             return {
35 19         91 package => $data,
36             };
37             }
38              
39             sub build_self {
40 311     311 0 857 my ($self, $data) = @_;
41              
42 311 100       1207 $self->parent('Venus::Error') if !$self->parent;
43              
44 311         790 return $self;
45             }
46              
47             # METHODS
48              
49             sub as {
50 1     1 1 4 my ($self, $name) = @_;
51              
52 1         5 $self->name($name);
53              
54 1         14 return $self;
55             }
56              
57             sub assertion {
58 0     0 1 0 my ($self) = @_;
59              
60 0         0 my $assertion = $self->SUPER::assertion;
61              
62             $assertion->match('string')->format(sub{
63 0   0 0   0 (ref $self || $self)->new($_)
64 0         0 });
65              
66 0         0 return $assertion;
67             }
68              
69             sub capture {
70 11     11 0 32 my ($self, @args) = @_;
71              
72 11         35 my $frame = $self->frame;
73              
74 11   100     149 $self->stash(captured => {
75             callframe => [caller($frame // 1)],
76             arguments => [@args],
77             });
78              
79 11         51 return $self;
80             }
81              
82             sub error {
83 322     322 1 959 my ($self, $data) = @_;
84              
85 322         20043 require Venus::Error;
86              
87 322         1124 my $frame = $self->frame;
88 322         1267 my $name = $self->name;
89 322   66     1513 my $context = $self->context || (caller($frame // 1))[3];
90 322   66     1295 my $package = $self->package || join('::', map ucfirst, (caller(0))[0], 'error');
91 322         1039 my $parent = $self->parent;
92 322         1110 my $message = $self->message;
93              
94 322   100     1936 $data //= {};
95 322   66     1777 $data->{context} //= $context;
96 322 100 33     1788 $data->{message} //= $message if $message;
97 322 100 33     1728 $data->{name} //= $name if $name;
98              
99 322 100       567 if (%{$self->stash}) {
  322         1024  
100 272   33     1305 $data->{'$stash'} //= $self->stash;
101             }
102              
103 322         712 local $@;
104 28 100 100 28   308 if (!$package->can('new') and !eval "package $package; use base '$parent'; 1") {
  28         80  
  28         4003  
  322         6233  
105 1         10 my $throw = Venus::Throw->new(package => 'Venus::Throw::Error');
106 1         18 $throw->message($@);
107 1         4 $throw->stash(package => $package);
108 1         5 $throw->stash(parent => $parent);
109 1         18 $throw->error;
110             }
111 321 50       2411 if (!$parent->isa('Venus::Error')) {
112 0         0 my $throw = Venus::Throw->new(package => 'Venus::Throw::Error');
113 0         0 $throw->message(qq(Parent '$parent' doesn't derive from 'Venus::Error'));
114 0         0 $throw->stash(package => $package);
115 0         0 $throw->stash(parent => $parent);
116 0         0 $throw->error;
117             }
118 321 50       1642 if (!$package->isa('Venus::Error')) {
119 0         0 my $throw = Venus::Throw->new(package => 'Venus::Throw::Error');
120 0         0 $throw->message(qq(Package '$package' doesn't derive from 'Venus::Error'));
121 0         0 $throw->stash(package => $package);
122 0         0 $throw->stash(parent => $parent);
123 0         0 $throw->error;
124             }
125              
126 321 50       1804 @_ = ($package->new($data ? $data : ()));
127              
128 321         3564 goto $package->can('throw');
129             }
130              
131             sub on {
132 2     2 1 6 my ($self, $name) = @_;
133              
134 2         8 my $frame = $self->frame;
135              
136 2   50     20 my $routine = (split(/::/, (caller($frame // 1))[3]))[-1];
137              
138 2 100 66     14 undef $routine if $routine eq '__ANON__' || $routine eq '(eval)';
139              
140 2 50 66     20 $self->name(join('.', 'on', grep defined, $routine, $name)) if $routine || $name;
141              
142 2         19 return $self;
143             }
144              
145             1;
146              
147              
148              
149             =head1 NAME
150              
151             Venus::Throw - Throw Class
152              
153             =cut
154              
155             =head1 ABSTRACT
156              
157             Throw Class for Perl 5
158              
159             =cut
160              
161             =head1 SYNOPSIS
162              
163             package main;
164              
165             use Venus::Throw;
166              
167             my $throw = Venus::Throw->new;
168              
169             # $throw->error;
170              
171             =cut
172              
173             =head1 DESCRIPTION
174              
175             This package provides a mechanism for generating and raising errors (exception
176             objects).
177              
178             =cut
179              
180             =head1 ATTRIBUTES
181              
182             This package has the following attributes:
183              
184             =cut
185              
186             =head2 frame
187              
188             frame(Int)
189              
190             This attribute is read-write, accepts C<(Int)> values, and is optional.
191              
192             =cut
193              
194             =head2 name
195              
196             name(Str)
197              
198             This attribute is read-write, accepts C<(Str)> values, and is optional.
199              
200             =cut
201              
202             =head2 message
203              
204             message(Str)
205              
206             This attribute is read-write, accepts C<(Str)> values, and is optional.
207              
208             =cut
209              
210             =head2 package
211              
212             package(Str)
213              
214             This attribute is read-only, accepts C<(Str)> values, and is optional.
215              
216             =cut
217              
218             =head2 parent
219              
220             parent(Str)
221              
222             This attribute is read-only, accepts C<(Str)> values, is optional, and defaults to C<'Venus::Error'>.
223              
224             =cut
225              
226             =head2 context
227              
228             context(Str)
229              
230             This attribute is read-only, accepts C<(Str)> values, and is optional.
231              
232             =cut
233              
234             =head1 INHERITS
235              
236             This package inherits behaviors from:
237              
238             L
239              
240             =cut
241              
242             =head1 INTEGRATES
243              
244             This package integrates behaviors from:
245              
246             L
247              
248             =cut
249              
250             =head1 METHODS
251              
252             This package provides the following methods:
253              
254             =cut
255              
256             =head2 as
257              
258             as(string $name) (Venus::Throw)
259              
260             The as method sets a L for the error and returns the invocant.
261              
262             I>
263              
264             =over 4
265              
266             =item as example 1
267              
268             # given: synopsis
269              
270             package main;
271              
272             $throw = $throw->as('on.handler');
273              
274             # bless({...}, 'Venus::Throw')
275              
276             =back
277              
278             =cut
279              
280             =head2 error
281              
282             error(hashref $data) (Venus::Error)
283              
284             The error method throws the prepared error object.
285              
286             I>
287              
288             =over 4
289              
290             =item error example 1
291              
292             # given: synopsis;
293              
294             my $error = $throw->error;
295              
296             # bless({
297             # ...,
298             # "context" => "(eval)",
299             # "message" => "Exception!",
300             # }, "Main::Error")
301              
302             =back
303              
304             =over 4
305              
306             =item error example 2
307              
308             # given: synopsis;
309              
310             my $error = $throw->error({
311             message => 'Something failed!',
312             context => 'Test.error',
313             });
314              
315             # bless({
316             # ...,
317             # "context" => "Test.error",
318             # "message" => "Something failed!",
319             # }, "Main::Error")
320              
321             =back
322              
323             =over 4
324              
325             =item error example 3
326              
327             package main;
328              
329             use Venus::Throw;
330              
331             my $throw = Venus::Throw->new('Example::Error');
332              
333             my $error = $throw->error;
334              
335             # bless({
336             # ...,
337             # "context" => "(eval)",
338             # "message" => "Exception!",
339             # }, "Example::Error")
340              
341             =back
342              
343             =over 4
344              
345             =item error example 4
346              
347             package main;
348              
349             use Venus::Throw;
350              
351             my $throw = Venus::Throw->new(
352             package => 'Example::Error',
353             parent => 'Venus::Error',
354             );
355              
356             my $error = $throw->error({
357             message => 'Example error!',
358             });
359              
360             # bless({
361             # ...,
362             # "context" => "(eval)",
363             # "message" => "Example error!",
364             # }, "Example::Error")
365              
366             =back
367              
368             =over 4
369              
370             =item error example 5
371              
372             package Example::Error;
373              
374             use base 'Venus::Error';
375              
376             package main;
377              
378             use Venus::Throw;
379              
380             my $throw = Venus::Throw->new(
381             package => 'Example::Error::Unknown',
382             parent => 'Example::Error',
383             );
384              
385             my $error = $throw->error({
386             message => 'Example error (unknown)!',
387             });
388              
389             # bless({
390             # ...,
391             # "context" => "(eval)",
392             # "message" => "Example error (unknown)!",
393             # }, "Example::Error::Unknown")
394              
395             =back
396              
397             =over 4
398              
399             =item error example 6
400              
401             package main;
402              
403             use Venus::Throw;
404              
405             my $throw = Venus::Throw->new(
406             package => 'Example::Error::NoThing',
407             parent => 'No::Thing',
408             );
409              
410             my $error = $throw->error({
411             message => 'Example error (no thing)!',
412             });
413              
414             # No::Thing does not exist
415              
416             # Exception! Venus::Throw::Error (isa Venus::Error)
417              
418             =back
419              
420             =over 4
421              
422             =item error example 7
423              
424             # given: synopsis;
425              
426             my $error = $throw->error({
427             name => 'on.test.error',
428             context => 'Test.error',
429             message => 'Something failed!',
430             });
431              
432             # bless({
433             # ...,
434             # "context" => "Test.error",
435             # "message" => "Something failed!",
436             # "name" => "on_test_error",
437             # }, "Main::Error")
438              
439             =back
440              
441             =cut
442              
443             =head2 on
444              
445             on(string $name) (Venus::Throw)
446              
447             The on method sets a L for the error in the form of
448             C<"on.$subroutine.$name"> or C<"on.$name"> (if outside of a subroutine) and
449             returns the invocant.
450              
451             I>
452              
453             =over 4
454              
455             =item on example 1
456              
457             # given: synopsis
458              
459             package main;
460              
461             $throw = $throw->on('handler');
462              
463             # bless({...}, 'Venus::Throw')
464              
465             # $throw->name;
466              
467             # "on.handler"
468              
469             =back
470              
471             =over 4
472              
473             =item on example 2
474              
475             # given: synopsis
476              
477             package main;
478              
479             sub execute {
480             $throw->on('handler');
481             }
482              
483             $throw = execute();
484              
485             # bless({...}, 'Venus::Throw')
486              
487             # $throw->name;
488              
489             # "on.execute.handler"
490              
491             =back
492              
493             =cut
494              
495             =head1 OPERATORS
496              
497             This package overloads the following operators:
498              
499             =cut
500              
501             =over 4
502              
503             =item operation: C<("")>
504              
505             This package overloads the C<""> operator.
506              
507             B
508              
509             # given: synopsis;
510              
511             my $result = "$throw";
512              
513             # "Exception!"
514              
515             =back
516              
517             =over 4
518              
519             =item operation: C<(~~)>
520              
521             This package overloads the C<~~> operator.
522              
523             B
524              
525             # given: synopsis;
526              
527             my $result = $throw ~~ 'Exception!';
528              
529             # 1
530              
531             =back
532              
533             =head1 AUTHORS
534              
535             Awncorp, C
536              
537             =cut
538              
539             =head1 LICENSE
540              
541             Copyright (C) 2000, Awncorp, C.
542              
543             This program is free software, you can redistribute it and/or modify it under
544             the terms of the Apache license version 2.0.
545              
546             =cut