From: Dave Rolsky Date: Sat, 21 Feb 2009 22:28:17 +0000 (+0000) Subject: Officially document sugar-free form for type and subtype where it X-Git-Tag: 0.71_01~7 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=9e856c835c42b664192d2d37a0db5468153a7079;p=gitmo%2FMoose.git Officially document sugar-free form for type and subtype where it accepts a hashref of named parameters, rather than positional params. This preserves the safety of non-positional params, but lets you integrate easily with other modules, for doing subtype( 'Foo', { where => sub_returner() } ); Added tests for this new style and made sure the docs show it too. --- diff --git a/lib/Moose/Util/TypeConstraints.pm b/lib/Moose/Util/TypeConstraints.pm index 1046c44..733e297 100644 --- a/lib/Moose/Util/TypeConstraints.pm +++ b/lib/Moose/Util/TypeConstraints.pm @@ -5,7 +5,7 @@ use strict; use warnings; use Carp (); -use List::MoreUtils qw( all ); +use List::MoreUtils qw( all any ); use Scalar::Util qw( blessed reftype ); use Moose::Exporter; @@ -256,17 +256,16 @@ sub register_type_constraint { # type constructors sub type { - if ( all { ( reftype($_) || '' ) eq 'CODE' || ! ref $_ } @_ ) { - # back-compat version, called without sugar - _create_type_constraint( $_[0], undef, $_[1] ); + # back-compat version, called without sugar + if ( ! any { ( reftype($_) || '' ) eq 'HASH' } @_ ) { + return _create_type_constraint( $_[0], undef, $_[1] ); } - else { - my $name = shift; - my %p = map { %{$_} } @_; + my $name = shift; - _create_type_constraint( $name, undef, $p{check}, $p{message}, $p{optimized} ); - } + my %p = map { %{$_} } @_; + + return _create_type_constraint( $name, undef, $p{where}, $p{message}, $p{optimize_as} ); } sub subtype { @@ -294,12 +293,12 @@ sub subtype { my %p = map { %{$_} } @_; # subtype Str => where { ... }; - if ( ! exists $p{parent} ) { - $p{parent} = $name; + if ( ! exists $p{as} ) { + $p{as} = $name; $name = undef; } - _create_type_constraint( $name, $p{parent}, $p{check}, $p{message}, $p{optimized} ); + return _create_type_constraint( $name, $p{as}, $p{where}, $p{message}, $p{optimize_as} ); } sub class_type { @@ -333,10 +332,10 @@ sub coerce { _install_type_coercions($type_name, \@coercion_map); } -sub as ($) { { parent => $_[0] } } -sub where (&) { { check => $_[0] } } -sub message (&) { { message => $_[0] } } -sub optimize_as (&) { { optimized => $_[0] } } +sub as ($) { { as => $_[0] } } +sub where (&) { { where => $_[0] } } +sub message (&) { { message => $_[0] } } +sub optimize_as (&) { { optimize_as => $_[0] } } sub from {@_} sub via (&) { $_[0] } @@ -836,10 +835,13 @@ them to work with Moose. For instance, this is how you could use it with L to declare a completely new type. - type 'HashOfArrayOfObjects' - => IsHashRef( + type 'HashOfArrayOfObjects', + { + where => IsHashRef( -keys => HasLength, - -values => IsArrayRef( IsObject )); + -values => IsArrayRef(IsObject) + ) + }; For more examples see the F test file. @@ -875,8 +877,13 @@ See the L for an example of how to use these. This creates a base type, which has no parent. -Note that calling C I the sugar helpers (C, -C, etc), is deprecated. +The C function should either be called with the sugar helpers +(C, C, etc), or with a name and a hashref of +parameters: + + type( 'Foo', { where => ..., message => ... } ); + +The valid hashref keys are C, C, and C. =item B as 'Parent' => where { } ...> @@ -885,8 +892,14 @@ This creates a named subtype. If you provide a parent that Moose does not recognize, it will automatically create a new class type constraint for this name. -Note that calling C I the sugar helpers (C, -C, etc), is deprecated. +When creating a named type, the C function should either be +called with the sugar helpers (C, C, etc), or with a +name and a hashref of parameters: + + subtype( 'Foo', { where => ..., message => ... } ); + +The valid hashref keys are C (the parent), C, C, +and C. =item B where { } ...> @@ -894,6 +907,12 @@ This creates an unnamed subtype and will return the type constraint meta-object, which will be an instance of L. +When creating an anonymous type, the C function should either +be called with the sugar helpers (C, C, etc), or with +just a hashref of parameters: + + subtype( { where => ..., message => ... } ); + =item B Creates a new subtype of C with the name C<$class> and the diff --git a/t/040_type_constraints/001_util_type_constraints.t b/t/040_type_constraints/001_util_type_constraints.t index 9b463e9..b9e044c 100644 --- a/t/040_type_constraints/001_util_type_constraints.t +++ b/t/040_type_constraints/001_util_type_constraints.t @@ -3,7 +3,7 @@ use strict; use warnings; -use Test::More tests => 73; +use Test::More tests => 84; use Test::Exception; use Scalar::Util (); @@ -161,6 +161,31 @@ throws_ok {$r->add_type_constraint(bless {}, 'SomeClass')} qr/not a valid type c ok( $subtype->has_message, 'subtype does have a message' ); } +# alternative sugar-less calling style which is documented as legit: +{ + my $subtype = subtype( 'MyStr', { as => 'Str' } ); + isa_ok( $subtype, 'Moose::Meta::TypeConstraint', 'got a subtype' ); + is( $subtype->name, 'MyStr', 'name is MyStr' ); + is( $subtype->parent->name, 'Str', 'parent is Str' ); +} + +{ + my $subtype = subtype( { as => 'Str' } ); + isa_ok( $subtype, 'Moose::Meta::TypeConstraint', 'got a subtype' ); + is( $subtype->name, '__ANON__', 'name is __ANON__' ); + is( $subtype->parent->name, 'Str', 'parent is Str' ); +} + +{ + my $subtype = subtype( { as => 'Str', where => sub { /X/ } } ); + isa_ok( $subtype, 'Moose::Meta::TypeConstraint', 'got a subtype' ); + is( $subtype->name, '__ANON__', 'name is __ANON__' ); + is( $subtype->parent->name, 'Str', 'parent is Str' ); + ok( $subtype->check('FooX'), 'constraint accepts FooX' ); + ok( ! $subtype->check('Foo'), 'constraint reject Foo' ); +} + + # Back-compat for being called without sugar. Previously, calling with # sugar was indistinguishable from calling directly. diff --git a/t/200_examples/004_example_w_DCS.t b/t/200_examples/004_example_w_DCS.t index 3dd0e6a..e9edc2e 100644 --- a/t/200_examples/004_example_w_DCS.t +++ b/t/200_examples/004_example_w_DCS.t @@ -27,13 +27,16 @@ use Test::Exception; use Moose; use Moose::Util::TypeConstraints; use Declare::Constraints::Simple -All; - + # define your own type ... - type 'HashOfArrayOfObjects' - => IsHashRef( + type( 'HashOfArrayOfObjects', + { + where => IsHashRef( -keys => HasLength, - -values => IsArrayRef( IsObject )); - + -values => IsArrayRef(IsObject) + ) + } ); + has 'bar' => ( is => 'rw', isa => 'HashOfArrayOfObjects', @@ -42,7 +45,7 @@ use Test::Exception; # inline the constraints as anon-subtypes has 'baz' => ( is => 'rw', - isa => subtype('ArrayRef' => IsArrayRef(IsInt)), + isa => subtype( { as => 'ArrayRef', where => IsArrayRef(IsInt) } ), ); package Bar;