2011-04-28 72 views
5

Moose types很棒,但有時您需要更具體。大家都知道這些數據類型規則:該參數可能只有'A''B''C',或者只有一個貨幣符號,或者必須符合一些正則表達式。適用於穆斯(Moose)屬性的特定支票(超過穆斯類型)

看看下面有兩個約束屬性的示例,其中一個必須是'm''f',另一個必須是有效的ISO日期。穆斯有什麼最好的方式來指定這些約束條件?我會想到SQL CHECK子句,但AFAICS在Moose中沒有check關鍵字。所以我用trigger,但聽起來不對。任何人有更好的答案?

package Person; 
use Moose; 

has gender   => is => 'rw', isa => 'Str', trigger => 
    sub { confess 'either m or f' if $_[1] !~ m/^m|f$/ }; 
has name   => is => 'rw', isa => 'Str'; 
has dateOfBirth  => is => 'rw', isa => 'Str', trigger => 
    sub { confess 'not an ISO date' if $_[1] !~ m/^\d\d\d\d-\d\d-\d\d$/ }; 

no Moose; 
__PACKAGE__->meta->make_immutable; 

package main; 
use Test::More; 
use Test::Exception; 

dies_ok { Person->new(gender => 42) } 'gender must be m or f'; 
dies_ok { Person->new(dateOfBirth => 42) } 'must be an ISO date'; 

done_testing; 

這裏是我結束了使用:

package Blabla::Customer; 
use Moose::Util::TypeConstraints; 
use Moose; 

subtype ISODate => as 'Str' => where { /^\d\d\d\d-\d\d-\d\d$/ }; 

has id    => is => 'rw', isa => 'Str'; 
has gender   => is => 'rw', isa => enum ['m', 'f']; 
has firstname  => is => 'rw', isa => 'Str'; 
has dateOfBirth  => is => 'rw', isa => 'ISODate'; 

no Moose; 
__PACKAGE__->meta->make_immutable; 

這是駝鹿版本1.19,如果它很重要。我得到了以下警告:錯誤subtype as => 'Str', where => { ... }語法我錯誤地介紹了:Calling subtype() with a simple list of parameters is deprecated。所以我必須根據精細的手冊稍微改變它。

+1

**答案:**使用自己的類型。 – 2011-04-28 17:39:22

回答

6

只需定義您自己的子類型,然後使用它。

package Person; 

use Moose::Util::TypeConstraints; 

use namespace::clean; 
use Moose; 

has gender => (
    is => 'rw', 
    isa => subtype(
    as 'Str', 
    where { /^[mf]$/ } 
), 
); 
has name => (
    is => 'rw', 
    isa => 'Str' 
); 
has dateOfBirth => (
    is => 'rw', 
    isa => subtype(
    as 'Str', 
    where { /^\d\d\d\d-\d\d-\d\d$/ } 
), 
); 

no Moose; 
__PACKAGE__->meta->make_immutable; 
1; 
​​

或者你可以使用MooseX::Types模塊。

package Person::TypeConstraints; 

use MooseX::Types::Moose qw'Str'; 
use MooseX::Types -declare => [qw' 
    Gender ISODate 
']; 

subtype Gender, (
    as Str, 
    where { /^[mf]$/ }, 
); 

subtype ISODate, (
    as Str, 
    where { /^\d\d\d\d-\d\d-\d\d$/ } 
); 
1; 
package Person: 

use MooseX::Types::Moose qw'Str'; 
use Person::TypeConstraints qw'Gender ISODate'; 

use namespace::clean; 
use Moose; 

has gender => (
    is => 'rw', 
    isa => Gender, 
); 
has name => (
    is => 'rw', 
    isa => Str, 
); 
has dateOfBirth => (
    is => 'rw', 
    isa => ISODate, 
); 

no Moose; 
__PACKAGE__->meta->make_immutable; 
1; 
+2

當Moose有一個枚舉類型Constraint對我來說很困惑時,我不得不說對'Str'類型的依賴。 'has gender =>(isa => enum([qw | M m F f |])'=>'ro');'? – perigrin 2011-04-28 20:11:53

+0

我使用'Moose :: Util :: TypeConstraints'結束了,它具有已經安裝在目標系統上的優勢(我不能控制它)。我相信其他建議也很有趣。查看我的初始帖子,我將發佈更新,因爲調用'subtype'的語法與您示例中提供的語法稍有不同。還有'枚舉',我發現派上用場。萬分感謝! – Lumi 2011-04-28 20:11:57

+0

我必須糾正。 Brad的'subtype'語法很好。我通過寫'subtype as =>'Str'來拋出bean,其中=> {...}',這是錯誤的,或者被棄用。這是一個棘手的問題,這個人要比其他屬性修飾符有不同的拼寫。 – Lumi 2011-04-28 20:22:06

3

添加自己的類型像布拉德說:

use Moose::Util::TypeConstraints; 

my $gender_constraint = subtype as 'Str', where { $_ =~ /^[FfMm]$/ }; 
has gender => (is => 'rw', isa => $gender_constraint); 
+0

這是做到這一點的一種方式,但是如果您打算多次使用它,並且只在一個文件中使用它,那麼它纔有意義。如果您計劃對多個文件使用相同的約束,我會推薦使用[MooseX :: Types](http://search.cpan.org/perldoc/MooseX::Types)。 – 2011-04-28 18:13:21

+0

謝謝。儘管Brad似乎並不認同100%,但我認爲存儲和重用'subtype'的返回值是很好的,儘管它可能侷限於這個範圍。也許這就是你的意圖? – Lumi 2011-04-28 20:19:12

+0

@ Michael-Ludwig是的,我經常有像$ abs_int之類的東西在一個類的多個地方使用,所以我覺得它適用於此。 Brad是正確的,如果你在多個文件中使用相同的約束條件,MooseX :: Types是很棒的,並且子類型內聯對單個約束條件很好。 – SymKat 2011-04-28 21:55:17

0

你可以嘗試使用MooseX-Types-Parameterizable實現一個帶參數的情況下,你目前(未經測試,只是草圖)類型:

package YourTypes; 
use MooseX::Types -declare => [qw(OneOfStr MatchingStr)]; 
use MooseX::Types::Moose qw(Str ArrayRef RegexpRef); 

subtype OneOfStr, 
    as Parameterizable[ Str, ArrayRef[ Str ] ], 
    where { 
     my ($str, $allowed) = @_; 
     return scalar grep { $_ eq $str } @$allowed; 
    }; 

subtype MatchingStr, 
    as Parameterizable[ Str, RegexpRef ], 
    where { 
     my ($str, $rx) = @_; 
     return scalar $str =~ $rx; 
    }; 

1; 

你可以像這樣使用它:

use YourTypes qw(OneOfStr MatchingStr); 

has gender => (is => 'ro', isa => OneOfStr[ [qw(f m)] ]); 
has dob => (is => 'ro', isa => MatchingStr[ qr/^$yourregex$/ ]); 
+0

謝謝,我來看看。明天:-) – Lumi 2011-04-28 20:24:57