File Coverage

blib/lib/Exodist/Util/Sub.pm
Criterion Covered Total %
statement 48 54 88.8
branch 6 8 75.0
condition 5 9 55.5
subroutine 12 15 80.0
pod 5 8 62.5
total 76 94 80.8


line stmt bran cond sub pod time code
1             package Exodist::Util::Sub;
2 3     3   32280 use strict;
  3         6  
  3         106  
3 3     3   14 use warnings;
  3         35  
  3         71  
4              
5 3     3   853 use Exporter::Declare::Magic;
  3         88057  
  3         22  
6 3     3   9993 use Exodist::Util::Package qw/inject_sub/;
  3         8  
  3         20  
7 3     3   655 use Carp qw/croak/;
  3         6  
  3         174  
8 3     3   18 use B;
  3         5  
  3         120  
9 3     3   2622 use Hash::FieldHash qw(fieldhash);
  3         2481  
  3         290  
10              
11             default_exports qw/
12             enhance_sub
13             /;
14              
15             fieldhash my %STASH;
16              
17             default_export( 'enhanced_sub', 'sublike' );
18             default_export( 'esub', 'sublike', \&enhanced_sub );
19              
20             sub bless_code {
21 6     6 0 7 my $class = shift;
22 6         21 my %proto = @_;
23              
24 6   33     18 my $code = delete $proto{sub} || croak "No code provided";
25 6         14 bless( $code, $class );
26 6         32 $STASH{$code} = \%proto;
27              
28 6         13 return;
29             }
30              
31             sub enhanced_sub {
32 3     3 0 787 my ( $name, $code ) = @_;
33 3         11 my ( $caller, $file, $line ) = caller;
34              
35 3 100       17 inject_sub( $caller, $name, $code )
36             if $name;
37              
38 3         14 __PACKAGE__->bless_code(
39             sub => $code,
40             end_line => $line,
41             );
42              
43 3         6 return $code;
44             }
45              
46             sub enhance_sub {
47 3     3 0 6 my ($in) = @_;
48 3         4 my $ref;
49 3 100 66     13 if ( ref $in and ref $in eq 'CODE' ) {
50 1         3 $ref = $in;
51             }
52             else {
53 2         9 $in =~ m/(.*::)?([^:]+)$/;
54 2         6 my ( $caller, $sub ) = ( $1, $2 );
55 2 100       9 $caller =~ s/::$// if $caller;
56 2   66     9 $caller ||= caller;
57 2         3 $ref = \&{"$caller\::$sub"};
  2         10  
58             }
59              
60 3         10 __PACKAGE__->bless_code( sub => $ref );
61              
62 3         5 return;
63             }
64              
65             sub start_line {
66 3     3 1 2475 my $self = shift;
67 3         50 return B::svref_2object($self)->START->line;
68             }
69              
70             sub end_line {
71 6     6 1 9 my $self = shift;
72 6         40 return $STASH{$self}->{end_line};
73             }
74              
75             sub original_name {
76 0     0 1   my $self = shift;
77 0           return B::svref_2object($self)->GV->NAME;
78             }
79              
80             sub is_anon {
81 0     0 1   my $self = shift;
82 0 0         return $self->original_name eq '__ANON__' ? 1 : 0;
83             }
84              
85             sub original_package {
86 0     0 1   my $self = shift;
87 0           return B::svref_2object($self)->GV->STASH->NAME;
88             }
89              
90             1;
91              
92             =head1 NAME
93              
94             Exodist::Util::Sub - Subroutines with advanced information attached.
95              
96             =head1 DESCRIPTION
97              
98             This package allows you to enhance subs such that they can be directly queried
99             for information. You can also directly create enhanced subs.
100              
101             =head1 SYNOPSYS
102              
103             package MyPackage;
104             use strict;
105             use warnings;
106             use Exodist::Util::Sub;
107              
108             esub print_hi {
109             print "hi\n";
110             }
111              
112             enhanced_sub print_bye {
113             print "bye\n";
114             }
115              
116             sub print_ps {
117             print "ps\n";
118             }
119             enhance_sub 'print_ps';
120              
121             sub print_pps {
122             print "pps\n"
123             }
124             enhance_sub \&print_pps;
125              
126             sub print_ppps {
127             print "ppps\n"
128             }
129             enhance_sub 'MyPackage::print_ppps';
130              
131             my $code = esub {
132             print "code\n"
133             }
134              
135             $code->(); # prints 'code'
136             print $code->start_line(); # prints the approximate line on which the sub
137             # definition started.
138             print $code->end_line(); # Same but the lane where the definition ended
139              
140             (\&print_hi)->start_line();
141             (\&print_hi)->original_name;
142             (\&print_hi)->original_package;
143             (\&print_hi)->is_anon;
144              
145             =head1 CREATING ENHANCED SUBS
146              
147             esub print_hi {
148             print "hi\n";
149             }
150              
151             enhanced_sub print_bye {
152             print "bye\n";
153             }
154              
155             =head1 ENHANCING EXISTING SUBS
156              
157             sub print_ps {
158             print "ps\n";
159             }
160             enhance_sub 'print_ps';
161              
162             =head1 METHODS ATTACHED TO ENHANCED SUBS
163              
164             =over 4
165              
166             =item (\&sub)->start_line()
167              
168             Get the starting line on which the sub was defined (from L)
169              
170             =item (\&sub)->end_line()
171              
172             Get the last line on which the sub was defined. (Only available for subs
173             created as enhanced.)
174              
175             =item (\&sub)->original_name()
176              
177             Returns the original name given to the sub. (Only available on subs enhanced
178             after the fact.)
179              
180             =item (\&sub)->is_anon()
181              
182             Returns true if the sub was declared as an anonymous sub.
183              
184             =item (\&sub)->original_package()
185              
186             Returns the name of the package in which the sub was defined.
187              
188             =back
189              
190             =head1 AUTHORS
191              
192             Chad Granum L
193              
194             =head1 COPYRIGHT
195              
196             Copyright (C) 2010 Chad Granum
197              
198             Exodist-Util is free software; Standard perl licence.
199              
200             Exodist-Util is distributed in the hope that it will be useful, but WITHOUT
201             ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
202             FOR A PARTICULAR PURPOSE. See the license for more details.