package RPC::ExtDirect::Hook; use strict; use warnings; no warnings 'uninitialized'; ## no critic use B; use Carp; use RPC::ExtDirect (); ### PUBLIC CLASS METHOD (CONSTRUCTOR) ### # # Instantiate new Hook object # sub new { my ($class, $type, $method_def) = @_; my $package = $method_def->{package}; my $method = $method_def->{method}; my ($before, $instead, $after) = map { RPC::ExtDirect->get_hook( type => $_, package => $package, method => $method, ) } qw/ before instead after/; my $self = bless {}, $class; @$self{ qw/type method_def before instead after/ } = ( $type, $method_def, $before, $instead, $after ); return $self->hook ? $self : undef } ### PUBLIC INSTANCE METHOD ### # # Run the hook # sub run { my ($self, $env, $arg, $result, $exception, $method_called) = @_; my %hook_arg = %{ $self->method_def }; $hook_arg{code} = delete $hook_arg{referent}; my @param_names = @{ $hook_arg{param_names} || [] }; $hook_arg{arg} = $arg; $hook_arg{env} = $env; # Result and exception are passed to "after" hook only @hook_arg{ qw/result exception method_called/ } = ($result, $exception, $method_called) if $self->type eq 'after'; @hook_arg{ qw/before instead after/ } = map { $self->$_ } qw/before instead after/; # A drop of sugar my $code = $hook_arg{code}; my $package = $hook_arg{package}; $hook_arg{orig} = sub { $code->($package, @$arg) }; my $hook = $self->hook; my $hook_pkg = _package_from_coderef($hook); # By convention, hooks are called as class methods return $hook->($hook_pkg, %hook_arg); } ### PUBLIC INSTANCE METHODS ### # # Read only getters # sub type { shift->{type} } sub before { shift->{before} } sub instead { shift->{instead} } sub after { shift->{after} } sub method_def { shift->{method_def} } sub hook { my ($self) = @_; my $type = $self->type; return $self->$type; } ############## PRIVATE METHODS BELOW ############## ### PRIVATE PACKAGE SUBROUTINE ### # # Return package name from coderef # sub _package_from_coderef { my ($code) = @_; my $pkg = eval { B::svref_2object($code)->GV->STASH->NAME }; return defined $pkg && $pkg ne '' ? $pkg : undef; } 1; __END__ =pod =head1 NAME RPC::ExtDirect::Hook - Implements Ext.Direct method hooks =head1 SYNOPSIS This module is not intended to be used directly. =head1 AUTHOR Alexander Tokarev Etokarev@cpan.orgE =head1 COPYRIGHT AND LICENSE Copyright (c) 2011-2012 Alexander Tokarev. This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. See L. =cut