The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Package::Watchdog - Forbid subs in one package from accessing subs in another package, directly or otherwise.

DESCRIPTION

A watchdog object will 'watch' several packages and subs in their namespaces. The watchdog has a list of packages and their subs that should be considered off-limits to the packages being watched. If their is a violation, ie a watched package sub accesses a forbidden package sub, the watchdog will react. A watchdog can react by dying, issuing a warning, or running a custom subroutine.

SYNOPSYS

First we set some example packages:

    {
        # This packages subs will be forbidden
        package My::Package;
        use strict;
        use warnings;
        sub a { 'a' };
        sub b { 'b' };
        sub c { 'c' };

        # The next packages will be watches for violations
        # Note, every one calls a sub in the forbidden package

        package My::WatchA;
        use strict;
        use warnings;
        sub a { My::Package::a() };
        sub b { My::Package::a() };
        sub c { My::Package::a() };
        # ignore for now.
        sub d { My::Package::d() };

        package My::WatchB;
        use strict;
        use warnings;
        sub a { My::Package::a() };
        sub b { My::Package::a() };
        sub c { My::Package::a() };
    }

Now we set up the watchdog:

    $wd = Package::Watchdog->new()
        # All subs in My::WatchA are included in the watch since none are specified
        ->watch( package => 'My::WatchA', name => 'watch a' )
        # Only sub a() in My::WatchB will be included in the watch
        ->watch( package => 'My::WatchB', subs => [ 'a' ], name => 'watch b')
        # A second watcher will be placed on My::WatchA sub a()
        ->watch( package => 'My::WatchA', subs => [ 'a' ], name => 'watch c')
        # All subs will be forbidden if none are listed.
        ->forbid( 'My::Package' );

The subs in My::Package are only forbidden to My::WatchA and My::WatchB, when called outside those packages My::Package susb still work normally.

The following will all die after a warning:

    My::WatchA::a();
    My::WatchA::b();
    My::WatchA::c();

The following still work:

    My::Package::a();
    My::Package::b();
    My::Package::c();

You can make the watchdog bark, but not bite. If you create the watchdog with 'warn' as a parameter then violations will generate warnings, but will not die.

    my $wd = Package::Watchdog->new( 'warn' );

You can also create a custom reaction to violations. Please see the custom reaction section for more information. The original sub will be run after the custom reaction unless the custom reaction dies.

    # Custom reaction
    my $wd = Package::Watchdog->new( sub { ... } );

You can also provide different reactions for each watch:

    $wd = Package::Watchdog->new()
        ->watch( package => 'My::WatchA', react => 'warn' )
        ->watch( package => 'My::WatchB', react => 'die' )
        ->watch( package => 'My::WatchC', react => sub { ... } );

The watchdog can be killed by calling the kill() method. Alternately it can fall out of scope and be destroyed. The following are all ways to kill the watchdog:

    $wd->kill();
    $wd = undef; #When no other references to the watchdog exist.


    {
        my $wd2 = Package::Watchdog->new();
        # $wd2 is in effect
    }
    # $wd2 is dead.

CUSTOM REACTIONS

Custom reactions are anonymous subs.

    my $react = sub {
        my %params = @_;
        ... do stuff ...
    };

The custom react sub will be passed the following:

    %params = (
        watch => Package::Watchdog::Tracker::Watch, # The watch that was triggered
        watched => Package::Watchdog::Sub::Watched, # The class that manages the watched sub that was called.
        watched_params => [ Params with which the watched sub was called ],
        forbidden => Package::Watchdog::Sub::Forbidden, # The class that manages the forbidden sub that was called.
        forbidden_params => [ Params with which the forbidden sub was called ],
    );

It is safe to die within your custom reaction. The forbidden sub will run normally unless the custom reaction dies.

NOTES AND CAVEATS

Inherited subs

When Package::Watchdog obtains a list of all subs in a package, inherited subs are not included.

ACCESSORS

The following accessors methods are automatically generated using Package::Watchdog::Util::build_accessors(). These are listed purely for documentation purposes. They are not for use by the user.

react()
watches()
forbids()
stack()

METHODS

Unless otherwise specified methods all return the watchdog object and are chainable.

new( $reaction )

Create a new watchdog object.

$reaction must be one of 'die', 'warn', or a coderef (sub { ... })

watch( package => $package, subs => [ ... ], react => $react, name => $name )

Start watching the specified subs in the specified package. If subs is omited or contains '*' then all package subs will be watched.

forbid( $package, $subs )

Forbid the specified subs in the specified package. The second argument should be an arrayref.

unwatch()

*Unimplemented.*

unforbid()

*Unimplemented.*

kill()

Will make the watchdog inefective, removes all watches and forbids.

AUTHORS

Chad Granum chad@opensourcery.com

COPYRIGHT

Copyright (C) 2009 OpenSourcery, LLC

Package-Watchdog is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.

Package-Watchdog is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

Package-Watchdog is packaged with a copy of the GNU General Public License. Please see docs/COPYING in this distribution.