package Venus::Role::Proxyable; use 5.018; use strict; use warnings; use Venus::Role 'with'; # METHODS sub AUTOLOAD { require Venus::Error; my ($package, $method) = our $AUTOLOAD =~ m[^(.+)::(.+)$]; my $build = $package->can('BUILDPROXY'); my $error = qq(Can't locate object method "$method" via package "$package"); Venus::Error->throw($error) unless $build && ref($build) eq 'CODE'; my $proxy = $build->($package, $method, @_); Venus::Error->throw($error) unless $proxy && ref($proxy) eq 'CODE'; goto &$proxy; } sub BUILDPROXY { require Venus::Error; my ($package, $method, $self, @args) = @_; my $build = $self->can('build_proxy'); return $build->($self, $package, $method, @args) if $build; my $error = qq(Can't locate object method "build_proxy" via package "$package"); Venus::Error->throw($error); } # EXPORTS sub EXPORT { ['AUTOLOAD', 'BUILDPROXY'] } 1; =head1 NAME Venus::Role::Proxyable - Proxyable Role =cut =head1 ABSTRACT Proxyable Role for Perl 5 =cut =head1 SYNOPSIS package Example; use Venus::Class; with 'Venus::Role::Proxyable'; attr 'test'; sub build_proxy { my ($self, $package, $method, @args) = @_; return sub { [$self, $package, $method, @args] } if $method eq 'anything'; return undef; } package main; my $example = Example->new(test => time); # $example->anything(1..4); =cut =head1 DESCRIPTION This package provides a hook into method dispatch resoluton via a wrapper around the C routine which processes calls to routines which don't exist. =cut =head1 METHODS This package provides the following methods: =cut =head2 build_proxy build_proxy(Str $package, Str $method, Any @args) (CodeRef | Undef) The build_proxy method should return a code reference to fulfill the method dispatching request, or undef to result in a method not found error. I> =over 4 =item build_proxy example 1 package main; my $example = Example->new(test => 123); my $build_proxy = $example->build_proxy('Example', 'everything', 1..4); # undef =back =over 4 =item build_proxy example 2 package main; my $example = Example->new(test => 123); my $build_proxy = $example->build_proxy('Example', 'anything', 1..4); # sub { ... } =back =cut