NAME
Data::Verify - versatile data/type verification, validation and testing
SYNOPSIS
use Data::Verify qw(assess verify);
{
package Data::Verify::Type;
our $digit_not_0 = Data::Verify::Type->new(
desc => 'a number or digit, but not 0',
extends => [qw(limited)],
pass => { match => qr/[\d]+/ },
fail => { match => qr/^0+$/ }
);
our $german_zip = Data::Verify::Type->new(
desc => 'a german zip code',
extends => [qw(number)],
pass => { less => 7 },
fail => { less => 4 }
);
}
verify( label => 'my personal digit', value => '12', type => 'digit_not_0' );
verify( label => 'an foreign zip', value => '999-233', type => 'german_zip' );
$bouncer->inspect( $user );
DESCRIPTION
A sceptic programmer never trusts anybodys input (web forms, config files, etc.). He verifys if the data is in the right format. With this module he can do it in a very elegant and efficient way. Using object oriented techniques, you can create a hierarchy of tests for verifying almost everything.
The verification procedure is like a simple program. The building blocks are called tests (While this has little to do with modules like Test::Simple, the term 'test' is used because it behaves like it ). Multiple tests result into a 'test program'. While some tests may be expected to fail, and some to pass to result into a valid verification. I call every data which passes the complete program as expected belonging to a 'data type' (So i use this term instead of 'test program').
Here an example in pseudo-code for two data-types:
DATA_TYPE_B
{
PASS
{
TEST_1
TEST_2
}
}
DATA_TYPE_A (extends DATA_TYPE_B)
{
PASS
{
TEST_5
TEST_6
}
FAIL
{
TEST_1
TEST_2
TEST_3
TEST_4
}
}
This means: Data is (belonging to) 'DATA_TYPE_A' when it is passing test 5 and 6 with success, and is failing tests 1,2,3 and 4. It also EXTENDS 'DATA_TYPE_B', that means that "DATA_TYPE_A" inherits all "DATA_TYPE A" PASS+FAIL tests.
TESTS
Tests are simply subroutines in the Data::Verify::Test package. Per definition a test receives: 1) the test value 2) the test arguments. Then it simply returns true or false.
Here a very simple example:
sub my_test { $_[0] > $_[1] } # my_test( 12300, 100 ) would test if 12300 is bigger than 100
PREDEFINED TESTS
Following tests are always instantly available.
range - takes two arguments where the value has to be inbetween (ie. range => [1,800] )
lines - counts the lines (\n) (ie. lines => 5 )
less - lesser than the length in characters (ie. less => 3)
match - takes a regex to match (ie. match => qr/^0+$/ )
is - exact string comparision (ie. is => 'follow' )
bool - transformation of the value into bool (ie. bool => undef)
NULL - exact string match 'NULL' (ie. NULL => 1)
exists_in - checks whether the <var> is in a list. if list is an
Array: look if exact string is a member
Hash: look if the <var> key exists
Example:
pass => { exists_in => { firstname => 1, lastname => 1, email => 1 } },
fail => { exists_in => [qw(blabla)] }
DATA TYPES
A data can be simply instanciated by creation of a new Data::Verify::Type object.
Example (how to create a new data type):
package Data::Verify::Type;
our $number_notnull = new Data::Verify::Type(
desc => 'a number or digit, but not 0',
extends => [qw(number)],
fail => { match => qr/^0+$/ }
);
Normally we should have added 'pass => { match => qr/\d+/ },', but we dont explicitly need to add it
because we inherit that from 'number'. Note: A regex-guru would have written simply a better regex which
would had done it with just one match, but this example is for education purposes.
PREDEFINED DATA TYPES
Following types are always instantly available.
true - a boolean true value
false - a boolean false value
not_null - not the string "NULL"
null - must be the string "NULL"
limited - a word longer than 1 character
text - a standard length text ( 1-800 characters )
word - a word ( match => qr/[a-zA-Z\-]+[0-9]*/ } )
name - a first- or lastnames
login - a login- or nickname
email - an email address
number - a number or digit
number_notnull - a number or digit, but not 0
zip_ger - a german zip code
phone_ger - a german phone number
creditcard - a credit-card number (not implemented yet)
FUNCTIONS
verify( $teststring, $data_type )
Verifies a 'value' against a 'type'.
Example:
my $verify_result = verify( label => 'Config.Author.Level', value => 'NULL', type => 'not_null' );
assess( $verify_result ) # this would fail
Because verify returns a hashref containing information about the test result, you must use 'assess' (below) to transform it to a simple boolean value.
assess( $verify_result )
Use 'assess' to process the result of 'verify' to a simple boolean value.
Example:
assess( verify( value => 0, type => 'false' ); # would return true
describe( Data::Verify )
Prints out an english text, describing how the format has to be and how it is tested.
Bouncer Interface
Observes/Inspects other objects if they fullfil a list of tests.
A bouncer in front of a disco makes decisions. He inspects other persons if they meet the criteria/expectations to be accepted to enter the party or not. The criteria are instructed by the boss. This is also how "Bouncer" works: it inspects other objects and rejects/accepts them.
Shortly i call it 'object bouncing'.
EXAMPLE
use Data::Verify;
my $user = new User( email => 'hiho@test.de', registered => 1 );
my $user_bouncer = Bouncer->new(
tests =>
[
Bouncer::Test->new( field => 'email', type => 'email' ),
Bouncer::Test->new( field => 'registered', type => 'not_null' ),
Bouncer::Test->new( field => 'firstname', type => 'word' ),
Bouncer::Test->new( field => 'lastname', type => 'word' )
]
);
if( $user_bouncer->inspect( $user ) )
{
print "User is ok";
}
else
{
print "rejects User because of unsufficient field:", $@;
}
EXPORT
:all = assess, verify, describe
None by default.
AUTHOR
Murat Uenalan, muenalan@cpan.org
SEE ALSO
Regexp::Common, Data::FormValidator, HTML::FormValidator, CGI::FormMagick::Validator, CGI::Validate, Email::Valid, Email::Valid::Loose, Embperl::Form::Validate