2011-01-17 3 views
0

각 필드마다 유효성 검사 규칙 집합이 다른 일련의 필드가 있습니다.perl 서브 루틴 참조

해시 - 참조의 유효성을 검사하기위한 서브 루틴 참조를 배치했습니다.

현재 내 생성자에 있지만 내 개인 생성자에서 그것을 내 보내고 싶습니다.

나는

sub new { 
my $class = shift; 
my $self = {@_}; 

$class = (ref($class)) ? ref $class : $class; 
bless($self, $class); 

$self->{Validations} = { 
    Field1 => {name => sub{$self->checkField1(@_);},args => [qw(a b c)]} 
    Field2 => {name => sub{$self->checkField2(@_);},args => {key1, val1}} 
.. 
.. 
.. 
.. 
}; 

return $self; 
} 

지금 내 생성자에서 모든 유효성 검사 규칙을 먹고 싶어하고 내 검증을 통해 더 좋은 제어 할 수 있도록 다음과 같은 몇 가지 일을 할 아래로했을 유형 필드를 기반으로 규칙. (몇 가지 규칙이 분야의 한 세트에서 흔히 말해 난 그냥 필드의 값을 덮어 쓰기하여 다른 규칙에 대한 규칙을 덮어 쓸 수 있습니다.)

bless($self, $class); 

    $self->{Validations} = $self->_getValidation($self->{type}); 

    return $self; 
} 
sub _getValidation{ 
    my ($self,$type) = @_; 
    my $validation = { 
    Field1 => {name => sub {$self->checkField1(@_);}, args => {key1 => val1}},}; 

    return $validation; 
} 

하지만 Can't use string ("") as a subroutine ref while "strict refs" in use at...을 얻고 것은 아무도 말해 줄 수 왜 이런 행동이 하위 참조. 내 이름 키를 확인하면 null 또는 하위 {DUMMY}가됩니다.

+0

한가지 더 여기에 추가 할 수있는, 내가 그것을했을 'Field1 => {name => sub {$ self-> checkField1 (@_);} 이런 식으로 언젠가는 개별 필드의 유효성을 검사해야하며'$ obj-> checkField1 ('string', @ args);'더 나은 방법으로 내 접근 방식을 바꿀 준비가되었습니다. – awake416

+0

