2017-02-28 30 views
2

문자열을 기준으로 길이를 제한하고 길이를 제한 할 수있는 유형을 만들고 싶습니다. 즉, 길이 범위가 매개 변수가되는 매개 변수가있는 형식입니다. 내 구현에서 원하는 무엇
:Type : Tiny를 사용하는 다른 유형의 매개 변수 유형 : Tiny

  • 문자열 길이 범위에 대한 별도의 유형입니다.
  • 사용하지 MooseX :: 유형 :: 파라미터 화
  • 바로 arrayref와 유형을 parametrizing의 설탕, hashref NOT :
    • 이 : isa=>Varchar[1, 15]
    • 하지 않음이 : isa=>Varchar[{min=>1, max=>15,}]


내가 지금까지 가지고있는 것 :
파일 MyTypesTiny.pm

package MyTypesTiny; 

use strict; 
use warnings; 

use Type::Library 
    -base, 
    -declare => qw(VarcharRange Varchar); 

use Type::Utils -all; 
use Types::Standard -types; 
use MooseX::Types::Common::Numeric qw(PositiveOrZeroInt); 

declare VarcharRange, 
    as HashRef [PositiveOrZeroInt], 
    where { 
    return 0 if (grep { $_ ne 'min' && $_ ne 'max' } keys %{$_}); 
    return ($_->{min} <= $_->{max}) 
     if (defined $_->{max} && defined $_->{min}); 
    return 1; 
    }, message { "$_" }; 

coerce VarcharRange, from ArrayRef [PositiveOrZeroInt], via { 
    my $result; 
    my @keys = qw(min max); 
    foreach my $val (reverse @$_) { 
     my $key = pop @keys // 'bad_range'; 
     $result->{$key} = $val; 
    } 
    return $result; 
}; 

1; 

#!/usr/bin/env perl 

package MyClass; 

use Moose; 
use MyTypesTiny qw(VarcharRange); 

has 'my_range' => (isa=>VarcharRange, is=>'ro', coerce=>1); 

package main; 
use MyClass; 

my $check = MyClass->new( 
    my_range => [1, 15],  # works, as expected 
    # my_range => [1, 0], # fails, as expected 
    # my_range => [0, 1, 2], # fails, as expected 
); 

확인 파일 test_varchar.pl, VarcharRange 작동합니다. 이제 Varchar 자체를 추가해야합니다. 나는 즉시 박히 곳 그리고는 다음과 같습니다
는 MyTypesTiny.pm에 추가 :

declare Varchar, as Str, where {}, constraint_generator => sub { 
    # here I have @_ which is an ArrayRef 
    # and I want to create a VarcharRange object $range from it 
    # but what exactly should I do? 
    return sub { 
     my $len = length($_); 
     return 0 if ($range->{min} && $len < $range->{min}); 
     return 0 if ($range->{max} && $len > $range->{max}); 
     return 1; 
    }; 
}; 

내 뇌가 비등합니다. ArrayRef를 준비했습니다. 필요한 것은 VarcharRange (기본적으로 HashRef) 객체입니다. 그러나 VarcharRange는 유형이며 제한 및 강제 규칙 집합을 표시하는 이름입니다. 그것은 본질적으로 대상과 일치하지 않습니다. 유형에 대한 객체는 클래스 속성을 만들 때 만들어 지지만 여기서 어떤 클래스도 사용하지 않습니다.

+1

포기하지 않으십니까? : D – simbabque

+0

'VarcharRange'와'Varchar' 사이의 연결이 보이지 않습니다. – simbabque

+0

'Varchar' 코드 안에 주석 처리 된 행을 보라. 본질적으로, ArrayRef에 의해'Varchar'를 매개 변수화할 때, 실제로, 두껍게, VarcharRange (ArrayRef로부터 강요받을 수 있습니다)에 의해'Varchar'를 매개 변수화하려고합니다. – Bob

답변

0

그게 내가 끝내 줬어. 여분의 수업을 소개해야했습니다. 그것은 작동하고, 나는 아마 여기에서 멈출 것이다. 문자열 길이 범위에 대한

등급 :

package VarcharRange; 

use strict; 
use warnings; 
use Moose; 
use Moose::Util::TypeConstraints; 

