NAME
Tie::Assert - Enforces restrictions on variables' contents
VERSION
This document refers to version 0.11 of Tie::Assert, released October
6th 2004.
SYNOPSIS
# Tie a few scalars...
my $dna;
tie ($dna, 'Tie::Assert::Scalar',
sequenceCheck => Tie::Assert::CheckFactory->regex(qr/^[gatc]*$/i),
);
$dna = 'gattaca'; # Fine, it matches the regex.
$dna = 'wibble'; # Doesn't match regex, will cause an error.
my $percentage_score;
tie ($percentage_score, 'Tie::Assert::Scalar',
rangeCheck => Tie::Assert::CheckFactory->range(0 => 100),
);
$percentage_score = 23; # Fine, well within the range provided.
$percentage_score = 201; # An invalid percentage score, more errors.
my $positive_integer;
tie ($positive_integer, 'Tie::Assert::Scalar',
positiveCheck => Tie::Assert::CheckFactory->min(0),
integerCheck => Tie::Assert::CheckFactory->integer_ok(),
);
$positive_number = 23; # A valid positive number
$positive_number = -1; # Invalid, another error.
DESCRIPTION
Tie::Assert is designed to fill the niche when Perl developers need to
guarantee that a variable obeys certain rules at all times, times when
users of others languages would rely on assert() and type-checking.
This module is intended to be as flexible as possible, allowing the
developer to use it to do things as basic as ensuring a variable is
numeric and dying with an error message if not, up to ensuring a string
contains a valid and existing account number, and mailing a support
account if it's ever invalid.
Flexibility is the primary goal here, this module's useful for working
out where a program's setting it's variables to invalid values, to
providing a certain added level of security by ensuring variables cannot
be changed to out-of-range values.
Anywhere a value has to remain within a particular range this module
could potentially be useful.
BASIC USAGE
To use Tie::Assert in it's most common way you create a series of checks
with the methods of Tie::Assert::CheckFactory, and tie them do a
variable via the Tie::Assert::* family of modules.
For example, suppose we're going to ensure a variable is a positive
number, we can start by using the is_number() and min() functions of
CheckFactory to produce the following two checks:
my $number_check = Tie::Assert::CheckFactory->is_number();
my $positive_check = Tie::Assert::CheckFactory->min(0);
Now we can create our variable and tie it to these two checks, giving
them meaningful names in the control hash for tie(). The variable's a
scalar so we'll be using Tie::Assert::Scalar as the checker.
my $positive_number;
# We're tying $positive_number to a 'Tie::Assert::Scalar' checker..
tie ($positive_number, 'Tie::Assert::Scalar',
# .. call the number check is_number, this'll be displayed in
# the error if an assignment tries to set it to something
# not a number..
is_number => $number_check,
# .. similarly call the positive number check is_positive.
is_positive => $positive_number,
);
That's all there is to it. Now if we try and assign a value to the
$positive_number variable which isn't a positive number it'll draw our
attention to the problem by quitting the program with a nice meaningful
error message.
ADVANCED TOPICS
Obtaining the tied object
When Perl ties a variable it creates an object which methods are called
on behind the scenes, it's this object that other methods can be called
upon to change the way the Tie::Assert class affects it.
There's a keyword named tied() which returns the object behind a given
tied variable, so we can obtain the object behind $positive_number by:
my $positive_number_object = tied($positive_number);
If we want we can skip storing the tied object in a variable itself and
simply call methods directly on it, it's this format that'll be used
below.
Adding and removing checks on the fly
Sometimes it's convenient to be able to change the checks on a variable
at run time, and here's where you want to be able to add and remove
checks from the variable yourself rather than just relying on those
configured by the tie().
To add a check call add_check() on the tied object, providing it with a
check name and check as you did in the constructor.
tied($variable)->add_check(
oneToTen => Tie::Assert::CheckFactory->range(1=>10),
);
If there was already a check assigned to the variable with the given
name then it will be replaced by the new one.
To remove a check call remove_check() providing it with the check name
only.
tied($variable)->remove_check('oneToTen');
A final removal method remove_all_checks() will destroy all of the
checks on a given variable.
tied($variable)->remove_all_checks();
Obtaining information on the current checks
There's a couple of methods to query the filters assigned to a given
variable, the first is a simple count of the number of filters currently
attached to a variable:
print "Currently ",tied($variable)->count_filters," filters\n";
A complete list of filters can be obtained by calling the filter_names()
method:
for my $filter_name (tied($variable)->filter_names) {
print "Got filter $filter_name\n";
}
Changing the error handler
Often the developer doesn't want the entire program to die when it's
given an invalid value, they simply want it to log it, or even just
ignore the assignment. The Tie::Assert system handles this through the
set_error_handler() method that all tie'able classes in the system
support, to use it simply call set_error_handler() on the tied object
(See 'Obtaining the tied object' above) and pass it either a code
fragment, or a code reference to a function to handle the error. Either
way the function you provide should accept one parameter, the name of
the check.
So, if we had had a logging object with a log() method we may set the
error handler by calling:
tied($variable)->set_error_handler(
sub {$logger->log("Assert error, '".shift()."' check failed");
);
If we had a method to do the logging it's even easier.
tied($variable)->set_error_handler( \&log_assert_error );
...
sub log_assert_error {
my ($check_name) = @_;
$logger->log("Assert error, '".$check_name."' check failed");`
}
Providing your own custom checks
The CheckFactory provides functionality sufficient to cover the most
common uses, but sometimes there's need to be able to add your own
custom checks.
The secret here is that the CheckFactory itself simply returns a closure
which takes the value as it's sole parameter and returns a boolean
indicating whether it's allowed the value or not. To create your own
check it's just a case of providing your own closure or function pointer
with the same 'true for accept, false for error' behavior.
So, if I wanted to add a filter based on only allowing odd numbers..
tied($variable)->add_check(isOdd, sub { $_[0] % 2 });
Enabling and disabling the entire Test::Assert system
Sometimes in development there's a need to have stringent checking, but
when it hits live the error handler slows the process down too much.
The ideal solution to this is to replace the error handler with a
lighter version, thus keeping Tie::Assert's checks in the most vital
environment, but for times when this is not required it's possible to
disable the entire Tie::Assert framework with one single call.
Tie::Assert->disable;
... will turn off all assertions, allowing any values to be stored
again, and ...
Tie::Assert->enable;
... will again enable the assertions, with none of the configuration of
them lost during their disabled time.
Note that the global enabling and disabling of the Assert system will
not change the filters reported as being attached to a variable, they're
still attached there even when they're not active.
NOTE
This module is ALPHA code, it's seemed stable in a number of projects
but the interface is liable to change before the final release.
Developments expected in future versions include:
Adding Tie::Assert::Array
This should allow the use of assertions on both the index and value
of an array.
Adding Tie::Assert::Hash
This should allow the use of assertions on both the key and the
value of a hash.
Boolean Checks
Composite methods allowing you to combine multiple checks with AND
or OR logic, or reverse the result of a single test with a NOT.
PresentIn Checks
Basically an enumeration, restricts the value to those provided.
Length Checks
Restrictions based on the length of a string.
More comprehensive error messages
The error handlers should also receive the value which caused the
error, and the original value.
Hopefully a version with all of these changes should be released within
a week or so.
BUGS
No known bugs at present.
SEE ALSO
Tie::Aspect::CheckFactory, Tie::Aspect::Scalar
AUTHOR
Paul Golds (
[email protected])
COPYRIGHT
Copyright (c) 2004, Paul Golds. All Rights Reserved. This module is free
software. It may be used, redistributed, and/or modified under the same
terms as Perl itself.