Call::From - Call functions/methods with a fake caller()
use Call::From qw( call_method_from ); my $proxy = call_method_from('Fake::Namespace'); Some::Class->$proxy( method_name => @args ); # Some::Class->method_name( @args ) with caller() faked.
Call::From contains a collection of short utility functions to ease calling functions and methods from faked calling contexts without requiring arcane knowledge of Perl eval tricks.
The following functions and variables are exportable on request.
call_method_from
my $function = call_method_from( CONTEXT_SPEC ); $invocant->$function( method_name => @args );
Alternatively:
$invocant->${ \call_method_from( CONTEXT_SPEC ) }( method_name => @args );
call_function_from
my $function = call_function_from( CONTEXT_SPEC ); $function->( "Class::Name::function" , @args );
my $function = call_function_from( CONTEXT_SPEC ); $function->( Class::Name->can('function') , @args );
Or
call_function_from( CONTEXT_SPEC )->( "Class::Name::function", @args );
$_call_from
$invocant->$_call_from( CONTEXT_SPEC, method_name => @args );
Calling contexts can be specified in a number of ways.
In functions like import, you're most likely wanting to chain caller meta-data from whoever is calling import
import
So for instance:
package Bar; sub import { my $proxy = call_method_from(1); vars->$proxy( import => 'world'); } package Foo; Bar->import();
Would trick `vars` to seeing `Foo` as being the calling package, with the line of the Bar->import() call being the file and line of the apparent caller in vars::import
package
Bar->import()
file
line
vars::import
This syntax is essentially shorthand for
call_method_from([ caller(1) ])
Strings describing the name of the calling package allows you to conveniently call functions from arbitrary name-spaces for import reasons, while preserving the file and line context in Carp stack traces.
Carp
package Bar; sub import { vars->${\call_method_from('Quux')}( import => 'world'); } package Foo; Bar->import();
This example would call vars->import('world') from inside the Quux package, while file and line data would still indicate an origin inside Bar ( on the line that call_method_from was called on )
vars->import('world')
Quux
Bar
This syntax is essentially shorthand for:
call_method_from([ $package, __FILE__, __LINE__ ])
Array References in the form
[ $package, $file, $line ]
Can be passed as a CALLING CONTEXT. All fields are optional and will be supplemented with the contents of the calling context when missing.
CALLING CONTEXT
Subsequently:
call_method_from([]) == call_method_from() == call_method_from([__PACKAGE__, __FILE__, __LINE__]) call_method_from(['Package']) == call_method_from('Package') == call_method_from(['Package', __FILE__, __LINE__]) call_method_from(['Package','file']) == call_method_from(['Package','file', __LINE__])
The following modules are similar in some way to Call::From
Call::From
Import::Into
Import::Into is really inspiration that this module borrowed from. It contains the elegant trick of using eval to compile a kind of trampoline or thunk which contained the magical eval spice that allows this behavior to work.
eval
trampoline
thunk
As such, this module had a big help from the authors and maintainers of Import::Into in mimicking and generalizing its utility in contexts other than import
If Import::Into did not exist, you could use this module in its place:
require Module; Module->${\call_method_from( $Into_Package )}( import => @IMPORT_ARGS );
However, it does exist, and should you need such a functionality, it is recommended instead of this module.
Scope::Upper
This module is similar to Scope::Upper in that it can be used to "hide" who caller is from a calling context.
caller
However, Scope::Upper is more fancy, and uses Perl Guts in order to be able to actually hide the entire stack frame, regardless of how many frames up you look with caller($N_FRAME).
caller($N_FRAME)
Call::From is much simpler in that it can only add stack frames to the caller, and then, it adds redundant frames in performing its task.
This is sufficient for fooling something that only uses a simple caller() call, but is insufficient if you need to hide entire call chains. In fact, I personally see it as a feature that you can still see the true caller history in a full stack-trace, because the last place you want to be fooled is when you're debugging whether or not you've been fooled.
caller()
But its worth pointing out that at the time of this writing, changes are pending in Perl 5 to rework the entire stack system.
This change may break Scope::Upper in ways that might not be fixable.
In the event this happens, Call::From might be a suitable alternative if you only need to spoof a stack frame and don't care that the full stack is still there.
Kent Fredric <kentnl@cpan.org>
This software is copyright (c) 2016 by Kent Fredric <kentfredric@gmail.com>.
This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.
To install Call::From, copy and paste the appropriate command in to your terminal.
cpanm
cpanm Call::From
CPAN shell
perl -MCPAN -e shell install Call::From
For more information on module installation, please visit the detailed CPAN module installation guide.