Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Perl 使用type::Tiny使用另一个类型参数化类型_Perl_Oop_Moose_Coercion - Fatal编程技术网

Perl 使用type::Tiny使用另一个类型参数化类型

Perl 使用type::Tiny使用另一个类型参数化类型,perl,oop,moose,coercion,Perl,Oop,Moose,Coercion,我想基于字符串创建一个类型,它将有长度上限,也可以有长度下限。即参数化类型,其中长度范围将是一个参数。 我在实现中需要什么: 字符串长度范围的单独类型 不使用MooseX::Types::Parameterable 直接使用arrayref而不是hashref参数化类型的一种方法: 这:isa=>Varchar[1,15] 不是这样:isa=>Varchar[{min=>1,max=>15,}] 这就是我目前掌握的情况: 文件MyTypesTiny.pm package MyTypesT

我想基于字符串创建一个类型,它将有长度上限,也可以有长度下限。即参数化类型,其中长度范围将是一个参数。
我在实现中需要什么:

  • 字符串长度范围的单独类型
  • 不使用MooseX::Types::Parameterable
  • 直接使用arrayref而不是hashref参数化类型的一种方法:
    • 这:
      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;
好的,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;
    };
};
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;
将Varchar声明为Str,其中{},constraint_generator=>sub{
#这是一个数组ref
#我想从中创建一个VarcharRange对象$range
#但我到底该怎么办呢?
返回接头{
my$len=长度($\ux);
如果($range->{min}&$len<$range->{min}),则返回0;
如果($range->{max}&$len>$range->{max}),则返回0;
返回1;
};
};

我的大脑沸腾了。我的ArrayRef准备好了。我所需要的只是一个VarcharRange(基本上是一个HashRef)对象。但是VarcharRange是一个类型-一组约束和强制规则的名称标记集。它与对象本身不对应。类型的对象是在创建类属性时创建的,但我在这里没有任何类。

这就是我最终得到的。不得不额外增加一门课。它起作用了,我可能就到此为止

字符串长度范围的类:

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;

这是一个能够为“Varchar”类型提供参数的答案。启用参数化类型的神奇之处在于为类型提供一个
约束\u生成器
。此解决方案没有中间hashref,它只有一种类型

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;
    };
};
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;
tester.pl:

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

你不会放弃吧我看不到
VarcharRange
Varchar
之间的连接。请参阅
Varchar
代码中的注释行。本质上,当我通过ArrayRef参数化
Varchar
时,实际上,我想通过
VarcharRange
参数化
Varchar
(可以从ArrayRef强制)。然后呢?您只想验证字符串是否在该长度范围内?这些类型不是类。他们是典型的。我会这么做的。另外,not Types::Common::String(与Type::Tiny捆绑在一起)包含一个
StrLength
类型,从1.004000版起,该类型就可以实现这一点。
package MyClass;

use Moo;
use MyTypesTiny -all;

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

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