subtype 'AuxRange', as 'HashRef[Int]', where { 
    foreach my $range_id (keys %{$_}) { 
     return 0 if ($range_id ne 'min' && $range_id ne 'max'); 
     return 0 if ($_->{$range_id} < 0); 
    } 
    return ($_->{min} <= $_->{max}) 
     if (defined $_->{max} && defined $_->{min}); 
    return 1; 
}, message { 
    'invalid VarcharRange' 
}; 

coerce 'AuxRange', from 'ArrayRef[Int]', via { 
    my $result; 
    my @keys = qw(min max); 
    foreach my $val (reverse @$_) { 
     my $key = pop @keys // 'bad_range'; 
     $result->{$key} = $val; 
    } 
    return $result; 
}; 

has range => (
    isa  => 'AuxRange', 
    traits => ['Hash'], 
    coerce => 1, 
    handles => { 
     'max' => [ get => 'max' ], 
     'min' => [ get => 'min' ], 
    }, 
); 

1; 

Parametrizable 유형 :

package MyTypesTiny; 

use strict; 
use warnings; 

use Type::Library 
    -base, 
    -declare => qw(Varchar); 

use Type::Utils -all; 
use Types::Standard -types; 

use VarcharRange; 

declare Varchar, as Str, where { 
    1; 
}, inline_as { 
    my ($constraint, $varname) = @_; 
    return $constraint->parent->inline_check($varname); 
}, constraint_generator => sub { 
    my $range = VarcharRange->new(range => \@_); 
    return sub { 
     my $len = length($_); 
     return 0 if ($range->min() && $len < $range->min()); 
     return 0 if ($range->max() && $len > $range->max()); 
     return 1; 
    }; 
}, inline_generator => sub { 
    my $range = VarcharRange->new(range => \@_); 
    return sub { 
     my ($constraint, $varname) = @_; 
     my $check_line; 
     $check_line .= "length('$varname') >= $range->min()" 
      if ($range->min()); 
     if ($range->max()) { 
      $check_line .= ' && ' if ($range->min()); 
      $check_line .= "length('$varname') <= $range->max()"; 
     } 
     return $check_line; 
    }; 
}; 

1; 

그리고 테스트 템플릿과 재생이 :

#!/usr/bin/env perl 

package MyClass; 

use Moose; 
use MyTypesTiny qw(Varchar); 

# Varchar  means no length limitation 
# Varchar[1, 1] means min length is 1, max is 1 
# Varchar[15] means min length is 0, max is 15 
# Varchar[1, 15] means min length is 1, max is 15 

# put your parametrization here 
has 'my_string' => (isa => Varchar [ 9, 10 ], is => 'ro'); 

package main; 
use MyClass; 

# put your test string here 
my $check = MyClass->new(my_string => 'ASDef45F%',); 
0

이것은 당신에게 능력을 제공하는 답변입니다 "Varchar"유형에 매개 변수를 제공합니다. 매개 변수화 된 유형을 사용 가능하게하는 마법은 유형에 constraint_generator을 제공하는 것입니다. 이 솔루션은 중간 hashref가 없으며 하나의 유형 만 있습니다.

MyTypesTiny.pm :

package MyTypesTiny; 

use Types::Standard -all; 
use Type::Library -base, -declare => qw(Varchar); 
use Type::Utils -all; 

sub _get_varchar_args { 
    die "can only give 0-2 parameters" if @_ > 2; 
    map assert_Int($_), @_; 
    return @_ == 1 ? (0, @_) : @_; 
} 

declare "Varchar", 
    as Str, 
    constraint_generator => sub { 
    my ($min_length, $max_length) = _get_varchar_args(@_); 
    return sub { 
     length($_) >= $min_length and length($_) <= $max_length; 
    }; 
    }, 
    inline_generator => sub { 
    my ($min_length, $max_length) = _get_varchar_args(@_); 
    return sub { 
     my ($constraint, $varname) = @_; 
     return sprintf(
     'length(%s) >= %d and length(%s) <= %d', 
     $varname, 
     $min_length, 
     $varname, 
     $max_length, 
    ); 
    }; 
    }; 

1; 

MyClass.pm :

package MyClass; 

use Moo; 
use MyTypesTiny -all; 

has my_string => (
    is => 'ro', 
    isa => Varchar[9, 10], 
); 

1; 

테스터.pl :

#!perl 
use MyClass; 
my $check = MyClass->new(my_string => 'ASDef45F%'); # length 9, ok 
$check = MyClass->new(my_string => 'f45F%'); # length 5, not ok