NAME
Term::Fabulous::Validator - Checks the value of an input widget
SYNOPSIS
use Term::Fabulous::Validator;
use Term::Fabulous::Widget::TextField;
# By name, as a pattern or as code, through an input's validator:
my $email = Term::Fabulous::Widget::TextField->new( validator => 'email' );
my $code = Term::Fabulous::Widget::TextField->new( validator => qr/\A[A-Z]{3}\z/ );
my $even = Term::Fabulous::Widget::TextField->new( validator => sub ($value) { $value % 2 ? 'Please enter an even number.' : undef } );
# As an object, when a validator takes options:
my $port = Term::Fabulous::Widget::TextField->new(
validator => Term::Fabulous::Validator->integer( min => 1, max => 65535 ),
);
my $host = Term::Fabulous::Widget::TextField->new(
validator => Term::Fabulous::Validator->hostname( message => 'Bitte einen Rechnernamen eingeben.' ),
);
# Several at once: all must pass, the first message wins.
my $name = Term::Fabulous::Widget::TextField->new( validator => [ qr/\A\S/, qr/\S\z/ ] );
# Checking a value yourself:
my $validator = Term::Fabulous::Validator->coerce('email');
my $error = $validator->check('me@example'); # 'Please enter an e-mail address.'
DESCRIPTION
A validator checks one value and says what is wrong with it: "check" returns an error message for a value it rejects and undef for one it accepts. The input widgets take one through their validator parameter (see "validator" in Term::Fabulous::Widget::Input), check their value with it on every change and show the invalid look while the check fails; the message is theirs to read through "error" in Term::Fabulous::Widget::Input.
The named validators ("email", "integer", "number", "url", "hostname", "ip", "date", "time") cover the common types of a form. "pattern" checks a value against a regular expression, "code" runs your own check, and "all" combines several. A widget's validator parameter takes any of them as an object, and also the shorthands "coerce" understands: the name of a named validator, a regular expression, a code reference, or a list of those.
Validators check text, not meaning: email accepts anything shaped like name@host.tld and does not look the host up, integer does not know about the field's purpose. They do not care about an empty value either; whether a field may be left empty is the input's required parameter.
Some named validators also know which characters their values are made of: integer, number, date and time suggest an accept spec, which a text input uses as long as it was not given one of its own.
CONSTRUCTORS
Every constructor is a class method. The named validators, "pattern" and "code" take a message option: the error text "check" returns instead of the default. "all" and "coerce" take no options; give the validators they combine a message of their own. Unknown options die.
Term::Fabulous::Validator->email;
Something shaped like an e-mail address: a local part, @, and a host with at least one dot, without whitespace. Default message: "Please enter an e-mail address."
integer
Term::Fabulous::Validator->integer;
Term::Fabulous::Validator->integer( min => 1, max => 65535 );
A whole number: digits with an optional minus sign in front, nothing else (42, -7, 007; not +42, 4.0 or 1e3). With min or max, the number must lie in that range, the limits included. The default message names the range:
with
minandmax: "Please enter a whole number between 1 and 65535."with
minonly: "Please enter a whole number at least 1."with
maxonly: "Please enter a whole number at most 65535."without a range: "Please enter a whole number."
Suggests the accept spec '0-9-': digits and the minus sign, which a text input lets the user type anywhere, so 4-2 can be typed and is then rejected. Dies if min or max is not a number or min is above max.
number
Term::Fabulous::Validator->number( min => 0 );
A decimal number with a point as its decimal separator: an optional minus sign and digits with an optional fraction (3, 3., 3.5, .5, -0.25; not 3,5, 1e3 or +3), within min and max as for "integer". The default message is built like that of "integer" with "a number" in place of "a whole number", such as "Please enter a number at least 0." Suggests '0-9.-'.
url
Term::Fabulous::Validator->url;
A scheme (a letter, then letters, digits, +, . or -), :// and at least one more character, without whitespace anywhere: https://example.com, ftp://host/file. It does not check the scheme or the host, and example.com without a scheme is rejected. Default message: "Please enter a URL, such as https://example.com."
hostname
Term::Fabulous::Validator->hostname;
Labels of ASCII letters, digits and hyphens, separated by dots: each label 1 to 63 characters long and not starting or ending with a hyphen, the whole name at most 253 characters, with an optional trailing dot. localhost, db-1.example.com and example.com. pass; bad_host, -db.example.com and a..b do not. Default message: "Please enter a host name."
ip
Term::Fabulous::Validator->ip;
An IPv4 address in dotted quad form (192.0.2.1), or an IPv6 address (2001:db8::1, ::1), as "inet_pton" in Socket parses them. Host names, ports (192.0.2.1:80) and networks (192.0.2.0/24) are rejected. Default message: "Please enter an IP address."
date
Term::Fabulous::Validator->date( message => 'Please enter your birthday as YYYY-MM-DD.' );
A calendar day as YYYY-MM-DD, with four digits for the year and two each for the month and the day, that exists: 2024-02-29 passes, 2026-02-29 and 2026-4-1 do not. Default message: "Please enter a date as YYYY-MM-DD." Suggests '0-9-'.
time
Term::Fabulous::Validator->time;
HH:MM or HH:MM:SS on the 24-hour clock, with two digits each: 07:30 and 23:59:59 pass, 7:30, 24:00 and 12:60 do not. Default message: "Please enter a time as HH:MM." Suggests '0-9:'.
pattern
Term::Fabulous::Validator->pattern( qr/\A[A-Z]{3}\z/, message => 'Three capital letters, please.' );
The value must match the regular expression. The expression is not anchored for you: qr/[0-9]/ accepts any value with a digit in it, so anchor it with \A and \z to describe the whole value. Default message: "Please match the expected format." Dies for anything but a regular expression.
code
Term::Fabulous::Validator->code( sub ($value) {
return 'Please enter an even number.' if $value % 2;
return;
} );
Your own check. The code is called with the value and returns what is wrong with it:
a string other than
"1": the error message;1(as from a true comparison) or a reference: the validator'smessage, by default "Invalid value.";a false value (
undef, an empty list,''or0): the value is fine.
So sub ($value) { $value % 2 } rejects odd numbers with the validator's message. An input never calls the code with an empty value (see "required" in Term::Fabulous::Widget::Input); "check" does, if you pass one.
all
Term::Fabulous::Validator->all( 'hostname', qr/\.example\.com\z/ );
Every validator must pass; they are checked in the given order and the message of the first one that fails is the error. Each argument is coerced as "coerce" does, so names, regular expressions and code references work too. The combined validator suggests the accept spec of the first validator that has one, and its "message" is that of the first validator. A single argument returns that validator itself; no argument dies. all takes no message option.
coerce
my $validator = Term::Fabulous::Validator->coerce($spec);
What an input's validator parameter does with its value: a Term::Fabulous::Validator is returned as it is, a string names one of the named constructors ("names" lists them; anything else dies with the list), a regular expression becomes "pattern", a code reference "code", an array reference "all" over its items, and undef stays undef. Any other kind of value dies.
new
my $message = 'Please enter a hexadecimal number.';
my $hex = Term::Fabulous::Validator->new(
name => 'hex',
message => $message,
accept => '0-9a-fA-F',
check => sub ($value) { $value =~ /\A[0-9a-fA-F]+\z/ ? undef : $message },
);
The general form the constructors above use, for a validator that also suggests an accept spec. It takes:
name-
Required. A string, returned by "name".
message-
Required. A string, returned by "message".
checkdecides what "check" returns;messageis only reported, socheckusually returns it. check-
Required. Code called with the value that returns the error message, or a false value for a valid one. Unlike "code", a true value is always used as the message as it is.
accept-
Optional. The accept spec suggested to a text input (see "accept" in Term::Fabulous::Widget::TextInput), or
undef.
Without an accept, "code" is the shorter way to the same thing.
METHODS
check
my $error = $validator->check($value);
The error message for a value the validator rejects, undef for one it accepts.
name
The name of the constructor that made the validator ('email', 'pattern', 'code', 'all', ...).
message
The message "check" returns for a value the validator rejects, unless "code" or "all" gives a more specific one.
accept
The accept spec the validator suggests for a text input, or undef.
names
my @names = Term::Fabulous::Validator->names;
The names "coerce" accepts, as a list of strings.
SEE ALSO
"validator" in Term::Fabulous::Widget::Input and "required" in Term::Fabulous::Widget::Input, where validators are used; "accept" in Term::Fabulous::Widget::TextInput for restricting the characters of a text input; the checking input section of the forms guide; the recipes "Check the values of a form (required, validator)" in Term::Fabulous::Cookbook::Forms (every named validator in one form) and "Write your own checks and restrict typing (accept, pattern, code)" in Term::Fabulous::Cookbook::Forms.