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.
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.