File Coverage

blib/lib/Safe/Hole.pm
Criterion Covered Total %
statement 62 85 72.9
branch 20 38 52.6
condition 3 5 60.0
subroutine 10 13 76.9
pod 4 4 100.0
total 99 145 68.2


line stmt bran cond sub pod time code
1             # Safe::Hole - make a hole to the original main compartment in the Safe compartment
2             # Copyright 1999-2001, Sey Nakajima, All rights reserved.
3             # This program is free software under the GPL.
4             package Safe::Hole;
5              
6             require 5.005;
7 2     2   23275 use Carp;
  2         7  
  2         172  
8 2     2   11 use strict;
  2         3  
  2         72  
9 2     2   11 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK);
  2         6  
  2         365  
10              
11             require Exporter;
12             require DynaLoader;
13              
14             @ISA = qw(Exporter DynaLoader);
15             # Items to export into callers namespace by default. Note: do not export
16             # names by default without a very good reason. Use EXPORT_OK instead.
17             # Do not simply export all your public functions/methods/constants.
18             @EXPORT = qw(
19             );
20             $VERSION = '0.13';
21              
22             bootstrap Safe::Hole $VERSION;
23              
24             sub new {
25 4     4 1 4117 my($class, $args) = @_;
26 4         13 my $self = bless {}, $class;
27 4 100 100     24 $args = { ROOT => $args || 'main' } unless ref $args eq 'HASH';
28 4 100       10 if ( $args->{ROOT} ) {
29 2         5 $self->{PACKAGE} = $args->{ROOT};
30 2     2   11 no strict 'refs';
  2         3  
  2         808  
31 2         3 $self->{STASH} = \%{"$args->{ROOT}::"};
  2         8  
32             } else {
33 2         14 $self->{INC} = [ \%INC, \@INC ];
34 2         9 $self->{OPMASK} = _get_current_opmask();
35 2         4 $self->{PACKAGE} = 'main';
36 2         3 $self->{STASH} = \%main::;
37             }
38 4         12 $self;
39             }
40              
41             sub call {
42 11     11 1 9344 my $self = shift;
43 11         13 my $coderef = shift;
44 11         18 my @args = @_;
45            
46             # _hole_call_sv() does not seem to like being ripped off the stack
47             # so we need some fancy footwork to catch and re-throw the error
48              
49 11         11 my (@r,$did_not_die);
50 11         13 my $wantarray = wantarray;
51              
52 11 100       44 local(*INC), do {
53 9         10 *INC = $_ for @{$self->{INC}};
  9         36  
54             } if $self->{INC};
55              
56             # Safe::Hole::User contains nothing but is a placeholder so that
57             # things that are called via Safe::Hole can Carp::croak properly.
58              
59             package
60             Safe::Hole::User; # Package name on a different line to keep it from being indexed
61              
62             my $inner_call = sub {
63 11     11   16 eval {
64 11         19 @_ = @args;
65 11 100       23 if ( $wantarray ) {
66 1         3 @r = &$coderef;
67             } else {
68 10         22 @r = scalar &$coderef;
69             }
70 10         292 $did_not_die=1;
71             };
72 11         46 };
73              
74 11 100       19 Safe::Hole::_hole_call_sv($self->{STASH}, $ {$self->{OPMASK}||\undef}, $inner_call);
  11         94  
75              
76 11 100       36 die $@ unless $did_not_die;
77 10 100       79 return wantarray ? @r : $r[0];
78             }
79              
80             sub root {
81 0     0 1 0 my $self = shift;
82 0         0 $self->{PACKAGE};
83             }
84              
85             sub wrap {
86 6     6 1 7903 my($self, $ref, $cpt, $name) = @_;
87 6         9 my($result, $typechar, $word);
88 2     2   11 no strict 'refs';
  2         3  
  2         614  
89 6 50 33     33 if( $cpt && $name ) {
90 6 50       20 croak "Safe object required" unless ref($cpt) eq 'Safe';
91 6 50       51 if( $name =~ /^(\W)(\w+(::\w+)*)$/ ) {
92 6         20 ($typechar, $word) = ($1, $2);
93             } else {
94 0         0 croak "'$name' not a valid name";
95             }
96             }
97 6         9 my $type = ref $ref;
98 6 50       19 if( $type eq '' ) {
    50          
    0          
99 0         0 croak "reference required";
100 0         0 } elsif( $type eq 'CODE' ) {
101 6     0   25 $result = sub { $self->call($ref, @_); };
  0         0  
102 6 50       13 if( $typechar eq '&' ) {
    0          
103 6         6 *{$cpt->root()."::$word"} = $result;
  6         20  
104             } elsif( $typechar ) {
105 0         0 croak "'$name' type mismatch with $type";
106             }
107             } elsif( %{$type.'::'} ) {
108 0         0 my $wrapclass = ref($self).'::'.$self->root().'::'.$type;
109 0         0 *{$wrapclass.'::AUTOLOAD'} =
110             sub {
111             $self->call(
112             sub {
113 2     2   38 no strict;
  2         5  
  2         513  
114 0         0 my $self = shift;
115 0 0       0 return if $AUTOLOAD =~ /::DESTROY$/;
116 0         0 my $name = $AUTOLOAD;
117 0         0 $name =~ s/.*://;
118 0         0 $self->{OBJ}->$name(@_);
119 0     0   0 }, @_);
120 0 0       0 } unless defined &{$wrapclass.'::AUTOLOAD'};
  0         0  
121 0         0 $result = bless { OBJ => $ref }, $wrapclass;
122 0 0       0 if( $typechar eq '$' ) {
    0          
123 0         0 ${$cpt->varglob($word)} = $result;
  0         0  
124             } elsif( $typechar ) {
125 0         0 croak "'$name' type mismatch with object (must be scalar)";
126             }
127             } else {
128 0         0 croak "type '$type' is not supported";
129             }
130 6         71 $result;
131             }
132              
133             # Autoload methods go after =cut, and are processed by the autosplit program.
134              
135             1;
136             __END__