2011-06-22 27 views
5

Aşağıdaki alt tip ve zorlama zincirinde ne eksik?Moose deep coercion - Kullanıcı tanımlı türlerin ArrayRef'i

  • Coercible dize karışık Coercible ait
  • Geçerli dize
  • Arrayref ve geçerli dizeler

: Ben valide türlerinden bir arrayref zorlamak veya aşağıdaki girişlerden ölmeye muktedir istiyorum Tüm türlerin tam olarak isimlendirildiğini ve kayıt dışı işlevlerin validate ve coerce_str geçerli olduğunu varsayın (boole döndürerek) ve geçerli bir dizeyi sırasıyla girişten döndürün ve döndürün.

subtype 'CustomType' 
    => as 'Str' 
    => where { validate($_) } 
    ; 

coerce 'CustomType' 
    => from 'Str' 
    => via { if (my $coerced = coerce_str($_)) { 
       return $coerced; 
      } 
      return $_; 
      } 
    ; 

subtype 'ArrayRefofCustomTypes' 
    => as 'ArrayRef[CustomType]' 
    ; 

coerce 'ArrayRefofCustomTypes' 
    => from 'CustomType' 
    => via { [ $_ ] } 
    ; 

has 'values' => (is => 'ro', required => 1, 
        isa => 'ArrayRefofCustomTypes', 
        coerce => 1, 
       ); 

