2013-05-27 22 views
7

Za pomocą łosia można utworzyć atrybuty o wartości domyślnej. Mam zestaw atrybutów, które mają minimalną, maksymalną i domyślną wartość. Są to atrybuty reprezentujące skalę (np. Tk :: Scale).Atrybuty Perl Moose z minimalną, maksymalną i domyślną wartością

Obecnie mam przynajmniej 3 atrybuty: prąd & domyślnie:

has 'attr' => (is => 'rw', isa => 'Int', default => 300, lazy => 1, clearer => '_clear_attr'); 

min:

has 'attr_min' => (is => 'rw', isa => Int', default => 100); 

max:

has 'attr_max' => (is => 'rw', isa => Int', default => 1000); 

Czy possioble mieć wszystkie cztery (current, default, min, max) w jednym atrybucie?

Odpowiedz

7

Myślę, że chcesz utworzyć regułę sprawdzania poprawności.

use Moose::Util::TypeConstraints; 

subtype 'ScaleVal', 
    as 'Int', 
    where { 100 <= $_ && $_ <= 1000 }; 

has attr => (
    is  => 'rw', 
    isa  => 'ScaleVal', 
    default => 300, 
); 
+0

To wygląda dobrze. Czy istnieje sposób sprawdzenia atrybutu? Na przykład. uzyskać wartość minimalną, maksymalną i domyślną? – capfan

+1

AFAIK nie z Moose :: Meta :: TypeConstraint. Zamiast tworzenia podtypu można utworzyć klasę pakietu, aby zaaplikować tę funkcję i zawijać podtyp z atrybutami min, max. – snoofkin

+0

@ikegami, proszę, powiedz, gdzie mogę przeczytać o systemie klasy Moose? – gaussblurinc

1

Istnieje oczywiście wiele sposobów, aby połączyć kilka wartości w bardziej złożonej wartości - to w zasadzie co badanie struktur danych na temat. Jakie konkretne struktury danych do wyboru to dość wciągające pytanie, wysoce zależne od rzeczywistych przypadków użycia.

Znam dość mało na temat twojej sprawy, ale to, co wyciągnąłem z twojego pytania, że ​​wszystkie te cechy reprezentują podobnie skonstruowane pojęcia. A więc chciałbym utworzyć nowy typ danych, Scale:

use MooseX::Declare; 
class Scale { 
    for (qw/min max def/) { 
     has $_ => (is => 'ro', isa => 'Num', required => 1); 
    } 
    has val => (is => 'rw', isa => 'Num', lazy_build => 1); 
    method _build_val() { 
     return $self->def; 
    } 
    method BUILD($args) { 
     confess "Out of range!" unless $self->_is_in_range($self->val); 
    } 
    method _is_in_range($val) { 
     return defined $val && $val >= $self->min && $val <= $self->max; 
    } 
    before val ($new_val?) { 
     return unless defined $new_val; 
     confess "Out of range!" unless $self->_is_in_range($new_val); 
    } 
} 

i chciałbym przedstawić na jakimś ThingWithScale atrybuty, które zostały poparte Scale obiektu.

class ThingWithScale { 
    has _attr => (
     is => 'ro', isa => 'Scale', 
     default => sub { shift->_make_attr() }, 
    ); 
    method _make_attr($class: $val?) { 
     return Scale->new(
      min => 100, max => 1000, def => 200, 
      (defined $val ? (val => $val) :()), 
     ) 
    } 
    # Convert `attr` argument to a `Scale` object before passing to real constructor. 
    sub BUILDARGS { 
     my ($class, %args) = @_; 

     if (defined (my $attr = delete $args{attr})) { 
      %args = (
       %args, 
       _attr => $class->_make_attr($attr) 
      ); 
     } 
     return $class->SUPER::BUILDARGS(%args); 
    } 
} 

my $thing = ThingWithScale->new(attr => 101); 

A o czasie pisałem że BUILDARGS sposób, aby automatycznie instancję obiektu skala od prostego parametru konstruktora, to zdaję sobie sprawę, że to, co naprawdę chciałem zrobić, to wymyślić nowy atrybut trait opisać atrybuty miały minimalne i maksymalne wartości prawne.

Powiązane problemy