support arrayrefs as well as lists for enum and duck_type
Jesse Luehrs [Thu, 10 Sep 2009 06:54:07 +0000 (01:54 -0500)]
this should make things more consistent with their anon-type forms,
without breaking backwards compatibility - just use an arrayref in all
cases.

Changes
lib/Moose/Manual/Delta.pod
lib/Moose/Util/TypeConstraints.pm
t/040_type_constraints/015_enum.t
t/040_type_constraints/034_duck_types.t

diff --git a/Changes b/Changes
index 377e0de..20d576e 100644 (file)
--- a/Changes
+++ b/Changes
@@ -10,6 +10,10 @@ for, noteworthy changes.
     * Moose::Meta::Method::Delegation
       - preserve aliasing for delegated methods (doy)
 
+    * Moose::Util::TypeConstraints
+      - allow arrayrefs for all forms of enum and duck_type, not just anonymous
+        (the non-arrayref forms may be removed in the future). (doy)
+
 0.92 Tue, Sep 22, 2009
     * Moose::Util::TypeConstraints
       - added the match_on_type operator (Stevan)
index fb79978..286fe8c 100644 (file)
@@ -64,6 +64,19 @@ this may cause issues should be helpful. Metaclasses (classes that inherit
 from L<Class::MOP::Object>) are currently exempt from this check, since at the
 moment we aren't very consistent about which metaclasses we immutabilize.
 
+=item C<enum> and C<duck_type> now take arrayrefs for all forms
+
+Previously, calling these functions with a list would take the first element of
+the list as the type constraint name, and use the remainder as the enum values
+or method names. This makes the interface inconsistent with the anon-type forms
+of these functions (which must take an arrayref), and a free-form list where
+the first value is sometimes special is hard to validate (and harder to give
+reasonable error messages for). These functions have been changed to take
+arrayrefs in all their forms - so, C<< enum 'My::Type' => [qw(foo bar)] >> is
+now the preferred way to create an enum type constraint. The old syntax still
+works for now, but it will hopefully be deprecated and removed in a future
+release.
+
 =back
 
 =head1 Version 0.89_01
index cab95a5..12d825f 100644 (file)
@@ -366,6 +366,9 @@ sub duck_type {
         @methods   = @$type_name;
         $type_name = undef;
     }
+    if ( @methods == 1 && ref $methods[0] eq 'ARRAY' ) {
+        @methods = @{ $methods[0] };
+    }
 
     register_type_constraint(
         create_duck_type_constraint(
@@ -412,6 +415,9 @@ sub enum {
         @values    = @$type_name;
         $type_name = undef;
     }
+    if ( @values == 1 && ref $values[0] eq 'ARRAY' ) {
+        @values = @{ $values[0] };
+    }
     ( scalar @values >= 2 )
         || __PACKAGE__->_throw_error(
         "You must have at least two values to enumerate through");
@@ -1026,10 +1032,10 @@ metaclass L<Moose::Meta::TypeConstraint::Role>.
 Creates a type constraint for either C<undef> or something of the
 given type.
 
-=item B<duck_type ($name, @methods)>
+=item B<duck_type ($name, \@methods)>
 
 This will create a subtype of Object and test to make sure the value
-C<can()> do the methods in C<@methods>.
+C<can()> do the methods in C<\@methods>.
 
 This is intended as an easy way to accept non-Moose objects that
 provide a certain interface. If you're using Moose classes, we
@@ -1037,20 +1043,20 @@ recommend that you use a C<requires>-only Role instead.
 
 =item B<duck_type (\@methods)>
 
-If passed an ARRAY reference instead of the C<$name>, C<@methods>
-pair, this will create an unnamed duck type. This can be used in an
-attribute definition like so:
+If passed an ARRAY reference as the only parameter instead of the
+C<$name>, C<\@methods> pair, this will create an unnamed duck type.
+This can be used in an attribute definition like so:
 
   has 'cache' => (
       is  => 'ro',
       isa => duck_type( [qw( get_set )] ),
   );
 
-=item B<enum ($name, @values)>
+=item B<enum ($name, \@values)>
 
 This will create a basic subtype for a given set of strings.
 The resulting constraint will be a subtype of C<Str> and
-will match any of the items in C<@values>. It is case sensitive.
+will match any of the items in C<\@values>. It is case sensitive.
 See the L<SYNOPSIS> for a simple example.
 
 B<NOTE:> This is not a true proper enum type, it is simply
@@ -1058,9 +1064,9 @@ a convenient constraint builder.
 
 =item B<enum (\@values)>
 
-If passed an ARRAY reference instead of the C<$name>, C<@values> pair,
-this will create an unnamed enum. This can then be used in an attribute
-definition like so:
+If passed an ARRAY reference as the only parameter instead of the
+C<$name>, C<\@values> pair, this will create an unnamed enum. This
+can then be used in an attribute definition like so:
 
   has 'sort_order' => (
       is  => 'ro',
index 162905e..931e15d 100644 (file)
@@ -11,7 +11,7 @@ use Moose::Util::TypeConstraints;
 
 enum Letter => 'a'..'z', 'A'..'Z';
 enum Language => 'Perl 5', 'Perl 6', 'PASM', 'PIR'; # any others? ;)
-enum Metacharacter => '*', '+', '?', '.', '|', '(', ')', '[', ']', '\\';
+enum Metacharacter => ['*', '+', '?', '.', '|', '(', ')', '[', ']', '\\'];
 
 my @valid_letters = ('a'..'z', 'A'..'Z');
 
index 87aca90..35c9abe 100644 (file)
@@ -2,7 +2,7 @@
 use strict;
 use warnings;
 
-use Test::More tests => 4;
+use Test::More tests => 5;
 use Test::Exception;
 
 {
@@ -39,6 +39,7 @@ use Test::Exception;
     use Moose::Util::TypeConstraints;
 
     duck_type 'DuckType' => qw(quack);
+    duck_type 'SwanType' => [qw(honk)];
 
     has duck => (
         isa        => 'DuckType',
@@ -53,6 +54,11 @@ use Test::Exception;
         is => 'ro',
     );
 
+    has other_swan => (
+        isa => 'SwanType',
+        is => 'ro',
+    );
+
 }
 
 # try giving it a duck
@@ -70,3 +76,5 @@ lives_ok { DucktypeTest->new( swan => Swan->new ) } 'but a Swan can honk';
 lives_ok { DucktypeTest->new( duck => RubberDuck->new ) }
 'the RubberDuck lives okay';
 
+# try with the other constraint form
+lives_ok { DucktypeTest->new( other_swan => Swan->new ) } 'but a Swan can honk';