CustomType çalışmalarını biliyorum; Bir özniteliği olduğu gibi tanımlayabilir ve nesneyi, zor bir dize veya zaten geçerli bir dize kullanarak başlatabilirim. Ne yapmam gerektiğinden emin değilim ki, yapıcıdan geçirilen diziye ayrılmayı ve içerilen dizelerin tümünü tek tek doğrulayarak açık bir şekilde ele almaktır. Derin baskı (http://search.cpan.org/dist/Moose/lib/Moose/Manual/Types.pod#Deep_coercion) dokümantasyonunu birkaç kez okudum ve tam anlamıyla anlayamıyorum ve birisinin beni doğru yönde göstermesini umuyorum. Teşekkürler!

İşte, bunu daha özlü bir ana hatlarıyla bunu kırpılmış ederdim ama:

{ 
    package My::Class; 

    use strict; 
    use warnings; 

    use Moose; 
    use Moose::Util::TypeConstraints; 

    subtype 'CustomType' 
    => as 'Str' 
     => where { validate($_) } 
    ; 

    coerce 'CustomType' 
    => from 'Str' 
     => via { if (my $coerced = coerce_str($_)) { 
       return $coerced; 
       } 
       return $_; 
      } 
    ; 

    subtype 'ArrayRefofCustomTypes' 
    => as 'ArrayRef[CustomType]' 
    ; 

    coerce 'ArrayRefofCustomTypes' 
    => from 'CustomType' 
     => via { [ $_ ] } 
    ; 

    has 'values' => (is => 'ro', required => 1, 
        isa => 'ArrayRefofCustomTypes', 
        coerce => 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' => [ values => [ 'valid' ] ]); #ok 
    new_ok('My::Class' => [ values => [ qw/valid valid still_valid/ ] ]); #ok 
    new_ok('My::Class' => [ values => 'valid' ]); # ok 
    new_ok('My::Class' => [ values => [ 'invalid; needs some coercion - ^&%&^' ] ]); #not ok 
    new_ok('My::Class' => [ values => 'invalid; needs some coercion - ^&%&^' ]); # not ok 
    cmp_ok(My::Class::coerce_str('invalid; needs some coercion - ^&%&^'), 'eq', 'invalid__needs_some_coercion________', 'properly coerces strings'); #ok 

} 

-olduğu gibi aşağıda bana verir yayınlanıyor. Sorun doğrulama değil, ama açıkça benim Coercions tanımlayan değilim, ben özlüyorum emin değilim: Eğer kullanılan

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 - ^&%&^" ] at C:/strawberry/perl/site/lib/Moose/Meta/Attribute.pm line 1131 

<<cut>> 

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 - ^&%&^" at C:/strawberry/perl/site/lib/Moose/Meta/Attribute.pm line 1131 

<<cut>> 

ok 6 - properly coerces strings 
1..6 
# Looks like you failed 2 tests of 6. 
+0

Bir not - Ben '} {> = aracılığıyla 'ArrayRef [Str]' den bir' zorlamak için 'ArrayRefofCustomTypes' => ekleme ve benim zorlama kod çoğaltma ancak arrayref içine yapışmasını idare container'll zanlısı Ancak bu, tüm dizgi -> özel tür dönüşüm kodunu çoğaltır.Belgeleri yeniden okurken, bunun tüm dönüşümlerin açık bir şekilde nasıl tanımlanması gerektiği ile ilgili olduğunu düşündüğümden şüpheliyim, ancak kodun çoğaltılmasından nefret ediyorum. – Oesor

cevap

2

Evet, zorlama, almak istediğiniz girdinin tüm permütasyonları için taban türlerinden özel türlere açık bir şekilde tanımlanmalıdır. Zorlama ve doğrulama kodunu alt programlara taşımak kod çoğaltmasını önlemeye yardımcı olur, ancak tamamen ortadan kaldırmaz. Aşağıdaki kod, bunu kanıtlamak için bir TAP planıyla birlikte beklediğim gibi çalışır. Her ne kadar işe yarıyorsa da, bu tür şeylerin üstesinden gelmenin bir yolu olduğuna kesinlikle inanmıyorum. Temel türlerden özel bir diziye özgü bir çok döküm gerçekleştiriyor ve bir erişimcinin zorlama ile birden çok türü kabul etmesi durumunda bu durumun daha geniş bir bağlamda ne kadar iyi çalıştığından emin değilim.

Düzenleme: Aslında, bu noktada coerce 'ArrayRefofCustomTypes' => from 'CustomType' tamamen gereksizdir, => from 'Str' hem geçerli hem de geçersiz girdileri işleyecektir.

{ 
    package My::Class; 

    use strict; 
    use warnings; 

    use Moose; 
    use Moose::Util::TypeConstraints; 

    subtype 'CustomType' 
    => as 'Str' 
     => where { validate_cust($_) } 
    ; 

    coerce 'CustomType' 
    => from 'Str' 
     => via { coerce_str_to_cust($_) } 
    ; 

    subtype 'ArrayRefofCustomTypes' 
    => as 'ArrayRef[CustomType]' 
    ; 

    coerce 'ArrayRefofCustomTypes' 
    => from 'CustomType' 
     => via { [ $_ ] } 
    => from 'ArrayRef[Str]' 
     => via { [ map { coerce_str_to_cust($_) } @$_ ] } 
    => from 'Str' 
     => via { [ coerce_str_to_cust($_) ] } 
    ; 

    has 'values' => (is => 'ro', required => 1, 
        isa => 'ArrayRefofCustomTypes', 
        coerce => 1, 
       ); 

    sub validate_cust { 
    my $val = shift; 
    if ($val =~ /^\w+$/) { 
     return 1; 
    } 
    return(); 
    } 

    sub coerce_str_to_cust { 
    my $val = shift; 
    my $coerced = $val; 
    $coerced =~ s/\s/_/g; 

    if (validate_cust($coerced)) { 
     return $coerced; 
    } 
    else { 
     return $val; 
    } 
    } 
} 

{ 
    package main; 

    use strict; 
    use warnings; 
    use Test::More tests => 12; 
    use Test::Exception; 

    new_ok('My::Class' => [ values => [ 'valid' ] ]); 
    new_ok('My::Class' => [ values => [ qw/valid valid still_valid/ ] ]); 
    new_ok('My::Class' => [ values => 'valid' ]); 
    new_ok('My::Class' => [ values => [ 'invalid and needs some coercion' ] ]); 
    new_ok('My::Class' => [ values => 'invalid and needs some coercion' ]); 
    new_ok('My::Class' => [ values => [ 'valid', 'valid', 'invalid and needs some coercion' ] ]); 
    throws_ok { my $obj = My::Class->new(values => [ q/can't be coerced cause it has &^%#$*&^%#$s in it/ ]); } qr/Attribute \(values\) does not pass the type constraint because: Validation failed/, 'throws exception on uncoercible input'; 

    my $uncoercible = q/can't be coerced cause it has &^%#$*&^%#$s in it/; 
    cmp_ok(My::Class::coerce_str_to_cust('invalid and needs some coercion'), 'eq', 'invalid_and_needs_some_coercion', 'properly coerces strings'); 
    cmp_ok(My::Class::coerce_str_to_cust($uncoercible), 'eq', $uncoercible , 'returns uncoercible strings unmodified'); 
    ok(My::Class::validate_cust('valid'), 'valid string validates'); 
    ok(My::Class::validate_cust(My::Class::coerce_str_to_cust('invalid and needs some coercion')), 'coerced string validates'); 
    ok(!My::Class::validate_cust('invalid and needs some coercion'), "invalid string doesn't validate"); 
} 
2

Her şey iyi çalışması gerekir.

my $customtype = Moose::Util::TypeConstraints::find_type_constraint('CustomType'); 
print "'a' validates as customtype? ", ($customtype->check('a') ? 'yes' : 'no'), "\n"; 

my $arraytype = Moose::Util::TypeConstraints::find_type_constraint('ArrayRefofCustomTypes'); 
print "[ 'a' ] validates as array? ", ($arraytype->check([ 'a' ]) ? 'yes' : 'no'), "\n"; 

{ 
    package Class; 
    use Moose; 
    has 'values' => (is => 'ro', required => 1, 
         isa => 'ArrayRefofCustomTypes', 
         coerce => 1, 
        ); 
} 

my $obj = Class->new(values => 'a'); 
print $obj->dump(2); 

Bu baskılar:

'a' validates as customtype? yes 
[ 'a' ] validates as array? yes 
$VAR1 = bless({ 
       'values' => [ 
           'a' 
          ] 
       }, 'Class'); 

Sonuç: Örneğin, bu test düşünün Sorun yaşıyorsanız, eğer başka bir kodu gönderiyor. Beklediğiniz gibi çalışmayan bazı kodları yapıştırabilir misiniz?

+0

Elbette; w/tam kod güncellendi. Düzenleme: Aslında; aceleyle yazılan, bu türden yazılı örneklerin iyi olmadığını söyler. – Oesor

+0

s /// g ile zorlanmaya yardımcı olur, ancak hala sorunu çözmez; kod güncellendi. – Oesor

İlgili konular