develooper Front page | perl.moose | Postings from May 2014

Parameterized Type Intersections?

Thread Next
From:
Thalhammer, Jeffrey Ryan
Date:
May 2, 2014 07:24
Subject:
Parameterized Type Intersections?
Message ID:
CABE6C1FpyviU+3-QYKX7dUT=QiMiAY5q_zKWkLKkDbLmLkmiRg@mail.gmail.com
Hello all-

Some context: I have a web application with a fair bit of code for
validating data (mostly from form fields). Most of that data eventually
ends up in attributes of some Moose class, which also have type
constraints. Functionality-wise, there seems to be a lot of overlap between
the validation code and the type constraints. Basically, they both make
assertions about the state of some data.

I’m using Input::Validator, which is a nice framework for composing
validation rules. But instead, I’d like to just use Moose-compatible type
constraints so I only have to define the rules in one place. The problem
is, the validation rules seem to be more complex and dynamic than type
constraints typically allow (at least, with MooseX::Types).

I feel that I want to construct type constraints that can take arbitrary
arguments. And I want to create type constraints by combining several other
constraints that must all be satisfied (maybe this is a type intersection
instead of a union). I have looked at MooseX::Types::Structured and
Types::Tiny, but from my initial read of the documentation they didn’t seem
to be what I want.

Consider a “Password” constraint that must be a) defined, b) a string, c)
more than $n characters in length, d) match some $regexp, and e) return
true when passed to some callback. I could cook up a single Password type
and validate all those characteristics with a single fat constraint. But I
want to get specific messages about the exact nature of the constraint
failure. Furthermore, I’d like to reuse those sub-constraints to create
other constraints.

Here’s a hypothetical example of what that might look like (misusing some
of the existing sugar for Moose type constraints):

subtype Defined as Any where { defined $_  }, message { 'Required' };
subtype String as Any where { not ref $_  }, message { 'Must be a string' };
subtype MinLength as Any where { my $min = shift; length $_  > $min },
message { 'Must be at least...' };
subtype Matches as Any where { my $rx = shift; $_ =~ $rx }, message {
'Must match pattern ...' };
subtype Callback as Any where { my $cb = shift; $cb->($_) }, message {
'Must not have been used before' };

subtype Password, as Defined & String & MinLength(16) &
Matches(qr/.../) & Callback(sub{...});
subtype LongPassword, as Defined & String & MinLength(32) &
Matches(qr/.../) & Callback(sub{...});
subtype LongNumericPassword, as Defined & String & MinLength(32) &
Matches(qr/^\d$/) & Callback(sub{...});

Does that make any sense? Is this a misappropriate use of type constraints?
Is this already supported and I’ve just overlooked it?

-Jeff

Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About