재미있는 일이 여기에서 발생했는데 아무런 문제없이 작동합니다. 실제로 Field1을 시작하는 키를 정의하고 생성 된 첫 번째 필드는 Field0입니다. (..하지만이 질문은 여전히 ​​더 나은 접근을 위해 열려 있습니다. – awake416

+0

유효성 검사는 속성에 넣는 객체마다 실제로 다릅니 까? 그렇지 않으면'$ self'를 캡처하기 만합니까? 당신이 할 필요가 없기 때문에 ... – hobbs

답변

5

Moose에 대한 재구성에 거의 나빠진 것처럼 보입니다. 비슷한 것을 구축하는 대신 Moose을 사용하는 것이 좋지만 덜 유용합니다.

오류 메시지는 코드에서 코드 참조가 필요한 곳에서 문자열을 전달한다는 것을 의미합니다. 스택 추적을 통해 오류의 출처를 파악합니다.

Carp :: Always를 사용하여 $SIG{__DIE__} 처리기를 재정 의하여 스택 추적을 생성하거나 Carp::confess을 코드에 삽입하여이 작업을 수행 할 수 있습니다.

여기에 sigdie 솔루션, 그것은 당신의 모듈 초기화 전에 실행되는 위치 코드에서이 스틱 :

$SIG{__DIE__} = sub { Carp::confess(@_) }; 

당신은 BEGIN 블록에 넣어해야 할 수도 있습니다.

저는 건물 객체에이 접근법을 사용하지 않으려 고합니다. 당신은 행복하게 개체의 일부로 생성자에 전달 임의의 쓰레기를 축복! 당신은 개체 내부에 blithely reach합니다. 필드 유효성 검사 규칙은 이 아니라이 생성자에 속합니다.이 속성은 특성 변경자에 속합니다.

# Here's a bunch of validators. 
# I set them up so that each attribute supports: 
# Multiple validators per attribute 
# Distinct error message per attribute 
my %VALIDATORS = (

    some_attribute => [ 
     [ sub { 'foo1' }, 'Foo 1 is bad thing' ], 
     [ sub { 'foo2' }, 'Foo 2 is bad thing' ], 
     [ sub { 'foo3' }, 'Foo 3 is bad thing' ], 
    ], 
    other_attribute => [ [ sub { 'bar' }, 'Bar is bad thing' ] ], 

); 


sub new { 
    my $class = shift; # Get the invocant 
    my %args = @_;  # Get named arguments 

    # Do NOT make this a clone method as well 

    my $self = {}; 
    bless $class, $self; 

    # Initialize the object; 
    for my $arg (keys %args) { 

     # Make sure we have a sane error message on a bad argument. 
     croak "Bogus argument $arg not allowed in $class\n" 
      unless $class->can($arg); 

     $self->$arg($args{$arg}); 
    } 

    return $self; 
} 

# Here's an example getter/setter method combined in one. 
# You may prefer to separate get and set behavior. 

sub some_attribute { 
    my $self = shift; 

    if(@_){ 
     my $val = shift; 

     # Do any validation for the field 
     $_->[0]->($val) or croak $_->[1] 
      for @{ $VALIDATORS{some_attribute} || [] }; 

     $self->{some_attribute} = $val; 
    } 

    return $self->{some_attribute}; 

} 

이 모든 코드가 아주 좋은,하지만 당신은 모든 속성에 대한 속성 코드를 반복해야 : 당신이 DIY 객체를 사용해야하는 경우

, 당신의 관행을 정리. 이는 오류가 발생하기 쉬운 상용구 코드가 많이 있음을 의미합니다. 클로저 또는 문자열 평가를 사용하여 메서드를 동적으로 생성하는 방법을 배우거나 Class :: Accessor, Class :: Struct, Accessor :: Tiny 등과 같은 Perl의 많은 클래스 생성 라이브러리 중 하나를 사용할 수 있습니다. .

[무스] [3]을 배울 수 있습니다. Moose는 Perl OOP 연습을 인수 한 새로운 (ish) 객체 라이브러리입니다.그것은 강력한 기능을 제공하며 극적으로 고전 펄 OOP 이상 상용구를 감소 :

use Moose; 

type 'Foo' 
    => as 'Int' 
    => where { 
     $_ > 23 and $_ < 42 
    } 
    => message 'Monkeys flew out my butt'; 

has 'some_attribute' => (
    is => 'rw', 
    isa => 'Foo', 
); 
+0

감사합니다 daotoad, 나는 사슴을 사용하고 싶어 죽어 가고 있지만, 나는이 약간의 진절머리 나는 피할 수없는 제약으로 인해이 프로젝트에서 사용할 수 없다 :-(... – awake416

2

당신이 가진 모든 것을 읽을 수 없습니다,하지만이 나를 강타 : 당신이를 만들 때

sub new { 
    my $class = shift; 
    my $self = {@_}; 

    $class = (ref($class)) ? ref $class : $class; 
    bless($self, $class); 

보통을, 새 개체 인 경우 사용자는 개체 중 하나로 $self을 전달하지 않습니다. 그것이 당신이 만드는 것입니다.

sub new { 
    my $class = shift; #Contains the class 
    my %params = @_;  #What other parameters used 

    my $self = {};  #You're creating the $self object as a reference to something 
    foreach my $param (keys (%params)) { 
     $self->{$param} = $params{$param}; 
    } 

    bless ($self, $class) #Class is provided. You don't have to check for it. 
    return $self #This is the object you created. 
} 

이제 $self 위의 예에서와 같이 해시에 대한 참조가 될 필요가 없습니다 :

당신은 일반적으로 이런 일을 참조하십시오. 배열에 대한 참조 일 수 있습니다. 또는 함수에 대한 것일 수도 있습니다. 그러나 일반적으로 참조입니다. 요점은 사용자가 new 서브 루틴에 의해 생성되기 때문에 사용자가 $self을 전달하지 않는다는 것입니다.

아니요, new 서브 루틴이 호출 될 때 주어지기 때문에 $class의 값을 확인해야합니까?

당신이 (그런데 좋은 생각) 개인 클래스에서 검증을하고 싶은 경우에, 당신은 그래서 bless 후 수행 할 수

sub new { 
    my $class = shift; #Contains the class 
    my %params = @_;  #What other parameters used 

    my $self = {};  #You're creating the $self object as a reference to something 
    foreach my $param (keys (%params)) { 
     $self->{$param} = $params{$param}; 
    } 

    bless ($self, $class) #Class is provided. You don't have to check for it. 

    #Now you can run your verifications since you've blessed the object created 
    if (not $self->_validate_parameters()) { 
     croak qq(Invalid parameters passed in class $class); 
    } 
    return $self #This is the object you created. 
} 
+0

나를 고쳐 주셔서 고마워요.하지만 여기서 요구 사항은 규칙 집합을 가져 오는 것입니다 하나의 매개 변수 유형을 기반으로. 아이디 유형에 대한 숙녀 여러분, 나는 다른 유효성 검사 규칙을 사용하고 싶습니다. – awake416

관련 문제