title: Moose deep coercion - ArrayRef of user-defined types
body: <p>What am I missing in the following subtype and coercion chain? I'd like to be able to coerce an arrayref of validated types or die from the following inputs:</p>
  
  <ul>
  <li>Coercible string</li>
  <li>Valid string</li>
  <li>Arrayref of mixed coercible and valid strings</li>
  </ul>
  
  <p>Assume that all types are fully namespaced and that the undeclared functions <code>validate</code> and <code>coerce_str</code> validate (returning bool) and coerce and return a valid string from input, respectively.</p>
  
  <pre><code>subtype 'CustomType'
    =&gt; as 'Str'
      =&gt; where { validate($_) }
    ;
  
  coerce 'CustomType'
    =&gt; from 'Str'
      =&gt; via { if (my $coerced = coerce_str($_)) {
                 return $coerced;
               } 
               return $_;
             }
    ;
  
  subtype 'ArrayRefofCustomTypes'
    =&gt; as 'ArrayRef[CustomType]'
    ;
  
  coerce 'ArrayRefofCustomTypes'
    =&gt; from 'CustomType'
      =&gt; via { [ $_ ] }
    ;
  
  has 'values' =&gt; ( is =&gt; 'ro', required =&gt; 1,
                    isa =&gt; 'ArrayRefofCustomTypes', 
                    coerce =&gt; 1,
                  );
  </code></pre>
  
  <p>I know CustomType works; as I can define an attribute as it and initialize the object using either a coercible string or an already valid string. What I'm not so sure how to do is to explicitly handle delving into the passed arrayref from the constructor and validating all of the contained strings individually. I've read through the documentation on deep coercion (<a href="http://search.cpan.org/dist/Moose/lib/Moose/Manual/Types.pod#Deep_coercion" rel="nofollow">http://search.cpan.org/dist/Moose/lib/Moose/Manual/Types.pod#Deep_coercion</a>) a couple times and I'm just not quite getting it and am hoping someone can point me in the right direction. Thanks!</p>
  
  <p>Here, I'd pared it down to outline it more succinctly, but:</p>
  
  <pre><code>{ 
    package My::Class;
  
    use strict;
    use warnings;
  
    use Moose;
    use Moose::Util::TypeConstraints;
  
    subtype 'CustomType'
      =&gt; as 'Str'
        =&gt; where { validate($_) }
      ;
  
    coerce 'CustomType'
      =&gt; from 'Str'
        =&gt; via { if (my $coerced = coerce_str($_)) {
                   return $coerced;
                 } 
                 return $_;
               }
      ;
  
    subtype 'ArrayRefofCustomTypes'
      =&gt; as 'ArrayRef[CustomType]'
      ;
  
    coerce 'ArrayRefofCustomTypes'
      =&gt; from 'CustomType'
        =&gt; via { [ $_ ] }
      ;
  
    has 'values' =&gt; ( is =&gt; 'ro', required =&gt; 1,
                      isa =&gt; 'ArrayRefofCustomTypes', 
                      coerce =&gt; 1,
                    );
  
    sub validate {
      my $val = shift;
      if ($val =~ /^\w+$/) {
        return 1;
      }
      return ();
    }
  
    sub coerce_str {
      my $val = shift;
      $val =~ s/\W/_/g;
      return $val;
    }
  }
  
  {
    package main;
  
    use strict;
    use warnings;
    use Test::More qw/no_plan/;
  
    new_ok( 'My::Class' =&gt; [ values =&gt; [ 'valid' ] ]); #ok
    new_ok( 'My::Class' =&gt; [ values =&gt; [ qw/valid valid still_valid/ ] ]); #ok
    new_ok( 'My::Class' =&gt; [ values =&gt; 'valid' ]); # ok
    new_ok( 'My::Class' =&gt; [ values =&gt; [ 'invalid; needs some coercion - ^&amp;%&amp;^' ] ]); #not ok
    new_ok( 'My::Class' =&gt; [ values =&gt; 'invalid; needs some coercion - ^&amp;%&amp;^' ]); # not ok
    cmp_ok( My::Class::coerce_str('invalid; needs some coercion - ^&amp;%&amp;^'), 'eq', 'invalid__needs_some_coercion________', 'properly coerces strings'); #ok
  
  }
  </code></pre>
  
  <p>Running that as-is gives me the below. The problem is not the validation, but that I'm not explicitly defining my coercions, and I'm not sure what I'm missing:</p>
  
  <pre><code>ok 1 - The object isa My::Class
  ok 2 - The object isa My::Class
  ok 3 - The object isa My::Class    
  not ok 4 - new() died
  #   Failed test 'new() died'
  #   at testcoercion.pl line 63.
  #     Error was:  Attribute (values) does not pass the type constraint because: Validation failed for 'ArrayRefofCustomTypes' with value [ "invalid; needs some coercion - ^&amp;%&amp;^" ] at C:/strawberry/perl/site/lib/Moose/Meta/Attribute.pm line 1131
  
  &lt;&lt; cut &gt;&gt;
  
  not ok 5 - new() died
  #   Failed test 'new() died'
  #   at testcoercion.pl line 64.
  #     Error was:  Attribute (values) does not pass the type constraint because: Validation failed for 'ArrayRefofCustomTypes' with value "invalid; needs some coercion - ^&amp;%&amp;^" at C:/strawberry/perl/site/lib/Moose/Meta/Attribute.pm line 1131
  
  &lt;&lt; cut &gt;&gt;
  
  ok 6 - properly coerces strings
  1..6
  # Looks like you failed 2 tests of 6.
  </code></pre>