File Coverage

blib/lib/Autoload/AUTOCAN.pm
Criterion Covered Total %
statement 39 42 92.8
branch 16 22 72.7
condition 2 3 66.6
subroutine 7 8 87.5
pod n/a
total 64 75 85.3


line stmt bran cond sub pod time code
1             package Autoload::AUTOCAN;
2              
3 2     2   2573 use strict;
  2         2  
  2         43  
4 2     2   6 use warnings;
  2         37  
  2         39  
5 2     2   6 use Carp ();
  2         2  
  2         21  
6 2     2   5 use Scalar::Util ();
  2         2  
  2         354  
7              
8             our $VERSION = '0.003';
9              
10             my $autoload_methods = <<'EOF';
11             sub AUTOLOAD {
12             my ($inv) = @_;
13             my ($package, $method) = our $AUTOLOAD =~ /^(.+)::(.+)$/;
14             Carp::croak qq[Undefined subroutine &${package}::$method called]
15             unless defined $inv && (!ref $inv or Scalar::Util::blessed $inv) && $inv->isa(__PACKAGE__);
16             my $autocan = $inv->can('AUTOCAN');
17             my $sub = defined $autocan ? $inv->$autocan($method) : undef;
18             Carp::croak qq[Can't locate object method "$method" via package "$package"]
19             unless defined $sub and do { local $@; eval { $sub = \&$sub } };
20             # allow overloads and blessed subrefs; assign ref so overload is only invoked once
21             goto &$sub;
22             }
23             EOF
24              
25             my $autoload_functions = <<'EOF';
26             sub AUTOLOAD {
27             my ($package, $function) = our $AUTOLOAD =~ /^(.+)::(.+)$/;
28             my $autocan = __PACKAGE__->can('AUTOCAN');
29             my $sub = defined $autocan ? __PACKAGE__->$autocan($function) : undef;
30             Carp::croak qq[Undefined subroutine &${package}::$function called]
31             unless defined $sub and do { local $@; eval { $sub = \&$sub } };
32             # allow overloads and blessed subrefs; assign ref so overload is only invoked once
33             goto &$sub;
34             }
35             EOF
36              
37             my $install_can = <<'EOF';
38             sub can {
39             my ($package, $function) = @_;
40             my $sub = $package->SUPER::can($function);
41             return $sub if defined $sub;
42             return undef if $function eq 'AUTOCAN'; # don't recurse on AUTOCAN
43             my $autocan = $package->can('AUTOCAN');
44             return defined $autocan ? scalar $package->$autocan($function) : undef;
45             }
46             EOF
47              
48             sub import {
49 2     2   11 my ($class, $style) = @_;
50 2 100       6 $style = 'methods' unless defined $style;
51            
52 2         4 my $target = caller;
53 2         2 my $autoload_code;
54 2 100       7 if ($style eq 'methods') {
    50          
55 1         1 $autoload_code = $autoload_methods;
56 1 50       12 $autoload_code .= 'sub DESTROY {}' unless $target->can('DESTROY');
57             } elsif ($style eq 'functions') {
58 1         1 $autoload_code = $autoload_functions;
59             } else {
60 0         0 Carp::croak "Invalid autoload style '$style' (expected 'functions' or 'methods')";
61             }
62            
63 2         3 my ($errored, $error);
64             {
65 2         2 local $@;
  2         3  
66 2 50 66 7   419 unless (eval "package $target;\n$install_can\n$autoload_code\n1") {
  7 100   19   2435  
  7 100   0   32  
  7 100       69  
  7 50       218  
  6 50       15  
  6         357  
  4         7  
  4         6  
  22         409  
  22         90  
  19         41  
  5         14  
  5         10  
  5         24  
67 0         0 $errored = 1;
68 0         0 $error = $@;
69             }
70             }
71            
72 2 50       262 die $error if $errored;
73             }
74              
75             1;
76              
77             =head1 NAME
78              
79             Autoload::AUTOCAN - Easily set up autoloading
80              
81             =head1 SYNOPSIS
82              
83             package My::Class;
84             use Moo; # or object system of choice
85             use Autoload::AUTOCAN;
86            
87             has count => (is => 'rw', default => 0);
88            
89             sub increment { $_[0]->count($_[0]->count + 1) }
90            
91             sub AUTOCAN {
92             my ($self, $method) = @_;
93             return sub { $_[0]->increment } if $method =~ m/inc/;
94             return undef;
95             }
96            
97             1;
98            
99             # elsewhere
100             my $obj = My::Class->new;
101             $obj->inc;
102             say $obj->count; # 1
103             $obj->increment; # existing method, not autoloaded
104             say $obj->count; # 2
105             $obj->do_increment;
106             say $obj->count; # 3
107             $obj->explode; # method not found error
108              
109             =head1 DESCRIPTION
110              
111             L is a very powerful mechanism for
112             dynamically handling function calls that are not defined. However, its
113             implementation is very complicated. For the simple case where you wish to
114             allow method calls to methods that don't yet exist, this module allows you to
115             define an C method which will return either a code reference or
116             C.
117              
118             L installs an C subroutine in the current package,
119             which is invoked when an unknown method is called. The installed C
120             will call C with the invocant (class or object the method was called
121             on) and the method name. If C returns a code reference, it will be
122             called with the same arguments as passed to the unknown method (including the
123             invocant). If C returns C, an error will be thrown as expected
124             when calling an undefined method.
125              
126             Along with C, the module installs a C method which returns code
127             references as normal for defined methods (see L), and delegates to
128             C for unknown methods.
129              
130             C affects standard function calls in addition to method calls. By
131             default, the C provided by this module will die (as Perl normally
132             does without a defined C) if a nonexistent function is called without
133             a class or object invocant. If you wish to autoload functions instead of
134             methods, you can pass C as an import argument, and the installed
135             C will autoload functions using C from the current package,
136             rather than using the first argument as an invocant.
137              
138             package My::Functions;
139             use Autoload::AUTOCAN 'functions';
140            
141             sub AUTOCAN {
142             my ($package, $function) = @_;
143             return sub { $_[0]x5 } if $function =~ m/dup/;
144             return undef;
145             }
146            
147             # elsewhere
148             say My::Functions::duplicate('foo'); # foofoofoofoofoo
149             say My::Functions::foo('bar'); # undefined subroutine error
150              
151             =head1 BUGS
152              
153             Report any issues on the public bugtracker.
154              
155             =head1 AUTHOR
156              
157             Dan Book
158              
159             =head1 COPYRIGHT AND LICENSE
160              
161             This software is Copyright (c) 2017 by Dan Book.
162              
163             This is free software, licensed under:
164              
165             The Artistic License 2.0 (GPL Compatible)
166              
167             =head1 SEE ALSO
168              
169             L, L