File Coverage

blib/lib/MRO/Magic.pm
Criterion Covered Total %
statement 82 83 98.8
branch 18 20 90.0
condition 4 5 80.0
subroutine 17 18 94.4
pod n/a
total 121 126 96.0


line stmt bran cond sub pod time code
1             package MRO::Magic;
2             {
3             $MRO::Magic::VERSION = '0.100001';
4             }
5 6     6   93481 use 5.010; # uvar magic does not work prior to version 10
  6         23  
  6         311  
6 6     6   31 use strict;
  6         12  
  6         186  
7 6     6   30 use warnings;
  6         10  
  6         179  
8             # ABSTRACT: write your own method dispatcher
9              
10 6     6   4980 use mro;
  6         4327  
  6         35  
11 6     6   4442 use MRO::Define;
  6         3562  
  6         218  
12 6     6   34 use Scalar::Util qw(reftype);
  6         14  
  6         666  
13 6     6   4838 use Variable::Magic qw/wizard cast/;
  6         7729  
  6         1159  
14              
15              
16             sub import {
17 8     8   2273 my $self = shift;
18 8         12 my $arg;
19              
20 8 100 66     75 if (@_ == 1 and reftype $_[0] eq 'CODE') {
21 2         6 $arg = { metamethod => $_[0] };
22             } else {
23 6         23 $arg = { @_ };
24             }
25              
26 8         23 my $caller = caller;
27 8         14 my %to_install;
28              
29 8         18 my $code = $arg->{metamethod};
30 8   100     46 my $metamethod = $arg->{metamethod_name} || '__metamethod__';
31              
32 8 100       60 if (reftype $code eq 'SCALAR') {
33 4 100       57 Carp::confess("can't find metamethod via name ${ $arg->{metamethod} }")
  1         195  
34             unless $code = $caller->can($$code);
35             }
36              
37 6 100   6   35 if (do { no strict 'refs'; defined *{"$caller\::$metamethod"}{CODE} }) {
  6         10  
  6         906  
  7         14  
  7         12  
  7         61  
38 1         234 Carp::confess("can't install metamethod as $metamethod; already defined");
39             }
40              
41 6         10 my $method_name;
42              
43             my $wiz = wizard
44             copy_key => 1,
45 6     6   231 data => sub { \$method_name },
46 6         51 fetch => $self->_gen_fetch_magic({
47             metamethod => $metamethod,
48             passthru => $arg->{passthru},
49             });
50              
51             $to_install{ $metamethod } = sub {
52 97     97   121 my $invocant = shift;
53 97         305 $code->($invocant, $method_name, \@_);
54 6         249 };
55              
56 6     6   33 no strict 'refs';
  6         10  
  6         2491  
57 6         22 for my $key (keys %to_install) {
58 6         11 *{"$caller\::$key"} = $to_install{ $key };
  6         32  
59             }
60              
61 6 100       24 if ($arg->{overload}) {
62 1         2 my %copy = %{ $arg->{overload} };
  1         5  
63 1         2 for my $ol (keys %copy) {
64 2 100       6 next if $ol eq 'fallback';
65 1 50       4 next if ref $copy{ $ol };
66            
67 1         1 my $name = $copy{ $ol };
68             $copy{ $ol } = sub {
69 0     0   0 $_[0]->$name(@_[ 1 .. $#_ ]);
70 1         4 };
71             }
72              
73             # We need string eval to set the caller to a variable. -- rjbs, 2009-03-26
74             # We must do this before casting magic so that overload.pm can find the
75             # right entries in the stash to muck with. -- rjbs, 2009-03-26
76 1 50   1   101 die unless eval qq{
  1         7  
  1         2  
  1         14  
77             package $caller;
78             use overload %copy;
79             1;
80             };
81             }
82              
83             MRO::Define::register_mro($caller, sub {
84 88     88   35899 return [ undef, $caller ];
85 6         53 });
86              
87 6         27 cast %{"::$caller\::"}, $wiz;
  6         74  
88             }
89              
90             sub _gen_fetch_magic {
91 6     6   59 my ($self, $arg) = @_;
92              
93 6         9 my $metamethod = $arg->{metamethod};
94 6         10 my $passthru = $arg->{passthru};
95              
96 6     6   6058 use Data::Dumper;
  6         51970  
  6         1914  
97             return sub {
98 138 100   138   166700 return if $_[2] ~~ $passthru;
99              
100 129 100       459 return if substr($_[2], 0, 1) eq '(';
101              
102 116         136 ${ $_[1] } = $_[2];
  116         207  
103 116         165 $_[2] = $metamethod;
104 116         308 mro::method_changed_in('UNIVERSAL');
105              
106 116         171689 return;
107 6         48 };
108             }
109              
110             1;
111              
112             __END__