File Coverage

blib/lib/Sub/Context.pm
Criterion Covered Total %
statement 70 70 100.0
branch 18 18 100.0
condition 3 3 100.0
subroutine 16 16 100.0
pod n/a
total 107 107 100.0


line stmt bran cond sub pod time code
1             package Sub::Context;
2              
3 2     2   1818 use strict;
  2         5  
  2         110  
4 2     2   12 use Scalar::Util 'reftype';
  2         5  
  2         205  
5              
6 2     2   12 use vars '$VERSION';
  2         5  
  2         1542  
7             $VERSION = '1.00';
8              
9             sub import
10             {
11 6     6   3035 my ($class, %args) = @_;
12 6         23 my $pkg = caller();
13              
14 6         186 while (my ($subname, $args) = each %args)
15             {
16 4         16 my $sub = $class->_qualify_sub( $pkg, $subname );
17 4         12 $class->_wrap_sub( $sub, $args );
18             }
19             }
20              
21             sub _qualify_sub
22             {
23 7     7   954 my ($class, $package, $subname) = @_;
24              
25 7 100       37 return $subname if index( $subname, '::' ) > 0;
26 5         19 return $package . '::' . $subname;
27             }
28              
29             sub _wrap_sub
30             {
31 4     4   7 my ($class, $subname, $contexts) = @_;
32              
33             # may croak()
34 4         13 $class->_validate_contexts( $contexts );
35 3         10 $class->_generate_contexts( $subname, $contexts );
36              
37 3         9 my $glob = $class->_fetch_glob( $subname );
38 3         9 $class->_apply_contexts( $glob, $contexts );
39             }
40              
41             sub _generate_contexts
42             {
43 7     7   4116 my ($class, $subname, $contexts) = @_;
44              
45 7         19 for my $context ( $class->_contexts() )
46             {
47 21 100 100     120 next if ref $contexts->{$context}
48             && reftype( $contexts->{$context} ) eq 'CODE';
49              
50 14 100       46 my $message = exists $contexts->{$context} ?
51             ': ' . delete $contexts->{$context} :
52             '';
53              
54 14         38 $contexts->{$context} = $class->_default_sub(
55             $subname, $context, $message
56             );
57             }
58             }
59              
60             sub _default_sub
61             {
62 16     16   1285 my ($class, $subname, $context, $message) = @_;
63              
64             # don't look at this
65 16         21 my $sub = \&{ $subname };
  16         63  
66 16 100       105 return $sub if defined &$sub;
67              
68             return sub
69             {
70 7     7   2139 require Carp;
71 7         108 Carp::croak( "No sub for $context context$message")
72 6         61 };
73             }
74              
75             sub _apply_contexts
76             {
77 4     4   2300 my ($class, $glob, $contexts) = @_;
78              
79             *$glob = sub
80             {
81 12     12   9011 my $context = wantarray();
82 12 100       45 $context = defined $context ?
    100          
83             ( $context ? 'list' : 'scalar' ) :
84             'void';
85 12         18 goto &{ $contexts->{$context} };
  12         50  
86 4         34 };
87             }
88              
89             sub _contexts
90             {
91 14     14   1003 qw( void scalar list );
92             }
93              
94             sub _validate_contexts
95             {
96 6     6   74 my ($class, $contexts) = @_;
97 6         20 my %allowed = map { $_ => 1 } $class->_contexts();
  18         45  
98              
99 6         23 for my $provided ( keys %$contexts )
100             {
101 10 100       41 unless ( exists $allowed{$provided} )
102             {
103 2         16 require Carp;
104 2         43 Carp::croak( "Context type '$provided' not allowed!" );
105             }
106             }
107             }
108              
109             sub _fetch_glob
110             {
111 5     5   1774 my ($class, $globname) = @_;
112 5         27 my $glob = $class->_find_glob( $globname );
113              
114 5 100       25 return $glob unless defined &$globname;
115              
116 2         6 local *NEWGLOB;
117              
118 2     2   13 no strict 'refs';
  2         5  
  2         377  
119              
120 2         15 for my $slot (qw ( SCALAR ARRAY FORMAT IO HASH ))
121             {
122 10 100       12 *NEWGLOB = *{$glob}{$slot} if defined *{$glob}{$slot};
  5         13  
  10         49  
123             }
124              
125 2         5 *{$glob} = *NEWGLOB;
  2         8  
126 2         6 return $glob;
127             }
128              
129             sub _find_glob
130             {
131 7     7   12 my ($class, $name) = @_;
132 7         12 my $glob = \%main::;
133 7         26 my @package = split( '::', $name );
134 7         15 my $subroutine = pop @package;
135              
136 7         11 for my $package ( @package )
137             {
138 9         36 $glob = $glob->{$package . '::'};
139             }
140              
141 7         20 $glob = \$glob->{$subroutine};
142 7         24 return $glob;
143             }
144              
145             'your message here, contact $AUTHOR for rates';
146              
147             __END__