
=head1 NAME

Devel::Hook - Mess around with BEGIN/CHECK/INIT/END blocks

=head1 SYNOPSIS

  use Devel::Hook ();

  INIT {
    print "INIT #2\n";
  }

  BEGIN {
    Devel::Hook->push_INIT_hook( sub { print "INIT #3 (hook)\n" } );
    Devel::Hook->unshift_INIT_hook( sub { print "INIT #1 (hook)\n" } );
  }

  print "RUNTIME\n";

Output will be:

  INIT #1 (hook)
  INIT #2
  INIT #3 (hook)
  RUNTIME

=head1 DESCRIPTION

Perl keeps arrays of subroutines that are executed 
at the beginning and at the end of a running Perl program
and its program units. These subroutines correspond
to the special code blocks: C<BEGIN>, C<UNITCHECK>,
C<CHECK>, C<INIT> and C<END>. 
(See details at L<perlmod/"BEGIN, UNITCHECK, CHECK, INIT and END">.)
This module provides
limited capabilities to manipulate these arrays.

Such arrays belong to Perl's internals that you're
not supposed to see. Entries in these arrays get
consumed by the interpreter as it enters distinct
compilation phases, triggered by statements like
C<require>, C<use>, C<do>, C<eval>, etc. 
To play as safest as possible, the only allowed 
operations are to add entries to the start and to
the end of these arrays.

  # add code hooks to the start of <BLOCK> array
  Devel::Hook->unshift_<BLOCK>_hook( @blocks );

  # add code hooks to the end of <BLOCK> array
  Devel::Hook->push_<BLOCK>_hook( @blocks );

where E<lt>BLOCKE<gt> is one of: C<BEGIN>,
C<UNITCHECK>, C<CHECK>, C<INIT> or C<END>.

The hooks execute first if they are at the start
of the array and last if they are at the end.
Notice that the FIFO or LIFO nature of blocks
according to their textual order of appearance
at Perl source does not matter here.
For example, BEGIN and INIT are
FIFO (first-in, first-out) blocks while
CHECK, UNITCHECK and END are LIFO (last-in, first-out).
But the Perl interpreter and the user of this
module inserts blocks at the start of arrays
if they should execute earlier and at the end
if they are to be executed later,
with a homogeneous treatment with respect to
the block arrays.

If you are curious about the content of these arrays, 
read more at L<Manip::END/WARNING> and proceed
to L<the innards of Perl|perlhack>.

=head2 WHAT IS IT GOOD FOR

If you want to inject code into Perl compilation phases or
at the end of the program, this module may be useful.

If it can be done with literal C<BEGIN/UNITCHECK/CHECK/INIT/END>
blocks, it should be. For weirder things, maybe
C<Devel::Hook> can solve it.

As an example of application, L<Devel::Sub::Trace> uses this module
to insert a C<INIT> hook which will run just before any
other runtime code in the caller's package, wrapping
subs after they were compiled/generated but before
they get called by runtime code.

=head2 HOW TO USE IT

  (not yet finished)

With care. We are in the terrain of Perl internals we
are not supposed to mess with. And furthermore,
if you don't understand the implications of what
you are doing with this module, it is likely not
to do what you want.

  (to be finished)


=head1 METHODS

=over 4

=item * B< unshift_BEGIN_hook >

=item * B< push_BEGIN_hook >

  Devel::Hook->unshift_BEGIN_hook( @blocks );
  Devel::Hook->push_BEGIN_hook( @blocks );

This will add the blocks to the start (C<unshift_BEGIN_hook>)
and to the end (C<push_BEGIN_hook>) of the array of BEGIN
hooks.

C<@blocks> is an array of subroutine references. 


=item * B< unshift_UNITCHECK_hook >

=item * B< push_UNITCHECK_hook >

  Devel::Hook->unshift_UNITCHECK_hook( @blocks );
  Devel::Hook->push_UNITCHECK_hook( @blocks );

This will add the blocks to the start (C<unshift_UNITCHECK_hook>)
and to the end (C<push_UNITCHECK_hook>) of the array of UNITCHECK
hooks.

C<@blocks> is an array of subroutine references. 

The first stable release with C<UNITCHECK> was 5.10.0.
For earlier releases, these methods die.


=item * B< unshift_CHECK_hook >

=item * B< push_CHECK_hook >

  Devel::Hook->unshift_CHECK_hook( @blocks );
  Devel::Hook->push_CHECK_hook( @blocks );

This will add the blocks to the start (C<unshift_CHECK_hook>)
and to the end (C<push_CHECK_hook>) of the array of CHECK
hooks.

C<@blocks> is an array of subroutine references. 

=item * B< unshift_INIT_hook >

=item * B< push_INIT_hook >

  Devel::Hook->unshift_INIT_hook( @blocks );
  Devel::Hook->push_INIT_hook( @blocks );

This will add the blocks to the start (C<unshift_INIT_hook>)
and to the end (C<push_INIT_hook>) of the array of INIT
hooks.

C<@blocks> is an array of subroutine references. 

=item * B< unshift_END_hook >

=item * B< push_END_hook >

  Devel::Hook->unshift_END_hook( @blocks );
  Devel::Hook->push_END_hook( @blocks );

This will add the blocks to the start (C<unshift_END_hook>)
and to the end (C<push_END_hook>) of the array of END
hooks.

For END hooks, by adding to the start of the array (unshift), they will be
the first code blocks executed by Perl when it is exiting.

For END hooks, by adding to the end of the array (push), they will be
the last code blocks executed by Perl when it is exiting.

C<@blocks> is an array of subroutine references. 


=back


=head1 SEE ALSO

L<perlmod/"BEGIN, UNITCHECK, CHECK, INIT and END">

L<Manip::END>

L<B::CompilerPhase::Hook>


=head1 BUGS

Please report bugs via CPAN RT L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=Devel-Hook>
or L<mailto://bugs-Devel-Hook@rt.cpan.org>

=head1 TODO

=over 4

=item *

finish docs

=item *

finish tests

=item *

B<this module will be soon renamed into C<Devel::Hooks::BLOCK>>

=item *

test support for UNITCHECK blocks (needs Perl 5.10.0+)

=back


=head1 ACKNOWLEDGEMENTS

Everything I needed to learn about XS to write this
module was borrowed from L<Manip::END> written by Fergal Daly.
To be really honest, the code was all there
and I pruned it to a safer/limited/smaller API and included
the manipulation to other hooks besides END blocks.
And I also plagiarized his documentation.


=head1 AUTHOR

Fergal Daly (for the code in L<Manip::END>)

Adriano R. Ferreira, E<lt>ferreira@cpan.orgE<gt>


=head1 COPYRIGHT AND LICENSE

Copyright (C) 2008-2017 by Adriano R. Ferreira

This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself.


=cut
