File Coverage

blib/lib/Fukurama/Class/HideCaller.pm
Criterion Covered Total %
statement 45 58 77.5
branch 18 36 50.0
condition 11 22 50.0
subroutine 10 11 90.9
pod 1 1 100.0
total 85 128 66.4


line stmt bran cond sub pod time code
1             package Fukurama::Class::HideCaller;
2 5     5   24718 use Fukurama::Class::Version(0.01);
  5         12  
  5         31  
3 5     5   59 use Fukurama::Class::Rigid;
  5         8  
  5         25  
4 5     5   31 use Fukurama::Class::Carp;
  5         11  
  5         45  
5              
6             my $IS_DECORATED = undef;
7             our $REGISTER = {};
8             our $DISABLE;
9             my $USAGE_ERROR;
10              
11             =head1 NAME
12              
13             Fukurama::Class::HideCaller - Pragma to hide wrapper-classes in callers stack
14              
15             =head1 VERSION
16              
17             Version 0.01 (beta)
18              
19             =head1 SYNOPSIS
20              
21             package MyWrapperClass;
22             use Fukurama::Class::HideCaller('MyWrapperClass');
23            
24             sub wrap_around_test {
25             my $sub = \&MyClass::test;
26             no warnings;
27             *MyClass::test = sub {
28             print "before, ";
29             &{$sub}(@_);
30             print "after";
31             }
32             }
33            
34             package MyClass;
35             sub test {
36             no warnings;
37             print "middle, caller: " . [caller(0)]->[0] . ", ";
38             }
39            
40             package main;
41             MyWrapperClass->wrap_around_test();
42             MyClass->test();
43             # will print: before, middle, caller: main, after
44             # without the HideCaller, it will print: before, middle, caller: MyWrapper, after
45              
46             =head1 DESCRIPTION
47              
48             This pragma-like module provides functions to hide a wrapper-class in callers stack. It's a helper class
49             to provide parameter and return value checking without changings in any caller stack.
50              
51             =head1 CONFIG
52              
53             You can disable the whole behavior of this class by setting
54              
55             $Fukurama::Class::HideCaller::DISABLE = 1;
56            
57             =head1 EXPORT
58              
59             =over 4
60              
61             =item CORE::GLOBAL::caller
62              
63             would be decorated
64              
65             =back
66              
67             =head1 METHODS
68              
69             =over 4
70              
71             =item register_class( hidden_wrapper_class:STRING ) return:VOID
72              
73             Register a wrapper class to competely hide in caller stack.
74              
75             =back
76              
77             =head1 AUTHOR, BUGS, SUPPORT, ACKNOWLEDGEMENTS, COPYRIGHT & LICENSE
78              
79             see perldoc of L
80              
81             =cut
82              
83             # AUTOMAGIC void
84             sub import {
85 5     5   3695 my $class = $_[0];
86 5         8 my $hidden_class = $_[1];
87            
88 5 50       22 if(!$IS_DECORATED) {
89 5         20 $class->_decorate_caller();
90 5         8 $IS_DECORATED = 1;
91             }
92 5 50       21 $class->register_class($hidden_class) if(defined($hidden_class));
93 5         450 return;
94             }
95             # void
96             sub register_class {
97 6     6 1 1344 my $class = $_[0];
98 6         13 my $hidden_class = $_[1];
99            
100 6 50 66     34 if(!$IS_DECORATED && !$USAGE_ERROR) {
101 1         2 $USAGE_ERROR = 1;
102 1         4 _croak("Wrong usage: you have to say\n\t'use " . __PACKAGE__ . ";' or\n\t'use " . __PACKAGE__ . "('CLASSNAME')'");
103             }
104 5 50       53 if(!UNIVERSAL::isa($hidden_class, $hidden_class)) {
105 0         0 _croak("Class '$hidden_class' is not a valid class");
106             }
107 5         18 $REGISTER->{$hidden_class} = 1;
108 5         17 return;
109             }
110             # AUTOMAGIC void
111             END {
112            
113 5 50 33 5   1926 if(!$DISABLE && !$IS_DECORATED && !$USAGE_ERROR) {
114 0         0 $USAGE_ERROR = 1;
115 0         0 _croak("Wrong usage: you have to say\n\t'use " . __PACKAGE__ . ";' or\n\t'use " . __PACKAGE__ . "('CLASSNAME')'");
116             }
117             }
118             # void
119             sub _decorate_caller {
120 5     5   9 my $class = $_[0];
121            
122 5     5   32 no strict 'refs';
  5         10  
  5         250  
123            
124 5         14 my $old = *CORE::GLOBAL::caller{'CODE'};
125 5 50       18 if($old) {
126            
127 5     5   28 no warnings 'redefine';
  5         7  
  5         1954  
128            
129             # inspired by Hook::LexWrap code
130             *CORE::GLOBAL::caller = sub {
131 0   0 0   0 my $level = $_[0] || 0;
132 0         0 my $i = 1;
133 0         0 my $called_sub = undef;
134 0         0 while(1) {
135 0 0       0 my @caller = &$old($i++) or return;
136 0 0       0 $caller[3] = $called_sub if($called_sub);
137 0 0 0     0 $called_sub = ((${__PACKAGE__ . '::REGISTER'}->{$caller[0]} && !${__PACKAGE__ . '::DISABLE'}) ? $caller[3] : undef);
138 0 0 0     0 next if($called_sub || $level-- != 0);
139 0 0       0 return (wantarray ? (@_ ? @caller : @caller[0..2]) : $caller[0]);
    0          
140             }
141 0         0 };
142             } else {
143             # inspired by Hook::LexWrap code
144             *CORE::GLOBAL::caller = sub {
145 543   100 543   63185 my $level = $_[0] || 0;
146 543         572 my $i = 1;
147 543         560 my $called_sub = undef;
148 543         577 while(1) {
149 2719 100       15216 my @caller = CORE::caller($i++) or return;
150 2689 100       5573 $caller[3] = $called_sub if($called_sub);
151 2689 100 100     2554 $called_sub = ((${__PACKAGE__ . '::REGISTER'}->{$caller[0]} && !${__PACKAGE__ . '::DISABLE'}) ? $caller[3] : undef);
152 2689 100 100     12492 next if($called_sub || $level-- != 0);
153 513 100       9305 return (wantarray ? (@_ ? @caller : @caller[0..2]) : $caller[0]);
    100          
154             }
155 5         40 };
156             }
157 5         13 return;
158             }
159             1;