--- /dev/null
+.\" Automatically generated by Pod::Man 2.22 (Pod::Simple 3.10)
+.\"
+.\" Standard preamble:
+.\" ========================================================================
+.de Sp \" Vertical space (when we can't use .PP)
+.if t .sp .5v
+.if n .sp
+..
+.de Vb \" Begin verbatim text
+.ft CW
+.nf
+.ne \\$1
+..
+.de Ve \" End verbatim text
+.ft R
+.fi
+..
+.\" Set up some character translations and predefined strings. \*(-- will
+.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
+.\" double quote, and \*(R" will give a right double quote. \*(C+ will
+.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
+.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
+.\" nothing in troff, for use with C<>.
+.tr \(*W-
+.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
+.ie n \{\
+. ds -- \(*W-
+. ds PI pi
+. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
+. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
+. ds L" ""
+. ds R" ""
+. ds C` ""
+. ds C' ""
+'br\}
+.el\{\
+. ds -- \|\(em\|
+. ds PI \(*p
+. ds L" ``
+. ds R" ''
+'br\}
+.\"
+.\" Escape single quotes in literal strings from groff's Unicode transform.
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\"
+.\" If the F register is turned on, we'll generate index entries on stderr for
+.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index
+.\" entries marked with X<> in POD. Of course, you'll have to process the
+.\" output yourself in some meaningful fashion.
+.ie \nF \{\
+. de IX
+. tm Index:\\$1\t\\n%\t"\\$2"
+..
+. nr % 0
+. rr F
+.\}
+.el \{\
+. de IX
+..
+.\}
+.\"
+.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
+.\" Fear. Run. Save yourself. No user-serviceable parts.
+. \" fudge factors for nroff and troff
+.if n \{\
+. ds #H 0
+. ds #V .8m
+. ds #F .3m
+. ds #[ \f1
+. ds #] \fP
+.\}
+.if t \{\
+. ds #H ((1u-(\\\\n(.fu%2u))*.13m)
+. ds #V .6m
+. ds #F 0
+. ds #[ \&
+. ds #] \&
+.\}
+. \" simple accents for nroff and troff
+.if n \{\
+. ds ' \&
+. ds ` \&
+. ds ^ \&
+. ds , \&
+. ds ~ ~
+. ds /
+.\}
+.if t \{\
+. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
+. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
+. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
+. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
+. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
+. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
+.\}
+. \" troff and (daisy-wheel) nroff accents
+.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
+.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
+.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
+.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
+.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
+.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
+.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
+.ds ae a\h'-(\w'a'u*4/10)'e
+.ds Ae A\h'-(\w'A'u*4/10)'E
+. \" corrections for vroff
+.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
+.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
+. \" for low resolution devices (crt and lpr)
+.if \n(.H>23 .if \n(.V>19 \
+\{\
+. ds : e
+. ds 8 ss
+. ds o a
+. ds d- d\h'-1'\(ga
+. ds D- D\h'-1'\(hy
+. ds th \o'bp'
+. ds Th \o'LP'
+. ds ae ae
+. ds Ae AE
+.\}
+.rm #[ #] #H #V #F C
+.\" ========================================================================
+.\"
+.IX Title "MooseX::Types::Structured 3"
+.TH MooseX::Types::Structured 3 "2010-03-26" "perl v5.8.8" "User Contributed Perl Documentation"
+.\" For nroff, turn off justification. Always turn off hyphenation; it makes
+.\" way too many mistakes in technical documents.
+.if n .ad l
+.nh
+.SH "NAME"
+MooseX::Types::Structured \- Structured Type Constraints for Moose
+.SH "SYNOPSIS"
+.IX Header "SYNOPSIS"
+The following is example usage for this module.
+.PP
+.Vb 1
+\& package Person;
+\&
+\& use Moose;
+\& use MooseX::Types::Moose qw(Str Int HashRef);
+\& use MooseX::Types::Structured qw(Dict Tuple Optional);
+\&
+\& ## A name has a first and last part, but middle names are not required
+\& has name => (
+\& isa=>Dict[
+\& first => Str,
+\& last => Str,
+\& middle => Optional[Str],
+\& ],
+\& );
+\&
+\& ## description is a string field followed by a HashRef of tagged data.
+\& has description => (
+\& isa=>Tuple[
+\& Str,
+\& Optional[HashRef],
+\& ],
+\& );
+\&
+\& ## Remainder of your class attributes and methods
+.Ve
+.PP
+Then you can instantiate this class with something like:
+.PP
+.Vb 10
+\& my $john = Person\->new(
+\& name => {
+\& first => \*(AqJohn\*(Aq,
+\& middle => \*(AqJames\*(Aq
+\& last => \*(AqNapiorkowski\*(Aq,
+\& },
+\& description => [
+\& \*(AqA cool guy who loves Perl and Moose.\*(Aq, {
+\& married_to => \*(AqVanessa Li\*(Aq,
+\& born_in => \*(AqUSA\*(Aq,
+\& };
+\& ]
+\& );
+.Ve
+.PP
+Or with:
+.PP
+.Vb 7
+\& my $vanessa = Person\->new(
+\& name => {
+\& first => \*(AqVanessa\*(Aq,
+\& last => \*(AqLi\*(Aq
+\& },
+\& description => [\*(AqA great student!\*(Aq],
+\& );
+.Ve
+.PP
+But all of these would cause a constraint error for the 'name' attribute:
+.PP
+.Vb 2
+\& ## Value for \*(Aqname\*(Aq not a HashRef
+\& Person\->new( name => \*(AqJohn\*(Aq );
+\&
+\& ## Value for \*(Aqname\*(Aq has incorrect hash key and missing required keys
+\& Person\->new( name => {
+\& first_name => \*(AqJohn\*(Aq
+\& });
+\&
+\& ## Also incorrect keys
+\& Person\->new( name => {
+\& first_name => \*(AqJohn\*(Aq,
+\& age => 39,
+\& });
+\&
+\& ## key \*(Aqmiddle\*(Aq incorrect type, should be a Str not a ArrayRef
+\& Person\->new( name => {
+\& first => \*(AqVanessa\*(Aq,
+\& middle => [1,2],
+\& last => \*(AqLi\*(Aq,
+\& });
+.Ve
+.PP
+And these would cause a constraint error for the 'description' attribute:
+.PP
+.Vb 2
+\& ## Should be an ArrayRef
+\& Person\->new( description => \*(AqHello I am a String\*(Aq );
+\&
+\& ## First element must be a string not a HashRef.
+\& Person\->new (description => [{
+\& tag1 => \*(Aqvalue1\*(Aq,
+\& tag2 => \*(Aqvalue2\*(Aq
+\& }]);
+.Ve
+.PP
+Please see the test cases for more examples.
+.SH "DESCRIPTION"
+.IX Header "DESCRIPTION"
+A structured type constraint is a standard container Moose type constraint,
+such as an ArrayRef or HashRef, which has been enhanced to allow you to
+explicitly name all the allowed type constraints inside the structure. The
+generalized form is:
+.PP
+.Vb 1
+\& TypeConstraint[@TypeParameters or %TypeParameters]
+.Ve
+.PP
+Where 'TypeParameters' is an array reference or hash references of
+Moose::Meta::TypeConstraint objects.
+.PP
+This type library enables structured type constraints. It is built on top of the
+MooseX::Types library system, so you should review the documentation for that
+if you are not familiar with it.
+.SS "Comparing Parameterized types to Structured types"
+.IX Subsection "Comparing Parameterized types to Structured types"
+Parameterized constraints are built into core Moose and you are probably already
+familiar with the type constraints 'HashRef' and 'ArrayRef'. Structured types
+have similar functionality, so their syntax is likewise similar. For example,
+you could define a parameterized constraint like:
+.PP
+.Vb 2
+\& subtype ArrayOfInts,
+\& as ArrayRef[Int];
+.Ve
+.PP
+which would constrain a value to something like [1,2,3,...] and so on. On the
+other hand, a structured type constraint explicitly names all it's allowed
+\&'internal' type parameter constraints. For the example:
+.PP
+.Vb 2
+\& subtype StringFollowedByInt,
+\& as Tuple[Str,Int];
+.Ve
+.PP
+would constrain it's value to things like ['hello', 111] but ['hello', 'world']
+would fail, as well as ['hello', 111, 'world'] and so on. Here's another
+example:
+.PP
+.Vb 1
+\& package MyApp::Types;
+\&
+\& use MooseX::Types \-declare [qw(StringIntOptionalHashRef)];
+\& use MooseX::Types::Moose qw(Str Int);
+\& use MooseX::Types::Structured qw(Tuple Optional);
+\&
+\& subtype StringIntOptionalHashRef,
+\& as Tuple[
+\& Str, Int,
+\& Optional[HashRef]
+\& ];
+.Ve
+.PP
+This defines a type constraint that validates values like:
+.PP
+.Vb 2
+\& [\*(AqHello\*(Aq, 100, {key1 => \*(Aqvalue1\*(Aq, key2 => \*(Aqvalue2\*(Aq}];
+\& [\*(AqWorld\*(Aq, 200];
+.Ve
+.PP
+Notice that the last type constraint in the structure is optional. This is
+enabled via the helper Optional type constraint, which is a variation of the
+core Moose type constraint 'Maybe'. The main difference is that Optional type
+constraints are required to validate if they exist, while 'Maybe' permits
+undefined values. So the following example would not validate:
+.PP
+.Vb 1
+\& StringIntOptionalHashRef\->validate([\*(AqHello Undefined\*(Aq, 1000, undef]);
+.Ve
+.PP
+Please note the subtle difference between undefined and null. If you wish to
+allow both null and undefined, you should use the core Moose 'Maybe' type
+constraint instead:
+.PP
+.Vb 1
+\& package MyApp::Types;
+\&
+\& use MooseX::Types \-declare [qw(StringIntMaybeHashRef)];
+\& use MooseX::Types::Moose qw(Str Int Maybe);
+\& use MooseX::Types::Structured qw(Tuple);
+\&
+\& subtype StringIntMaybeHashRef,
+\& as Tuple[
+\& Str, Int, Maybe[HashRef]
+\& ];
+.Ve
+.PP
+This would validate the following:
+.PP
+.Vb 3
+\& [\*(AqHello\*(Aq, 100, {key1 => \*(Aqvalue1\*(Aq, key2 => \*(Aqvalue2\*(Aq}];
+\& [\*(AqWorld\*(Aq, 200, undef];
+\& [\*(AqWorld\*(Aq, 200];
+.Ve
+.PP
+Structured constraints are not limited to arrays. You can define a structure
+against a HashRef with the 'Dict' type constaint as in this example:
+.PP
+.Vb 5
+\& subtype FirstNameLastName,
+\& as Dict[
+\& firstname => Str,
+\& lastname => Str,
+\& ];
+.Ve
+.PP
+This would constrain a HashRef that validates something like:
+.PP
+.Vb 1
+\& {firstname => \*(AqChristopher\*(Aq, lastname => \*(AqParsons\*(Aq};
+.Ve
+.PP
+but all the following would fail validation:
+.PP
+.Vb 2
+\& ## Incorrect keys
+\& {first => \*(AqChristopher\*(Aq, last => \*(AqParsons\*(Aq};
+\&
+\& ## Too many keys
+\& {firstname => \*(AqChristopher\*(Aq, lastname => \*(AqParsons\*(Aq, middlename => \*(AqAllen\*(Aq};
+\&
+\& ## Not a HashRef
+\& [\*(AqChristopher\*(Aq, \*(AqParsons\*(Aq];
+.Ve
+.PP
+These structures can be as simple or elaborate as you wish. You can even
+combine various structured, parameterized and simple constraints all together:
+.PP
+.Vb 6
+\& subtype Crazy,
+\& as Tuple[
+\& Int,
+\& Dict[name=>Str, age=>Int],
+\& ArrayRef[Int]
+\& ];
+.Ve
+.PP
+Which would match:
+.PP
+.Vb 1
+\& [1, {name=>\*(AqJohn\*(Aq, age=>25},[10,11,12]];
+.Ve
+.PP
+Please notice how the type parameters can be visually arranged to your liking
+and to improve the clarity of your meaning. You don't need to run then
+altogether onto a single line. Additionally, since the 'Dict' type constraint
+defines a hash constraint, the key order is not meaningful. For example:
+.PP
+.Vb 6
+\& subtype AnyKeyOrder,
+\& as Dict[
+\& key1=>Int,
+\& key2=>Str,
+\& key3=>Int,
+\& ];
+.Ve
+.PP
+Would validate both:
+.PP
+.Vb 2
+\& {key1 => 1, key2 => "Hi!", key3 => 2};
+\& {key2 => "Hi!", key1 => 100, key3 => 300};
+.Ve
+.PP
+As you would expect, since underneath its just a plain old Perl hash at work.
+.SS "Alternatives"
+.IX Subsection "Alternatives"
+You should exercise some care as to whether or not your complex structured
+constraints would be better off contained by a real object as in the following
+example:
+.PP
+.Vb 2
+\& package MyApp::MyStruct;
+\& use Moose;
+\&
+\& ## lazy way to make a bunch of attributes
+\& has $_ for qw(full_name age_in_years);
+\&
+\& package MyApp::MyClass;
+\& use Moose;
+\&
+\& has person => (isa => \*(AqMyApp::MyStruct\*(Aq);
+\&
+\& my $instance = MyApp::MyClass\->new(
+\& person=>MyApp::MyStruct\->new(
+\& full_name => \*(AqJohn\*(Aq,
+\& age_in_years => 39,
+\& ),
+\& );
+.Ve
+.PP
+This method may take some additional time to setup but will give you more
+flexibility. However, structured constraints are highly compatible with this
+method, granting some interesting possibilities for coercion. Try:
+.PP
+.Vb 1
+\& package MyApp::MyClass;
+\&
+\& use Moose;
+\& use MyApp::MyStruct;
+\&
+\& ## It\*(Aqs recommended your type declarations live in a separate class in order
+\& ## to promote reusability and clarity. Inlined here for brevity.
+\&
+\& use MooseX::Types::DateTime qw(DateTime);
+\& use MooseX::Types \-declare [qw(MyStruct)];
+\& use MooseX::Types::Moose qw(Str Int);
+\& use MooseX::Types::Structured qw(Dict);
+\&
+\& ## Use class_type to create an ISA type constraint if your object doesn\*(Aqt
+\& ## inherit from Moose::Object.
+\& class_type \*(AqMyApp::MyStruct\*(Aq;
+\&
+\& ## Just a shorter version really.
+\& subtype MyStruct,
+\& as \*(AqMyApp::MyStruct\*(Aq;
+\&
+\& ## Add the coercions.
+\& coerce MyStruct,
+\& from Dict[
+\& full_name=>Str,
+\& age_in_years=>Int
+\& ], via {
+\& MyApp::MyStruct\->new(%$_);
+\& },
+\& from Dict[
+\& lastname=>Str,
+\& firstname=>Str,
+\& dob=>DateTime
+\& ], via {
+\& my $name = $_\->{firstname} .\*(Aq \*(Aq. $_\->{lastname};
+\& my $age = DateTime\->now \- $_\->{dob};
+\&
+\& MyApp::MyStruct\->new(
+\& full_name=>$name,
+\& age_in_years=>$age\->years,
+\& );
+\& };
+\&
+\& has person => (isa=>MyStruct);
+.Ve
+.PP
+This would allow you to instantiate with something like:
+.PP
+.Vb 4
+\& my $obj = MyApp::MyClass\->new( person => {
+\& full_name=>\*(AqJohn Napiorkowski\*(Aq,
+\& age_in_years=>39,
+\& });
+.Ve
+.PP
+Or even:
+.PP
+.Vb 5
+\& my $obj = MyApp::MyClass\->new( person => {
+\& lastname=>\*(AqJohn\*(Aq,
+\& firstname=>\*(AqNapiorkowski\*(Aq,
+\& dob=>DateTime\->new(year=>1969),
+\& });
+.Ve
+.PP
+If you are not familiar with how coercions work, check out the Moose cookbook
+entry Moose::Cookbook::Recipe5 for an explanation. The section \*(L"Coercions\*(R"
+has additional examples and discussion.
+.SS "Subtyping a Structured type constraint"
+.IX Subsection "Subtyping a Structured type constraint"
+You need to exercise some care when you try to subtype a structured type as in
+this example:
+.PP
+.Vb 2
+\& subtype Person,
+\& as Dict[name => Str];
+\&
+\& subtype FriendlyPerson,
+\& as Person[
+\& name => Str,
+\& total_friends => Int,
+\& ];
+.Ve
+.PP
+This will actually work \s-1BUT\s0 you have to take care that the subtype has a
+structure that does not contradict the structure of it's parent. For now the
+above works, but I will clarify the syntax for this at a future point, so
+it's recommended to avoid (should not really be needed so much anyway). For
+now this is supported in an \s-1EXPERIMENTAL\s0 way. Your thoughts, test cases and
+patches are welcomed for discussion. If you find a good use for this, please
+let me know.
+.SS "Coercions"
+.IX Subsection "Coercions"
+Coercions currently work for 'one level' deep. That is you can do:
+.PP
+.Vb 5
+\& subtype Person,
+\& as Dict[
+\& name => Str,
+\& age => Int
+\& ];
+\&
+\& subtype Fullname,
+\& as Dict[
+\& first => Str,
+\& last => Str
+\& ];
+\&
+\& coerce Person,
+\& ## Coerce an object of a particular class
+\& from BlessedPersonObject, via {
+\& +{
+\& name=>$_\->name,
+\& age=>$_\->age,
+\& };
+\& },
+\&
+\& ## Coerce from [$name, $age]
+\& from ArrayRef, via {
+\& +{
+\& name=>$_\->[0],
+\& age=>$_\->[1],
+\& },
+\& },
+\& ## Coerce from {fullname=>{first=>...,last=>...}, dob=>$DateTimeObject}
+\& from Dict[fullname=>Fullname, dob=>DateTime], via {
+\& my $age = $_\->dob \- DateTime\->now;
+\& my $firstn = $_\->{fullname}\->{first};
+\& my $lastn = $_\->{fullname}\->{last}
+\& +{
+\& name => $_\->{fullname}\->{first} .\*(Aq \*(Aq. ,
+\& age =>$age\->years
+\& }
+\& };
+.Ve
+.PP
+And that should just work as expected. However, if there are any 'inner'
+coercions, such as a coercion on 'Fullname' or on 'DateTime', that coercion
+won't currently get activated.
+.PP
+Please see the test '07\-coerce.t' for a more detailed example. Discussion on
+extending coercions to support this welcome on the Moose development channel or
+mailing list.
+.SS "Recursion"
+.IX Subsection "Recursion"
+Newer versions of MooseX::Types support recursive type constraints. That is
+you can include a type constraint as a contained type constraint of itself. For
+example:
+.PP
+.Vb 7
+\& subtype Person,
+\& as Dict[
+\& name=>Str,
+\& friends=>Optional[
+\& ArrayRef[Person]
+\& ],
+\& ];
+.Ve
+.PP
+This would declare a Person subtype that contains a name and an optional
+ArrayRef of Persons who are friends as in:
+.PP
+.Vb 10
+\& {
+\& name => \*(AqMike\*(Aq,
+\& friends => [
+\& { name => \*(AqJohn\*(Aq },
+\& { name => \*(AqVincent\*(Aq },
+\& {
+\& name => \*(AqTracey\*(Aq,
+\& friends => [
+\& { name => \*(AqStephenie\*(Aq },
+\& { name => \*(AqIlya\*(Aq },
+\& ],
+\& },
+\& ],
+\& };
+.Ve
+.PP
+Please take care to make sure the recursion node is either Optional, or declare
+a Union with an non recursive option such as:
+.PP
+.Vb 5
+\& subtype Value
+\& as Tuple[
+\& Str,
+\& Str|Tuple,
+\& ];
+.Ve
+.PP
+Which validates:
+.PP
+.Vb 10
+\& [
+\& \*(AqHello\*(Aq, [
+\& \*(AqWorld\*(Aq, [
+\& \*(AqIs\*(Aq, [
+\& \*(AqGetting\*(Aq,
+\& \*(AqOld\*(Aq,
+\& ],
+\& ],
+\& ],
+\& ];
+.Ve
+.PP
+Otherwise you will define a subtype thatis impossible to validate since it is
+infinitely recursive. For more information about defining recursive types,
+please see the documentation in MooseX::Types and the test cases.
+.SH "TYPE CONSTRAINTS"
+.IX Header "TYPE CONSTRAINTS"
+This type library defines the following constraints.
+.SS "Tuple[@constraints]"
+.IX Subsection "Tuple[@constraints]"
+This defines an ArrayRef based constraint which allows you to validate a specific
+list of contained constraints. For example:
+.PP
+.Vb 2
+\& Tuple[Int,Str]; ## Validates [1,\*(Aqhello\*(Aq]
+\& Tuple[Str|Object, Int]; ## Validates [\*(Aqhello\*(Aq, 1] or [$object, 2]
+.Ve
+.PP
+The Values of \f(CW@constraints\fR should ideally be MooseX::Types declared type
+constraints. We do support 'old style' Moose string based constraints to a
+limited degree but these string type constraints are considered deprecated.
+There will be limited support for bugs resulting from mixing string and
+MooseX::Types in your structures. If you encounter such a bug and really
+need it fixed, we will required a detailed test case at the minimum.
+.SS "Dict[%constraints]"
+.IX Subsection "Dict[%constraints]"
+This defines a HashRef based constraint which allowed you to validate a specific
+hashref. For example:
+.PP
+.Vb 1
+\& Dict[name=>Str, age=>Int]; ## Validates {name=>\*(AqJohn\*(Aq, age=>39}
+.Ve
+.PP
+The keys in \f(CW%constraints\fR follow the same rules as \f(CW@constraints\fR in the above
+section.
+.ie n .SS "Map[ $key_constraint, $value_constraint ]"
+.el .SS "Map[ \f(CW$key_constraint\fP, \f(CW$value_constraint\fP ]"
+.IX Subsection "Map[ $key_constraint, $value_constraint ]"
+This defines a HashRef based constraint in which both the keys and values are
+required to meet certain constraints. For example, to map hostnames to \s-1IP\s0
+addresses, you might say:
+.PP
+.Vb 1
+\& Map[ HostName, IPAddress ]
+.Ve
+.PP
+The type constraint would only be met if every key was a valid HostName and
+every value was a valid IPAddress.
+.SS "Optional[$constraint]"
+.IX Subsection "Optional[$constraint]"
+This is primarily a helper constraint for Dict and Tuple type constraints. What
+this allows is for you to assert that a given type constraint is allowed to be
+null (but \s-1NOT\s0 undefined). If the value is null, then the type constraint passes
+but if the value is defined it must validate against the type constraint. This
+makes it easy to make a Dict where one or more of the keys doesn't have to exist
+or a tuple where some of the values are not required. For example:
+.PP
+.Vb 5
+\& subtype Name() => as Dict[
+\& first=>Str,
+\& last=>Str,
+\& middle=>Optional[Str],
+\& ];
+.Ve
+.PP
+Creates a constraint that validates against a hashref with the keys 'first' and
+\&'last' being strings and required while an optional key 'middle' is must be a
+string if it appears but doesn't have to appear. So in this case both the
+following are valid:
+.PP
+.Vb 2
+\& {first=>\*(AqJohn\*(Aq, middle=>\*(AqJames\*(Aq, last=>\*(AqNapiorkowski\*(Aq}
+\& {first=>\*(AqVanessa\*(Aq, last=>\*(AqLi\*(Aq}
+.Ve
+.PP
+If you use the 'Maybe' type constraint instead, your values will also validate
+against 'undef', which may be incorrect for you.
+.SH "EXPORTABLE SUBROUTINES"
+.IX Header "EXPORTABLE SUBROUTINES"
+This type library makes available for export the following subroutines
+.SS "slurpy"
+.IX Subsection "slurpy"
+Structured type constraints by their nature are closed; that is validation will
+depend on an exact match between your structure definition and the arguments to
+be checked. Sometimes you might wish for a slightly looser amount of validation.
+For example, you may wish to validate the first 3 elements of an array reference
+and allow for an arbitrary number of additional elements. At first thought you
+might think you could do it this way:
+.PP
+.Vb 8
+\& # I want to validate stuff like: [1,"hello", $obj, 2,3,4,5,6,...]
+\& subtype AllowTailingArgs,
+\& as Tuple[
+\& Int,
+\& Str,
+\& Object,
+\& ArrayRef[Int],
+\& ];
+.Ve
+.PP
+However what this will actually validate are structures like this:
+.PP
+.Vb 1
+\& [10,"Hello", $obj, [11,12,13,...] ]; # Notice element 4 is an ArrayRef
+.Ve
+.PP
+In order to allow structured validation of, \*(L"and then some\*(R", arguments, you can
+use the \*(L"slurpy\*(R" method against a type constraint. For example:
+.PP
+.Vb 1
+\& use MooseX::Types::Structured qw(Tuple slurpy);
+\&
+\& subtype AllowTailingArgs,
+\& as Tuple[
+\& Int,
+\& Str,
+\& Object,
+\& slurpy ArrayRef[Int],
+\& ];
+.Ve
+.PP
+This will now work as expected, validating ArrayRef structures such as:
+.PP
+.Vb 1
+\& [1,"hello", $obj, 2,3,4,5,6,...]
+.Ve
+.PP
+A few caveats apply. First, the slurpy type constraint must be the last one in
+the list of type constraint parameters. Second, the parent type of the slurpy
+type constraint must match that of the containing type constraint. That means
+that a Tuple can allow a slurpy ArrayRef (or children of ArrayRefs, including
+another Tuple) and a Dict can allow a slurpy HashRef (or children/subtypes of
+HashRef, also including other Dict constraints).
+.PP
+Please note the the technical way this works 'under the hood' is that the
+slurpy keyword transforms the target type constraint into a coderef. Please do
+not try to create your own custom coderefs; always use the slurpy method. The
+underlying technology may change in the future but the slurpy keyword will be
+supported.
+.SH "ERROR MESSAGES"
+.IX Header "ERROR MESSAGES"
+Error reporting has been improved to return more useful debugging messages. Now
+I will stringify the incoming check value with Devel::PartialDump so that you
+can see the actual structure that is tripping up validation. Also, I report the
+\&'internal' validation error, so that if a particular element inside the
+Structured Type is failing validation, you will see that. There's a limit to
+how deep this internal reporting goes, but you shouldn't see any of the \*(L"failed
+with \s-1ARRAY\s0(\s-1XXXXXX\s0)\*(R" that we got with earlier versions of this module.
+.PP
+This support is continuing to expand, so it's best to use these messages for
+debugging purposes and not for creating messages that 'escape into the wild'
+such as error messages sent to the user.
+.PP
+Please see the test '12\-error.t' for a more lengthy example. Your thoughts and
+preferable tests or code patches very welcome!
+.SH "EXAMPLES"
+.IX Header "EXAMPLES"
+Here are some additional example usage for structured types. All examples can
+be found also in the 't/examples.t' test. Your contributions are also welcomed.
+.SS "Normalize a HashRef"
+.IX Subsection "Normalize a HashRef"
+You need a hashref to conform to a canonical structure but are required accept a
+bunch of different incoming structures. You can normalize using the Dict type
+constraint and coercions. This example also shows structured types mixed which
+other MooseX::Types libraries.
+.PP
+.Vb 1
+\& package Test::MooseX::Meta::TypeConstraint::Structured::Examples::Normalize;
+\&
+\& use Moose;
+\& use DateTime;
+\&
+\& use MooseX::Types::Structured qw(Dict Tuple);
+\& use MooseX::Types::DateTime qw(DateTime);
+\& use MooseX::Types::Moose qw(Int Str Object);
+\& use MooseX::Types \-declare => [qw(Name Age Person)];
+\&
+\& subtype Person,
+\& as Dict[
+\& name=>Str,
+\& age=>Int,
+\& ];
+\&
+\& coerce Person,
+\& from Dict[
+\& first=>Str,
+\& last=>Str,
+\& years=>Int,
+\& ], via { +{
+\& name => "$_\->{first} $_\->{last}",
+\& age => $_\->{years},
+\& }},
+\& from Dict[
+\& fullname=>Dict[
+\& last=>Str,
+\& first=>Str,
+\& ],
+\& dob=>DateTime,
+\& ],
+\& ## DateTime needs to be inside of single quotes here to disambiguate the
+\& ## class package from the DataTime type constraint imported via the
+\& ## line "use MooseX::Types::DateTime qw(DateTime);"
+\& via { +{
+\& name => "$_\->{fullname}{first} $_\->{fullname}{last}",
+\& age => ($_\->{dob} \- \*(AqDateTime\*(Aq\->now)\->years,
+\& }};
+\&
+\& has person => (is=>\*(Aqrw\*(Aq, isa=>Person, coerce=>1);
+.Ve
+.PP
+And now you can instantiate with all the following:
+.PP
+.Vb 6
+\& _\|_PACKAGE_\|_\->new(
+\& person=>{
+\& name=>\*(AqJohn Napiorkowski\*(Aq,
+\& age=>39,
+\& },
+\& );
+\&
+\& _\|_PACKAGE_\|_\->new(
+\& person=>{
+\& first=>\*(AqJohn\*(Aq,
+\& last=>\*(AqNapiorkowski\*(Aq,
+\& years=>39,
+\& },
+\& );
+\&
+\& _\|_PACKAGE_\|_\->new(
+\& person=>{
+\& fullname => {
+\& first=>\*(AqJohn\*(Aq,
+\& last=>\*(AqNapiorkowski\*(Aq
+\& },
+\& dob => \*(AqDateTime\*(Aq\->new(
+\& year=>1969,
+\& month=>2,
+\& day=>13
+\& ),
+\& },
+\& );
+.Ve
+.PP
+This technique is a way to support various ways to instantiate your class in a
+clean and declarative way.
+.SH "SEE ALSO"
+.IX Header "SEE ALSO"
+The following modules or resources may be of interest.
+.PP
+Moose, MooseX::Types, Moose::Meta::TypeConstraint,
+MooseX::Meta::TypeConstraint::Structured
+.SH "TODO"
+.IX Header "TODO"
+Here's a list of stuff I would be happy to get volunteers helping with:
+.PP
+.Vb 4
+\& * All POD examples need test cases in t/documentation/*.t
+\& * Want to break out the examples section to a separate cookbook style POD.
+\& * Want more examples and best practice / usage guidance for authors
+\& * Need to clarify deep coercions,
+.Ve
+.SH "AUTHOR"
+.IX Header "AUTHOR"
+John Napiorkowski <jjnapiork@cpan.org>
+.SH "CONTRIBUTORS"
+.IX Header "CONTRIBUTORS"
+The following people have contributed to this module and agree with the listed
+Copyright & license information included below:
+.PP
+.Vb 3
+\& Florian Ragwitz, <rafl@debian.org>
+\& Yuval Kogman, <nothingmuch@woobling.org>
+\& Tomas Doran, <bobtfish@bobtfish.net>
+.Ve
+.SH "COPYRIGHT & LICENSE"
+.IX Header "COPYRIGHT & LICENSE"
+Copyright 2008\-2009, John Napiorkowski <jjnapiork@cpan.org>
+.PP
+This program is free software; you can redistribute it and/or modify it under
+the same terms as Perl itself.