Aspect

 view release on metacpan or  search on metacpan

lib/Aspect/Advice/Before.pm  view on Meta::CPAN

				type      => 'before',
				pointcut  => \$pointcut,
				original  => \$original,
				sub_name  => \$name,
				wantarray => \$wantarray,
				args      => \\\@_,
				exception => \$\@, ### Not used (yet)
			}, 'Aspect::Point';

			local \$_ = \$Aspect::POINT;
			goto &\$original unless $MATCH_RUN;

			# Run the advice code
			&\$code(\$_);

			# Shortcut if they set a return value
			if ( exists \$_->{return_value} ) {
				return \@{\$_->{return_value}} if \$wantarray;
				return \$_->{return_value};
			}

			# Proceed to the original function
			\@_ = \$_->args; ### Superfluous?
			goto &\$original;
		};
END_PERL
		$self->{installed}++;
	}

	# If this will run lexical we don't need a descoping hook
	return unless $lexical;

	# Return the lexical descoping hook.
	# This MUST be stored and run at DESTROY-time by the
	# parent object calling _install. This is less bullet-proof
	# than the DESTROY-time self-executing blessed coderef
	return sub { $out_of_scope = 1 };
}

# Check for pointcut usage not supported by the advice type
sub _validate {
	my $self     = shift;
	my $pointcut = $self->pointcut;

	# The method used by the Highest pointcut is incompatible
	# with the goto optimisation used by the before() advice.
	if ( $pointcut->match_contains('Aspect::Pointcut::Highest') ) {
		return 'The pointcut highest is not currently supported by before advice';
	}

	# Pointcuts using "throwing" are irrelevant in before advice
	if ( $pointcut->match_contains('Aspect::Pointcut::Throwing') ) {
		return 'The pointcut throwing is illegal when used by before advice';
	}

	# Pointcuts using "throwing" are irrelevant in before advice
	if ( $pointcut->match_contains('Aspect::Pointcut::Returning') ) {
		return 'The pointcut returning is illegal when used by before advice';
	}

	$self->SUPER::_validate(@_);
}

1;

__END__

=pod

=head1 NAME

Aspect::Advice::Before - Execute code before a function is called

=head1 SYNOPSIS

  use Aspect;
  
  before {
  
      # Trace all calls to your module
      print STDERR "Called my function " . $_->sub_name . "\n";
  
      # Shortcut calls to foo() to always be true
      if ( $_->short_name eq 'foo' ) {
          return $_->return_value(1);
      }
  
      # Add an extra flag to bar() but call as normal
      if ( $_->short_name eq 'bar' ) {
          $_->args( $_->args, 'flag' );
      }

  } call qr/^ MyModule::\w+ $/

=head1 DESCRIPTION

The C<before> advice type is used to execute advice code prior to entry
into a target function. It is implemented by B<Aspect::Advice::Before>.

As well as creating side effects that run before the main code, the
C<before> advice type is particularly useful for changing parameters or
shortcutting calls to functions entirely and replacing the value they
would normally return with a different value.

Please note that the C<highest> pointcut (L<Aspect::Pointcut::Highest>) is
incompatible with C<before>. Creating a C<before> advice with a pointcut
tree that contains a C<highest> pointcut will result in an exception.

If speed is important to your program then C<before> is particular
interesting as the C<before> implementation is the only one that can take
advantage of tail calls via Perl's C<goto> function, where the rest of the
advice types need the more costly L<Sub::Uplevel> to keep caller() returning
correctly.

=head1 AUTHORS

Adam Kennedy E<lt>adamk@cpan.orgE<gt>

=head1 COPYRIGHT AND LICENSE

Copyright 2010 - 2013 Adam Kennedy.



( run in 0.515 second using v1.01-cache-2.11-cpan-5a3173703d6 )