File Coverage

blib/lib/Throw/Back.pm
Criterion Covered Total %
statement 10 21 47.6
branch 0 4 0.0
condition n/a
subroutine 4 5 80.0
pod n/a
total 14 30 46.6


line stmt bran cond sub pod time code
1             package Throw::Back;
2              
3 4     4   193248 use strict;
  4         11  
  4         155  
4 4     4   23 use warnings;
  4         7  
  4         1015  
5              
6             $Throw::Back::VERSION = '0.01';
7              
8             use overload fallback => 1, '""' => sub {
9 0     0   0 my ($exc) = @_;
10 0         0 my $call_stack = '';
11 0 0       0 if ( exists $exc->{call_stack} ) {
12 0         0 for my $frame ( @{ $exc->{call_stack} } ) {
  0         0  
13 0         0 my $func = $frame->[3];
14 0         0 $func =~ s/^$frame->[0]\:://;
15 0         0 $call_stack .= " : $func() (file: $frame->[1], line: $frame->[2])\n";
16             }
17             }
18              
19 0 0       0 return $exc->{string} =~ m/\n$/ ? "$exc->{string}$call_stack" : "$exc->{string} (file: $exc->{file}, line: $exc->{line})\n$call_stack";
20 4     4   25 };
  4         17  
  4         64  
21              
22 4     4   6001 use Module::Want 0.6 ();
  0            
  0            
23              
24             sub throw::back {
25             my ( $class, @args ) = @_;
26              
27             # hack for no args:
28             if ( ref($class) eq 'Throw::Back::_arg' ) {
29             push @args, $class;
30             $class = undef;
31             }
32              
33             my $_arg = ref( $args[-1] ) eq 'Throw::Back::_arg' ? pop(@args) : bless( {}, 'Throw::Back::_arg' );
34             my %obj = %{$_arg};
35             if ( ref $class eq 'Throw::Back::_arg' ) {
36             %obj = %{$class};
37             }
38              
39             my $cn = 0;
40             my $caller;
41             my @stack_trace;
42             while ( my @caller = caller($cn) ) {
43             $caller = \@caller;
44             unshift( @{ $obj{call_stack} }, $caller ) if exists $obj{call_stack};
45             $cn++;
46             }
47              
48             $obj{file} = $caller->[1];
49             $obj{line} = $caller->[2];
50              
51             $obj{'previous_exception'} = $@ if defined $@ && ( ref($@) || length($@) );
52             local $@;
53              
54             if ( defined $class ) {
55             if ( !ref($class) && Module::Want::is_ns($class) ) { # a one word message is pointless so don’t do that!
56             $obj{type} = $class;
57              
58             # TODO ? $class->can('throw') ?
59              
60             if ( Module::Want::have_mod($class) && $class->can('new') ) {
61             $obj{exception} = $class->new(@args);
62             $obj{string} ||= eval { $obj{exception}->to_string } || "$class Exception Thrown";
63             }
64             else {
65             $obj{string} ||= defined $args[0] && length $args[0] ? $args[0] : "$class Exception Thrown";
66             }
67             }
68             else {
69             if ( my $type = ref($class) ) {
70             $obj{type} = $type;
71             $obj{exception} = $class;
72             $obj{string} ||= defined $args[0] && length $args[0] ? $args[0] : "$type Exception Thrown";
73             }
74             else {
75             $obj{string} ||= $class;
76             }
77             }
78             }
79             else {
80             $obj{string} ||= defined $args[0] && length $args[0] ? $args[0] : "Exception Thrown";
81             }
82              
83             $obj{type} ||= __PACKAGE__;
84              
85             if ( defined wantarray ) {
86             return bless \%obj, __PACKAGE__;
87             }
88             else {
89             die bless \%obj, __PACKAGE__;
90             }
91             return;
92             }
93              
94             sub throw::stack {
95             push @_, bless( { 'call_stack' => [] }, 'Throw::Back::_arg' );
96             goto &throw::back;
97             }
98              
99             sub throw::text {
100             my ( $class, $phrase, @args ) = ref( $_[0] ) || Module::Want::is_ns( $_[0] ) ? @_ : ( undef, @_ ); # a one word message is pointless so don’t do that!
101             my $phrase_args = ref( $args[0] ) eq 'ARRAY' ? shift @args : [];
102              
103             my $_arg = ref( $args[-1] ) eq 'Throw::Back::_arg' ? pop(@args) : bless( {}, 'Throw::Back::_arg' );
104              
105             if ( defined $class ) {
106             my $lh = $class->can('locale') ? $class->locale : $class; # lazy façade baby, lazy façade!
107             if ( $lh->can('makevar') && $lh->can('makethis_base') ) {
108             $_arg->{string} = $lh->makevar( $phrase, @{$phrase_args} ); # parser knows throw::text() so makevar is good
109             $_arg->{string_not_localized} = $lh->makethis_base( $phrase, @{$phrase_args} );
110             }
111             elsif ( $class->can('maketext') ) { ## no extract maketext
112             $_arg->{string} = $class->maketext( $phrase, @{$phrase_args} ); ## no extract maketext (i.e. no makevar)
113             }
114             }
115              
116             if ( !exists $_arg->{string} ) {
117             $_arg->{phrase} = $phrase;
118             $_arg->{phrase_args} = $phrase_args;
119             }
120              
121             @_ = ( $class, @args, $_arg );
122             goto &throw::back;
123             }
124              
125             sub throw::stack::text {
126             push @_, bless( { 'call_stack' => [] }, 'Throw::Back::_arg' );
127             goto &throw::text;
128             }
129              
130             # TODO ? v0.02 ?:
131             # sub rethrow {
132             # my ($self) = @_;
133             # my $caller = [caller(0)];
134             #
135             # $self->{file} = $caller->[1];
136             # $self->{line} = $caller->[2];
137             # $self->{call_stack} = __get_stack() if $self->{call_stack};
138             #
139             # goto &__std_lazy_throw;
140             # }
141             #
142             # sub PROPAGATE { # see perldoc -f die
143             # my ($self, $file, $line) = @_;
144             # $self->{file} = $file;
145             # $self->{line} = $line;
146             # return $self;
147             # }
148              
149             1;
150              
151             __END__