The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
use strict;
use warnings;
use Test::More;
use Try::Tiny;

# this is an example of a validation that should live outside of the
# form, yet needs to be called in the form's validate routine

{

    package SignupForm;
    use HTML::FormHandler::Moose;
    extends 'HTML::FormHandler';

    has check_name_availability => (
        traits   => ['Code'],
        isa      => 'CodeRef',
        required => 1,
        handles  => { name_available => 'execute', },
    );

    has_field 'name';
    has_field 'email';

    sub validate {
        my $self = shift;
        my $name = $self->value->{name};
        if ( defined $name && length $name && !$self->name_available($name) ) {
            $self->field('name')->add_error('That name is taken already');
        }
    }

}

{
    package MyApp::Signup;
    use Moose;

    has 'form' => ( is => 'ro', builder => 'build_form' );
    sub build_form {
        my $self = shift;
        return SignupForm->new(
            {
                check_name_availability => sub {
                    my $name = shift;
                    return $self->username_available($name);
                },
            }
        );

    }
    sub username_available {
        my ( $self, $name ) = @_;
        return $name eq 'Sam' ? 1 : 0;
    }

}

my $obj = MyApp::Signup->new;

ok( $obj->form, 'form built' );

my $params = { name => 'Sam', email => 'sam@gmail.com' };

$obj->form->process( params => $params );
ok( $obj->form->validated, 'form validated' );

$params->{name} = 'Jane';
$obj->form->process( params => $params );
ok( !$obj->form->validated, 'form did not validate' );

done_testing;