File Coverage

blib/lib/Object/Lexical.pm
Criterion Covered Total %
statement 94 107 87.8
branch 15 26 57.6
condition 12 21 57.1
subroutine 13 14 92.8
pod 0 2 0.0
total 134 170 78.8


line stmt bran cond sub pod time code
1             package Object::Lexical;
2              
3 1     1   31429 use 5.008;
  1         4  
  1         40  
4 1     1   5 use strict;
  1         4  
  1         33  
5 1     1   5 use warnings;
  1         5  
  1         47  
6              
7             our $VERSION = '0.02';
8              
9 1     1   644 use PadWalker;
  1         741  
  1         140  
10              
11             my $counter = 0;
12              
13             my $opt_wrap = 1;
14             my $opt_export = 1;
15             my $opt_nonlex = 1;
16              
17             my %methods = ();
18              
19             sub instance {
20              
21             # create a new object instance with its own stash from an existing object
22              
23 2   33 2 0 25 my $type = shift() || DB::_ext_fetch_args() || caller();
24              
25 2         14 my $package = sprintf 'Object::Lexical::X%09d', $counter++;
26              
27             # move methods into the new package from the symbol table. this is a destructive copy -
28             # methods will need to be created again. this way, each copy has its own
29             # seperate lexical data.
30              
31 1     1   6 no strict 'refs';
  1         2  
  1         560  
32              
33 2 50       6 if($opt_nonlex) {
34 2         2 foreach my $x (keys %{$type.'::'}) {
  2         9  
35             # no warnings 'redefine';
36 12 100 66     78 next if $x eq 'new' or $x eq 'DESTROY' or $x eq 'instance' or $x eq 'method';
      100        
      100        
37 6 100       5 next unless defined &{$type.'::'.$x};
  6         27  
38 2         4 my $source = $type.'::'.$x;
39 2         5 my $target = $package.'::'.$x;
40 2         3 my $code = \&{$source};
  2         4  
41 2         6 my $thisglob = $package.'::this';
42 2 50       6 if($opt_wrap) {
43 2     3   6 *{$target} = sub { *{$thisglob} = shift; goto &$code; };
  2         18  
  3         12  
  3         7  
  3         6  
44             } else {
45 0         0 *{$target} = $code;
  0         0  
46             }
47 2         2 undef *{$source};
  2         9  
48             }
49             }
50              
51             # move lexically defined subs, too
52              
53 2         585 my $pad = PadWalker::peek_my(1);
54 2         9 foreach my $x (keys %$pad) {
55 6         6 my $code = ${$pad->{$x}};
  6         10  
56 6 100       38 next unless ref($code) eq 'CODE';
57 4         8 substr($x, 0, 1, ''); # remove sigil
58 4         6 my $target = $package.'::'.$x;
59 4         6 my $thisglob = $package.'::this';
60 4 50       5 if($opt_wrap) {
61 4     11   19 *{$target} = sub { *{$thisglob} = shift; goto &$code; };
  4         18  
  11         1033  
  11         32  
  11         23  
62             } else {
63 0         0 *{$target} = $code;
  0         0  
64             }
65             }
66              
67             # and anything defined with method()
68              
69 2         5 foreach my $x (keys %methods) {
70 2         3 my $code = $methods{$x};
71 2         5 my $target = $package.'::'.$x;
72 2         2 my $thisglob = $package.'::this';
73 2 50       5 if($opt_wrap) {
74 2     1   5 *{$target} = sub { *{$thisglob} = shift; goto &$code; };
  2         20  
  1         4  
  1         3  
  1         3  
75             } else {
76 0         0 *{$target} = $code;
  0         0  
77             }
78             }
79              
80             # inherit whomever our client is inheriting.
81             # count references for destruction - barrowed from Class::Object
82              
83 2         2 push @{$package.'::ISA'}, $type;
  2         19  
84 2         3 ${$package.'::_count'} = 1;
  2         9  
85              
86 2         8 *{$package.'::DESTROY'} = sub {
87 0     0   0 my $obj_class = ref shift;
88 0         0 ${$obj_class.'::_count'}--;
  0         0  
89 0 0       0 if( ${$obj_class.'::_count'} == 0 ) {
  0         0  
90 0         0 undef %{$obj_class.'::'};
  0         0  
91             }
92 2         6 };
93            
94             # bless \(my $foo), $package;
95 2         3 bless \%{$package.'::'}, $package;
  2         11  
96              
97             }
98              
99             sub method (&*) {
100 2     2 0 55 my $caller = caller;
101 2         6 my $code = shift;
102 2         4 my $name = shift;
103 2         5 $methods{$name} = $code;
104             # *{$caller.'::'.$name} = $code;
105             }
106              
107             sub import {
108              
109             # cleaning up
110 2     2   3101 %methods = ();
111              
112             # default options
113 2         2 $opt_wrap = 1; # sub wrapper to read $this automatically
114 2         2 $opt_export = 1; # export instance() and method()
115 2         3 $opt_nonlex = 1; # move non-lexically defined methods too
116              
117             # options
118 2         4 foreach(@_) {
119 2 50 33     17 $opt_wrap = 0 if $_ eq 'no_wrap' or $_ eq 'nowrap';
120 2 50 33     8 $opt_export = 0 if $_ eq 'no_export' or $_ eq 'noexport';
121 2 50 33     13 $opt_nonlex = 0 if $_ eq 'no_nonlex' or $_ eq 'nononlex';
122             }
123              
124             # export
125 2 50       6 if($opt_export) {
126 1     1   5 no strict 'refs';
  1         1  
  1         132  
127 2         4 my $caller = caller;
128 2         3 *{$caller.'::instance'} = *instance;
  2         11  
129 2         3 *{$caller.'::method'} = *method;
  2         8  
130             }
131              
132 2         2003 1;
133              
134             }
135              
136             package DB;
137              
138             sub _ext_fetch_args {
139 2     2   3 our @args;
140 2         12 (undef, undef) = caller(2);
141 2 50       7 return undef unless @args;
142 2         9 return $args[0];
143             }
144              
145             1;
146              
147             __END__