使用Type :: Tiny参数化类型与另一种类型 [英] Parametrizing type with another type using Type::Tiny

查看:406
本文介绍了使用Type :: Tiny参数化类型与另一种类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想基于字符串创建一个类型,该类型将具有长度上限,并且-可选-长度下限.即参数化类型,其中长度范围将是一个参数.
我想要实现什么:

I want to create a type, based on the string, which will have upper length limit, and - optionally - lower length limit. I.e., parameterized type, where length range would be a parameter.
What I want in my implementation:

  • 字符串长度范围的单独类型.
  • 不使用MooseX :: Types :: Parameterizable
  • 使用arrayref(而不是hashref)直接参数化类型的糖:
    • 此:isa=>Varchar[1, 15]
    • 不是这个:isa=>Varchar[{min=>1, max=>15,}]
    • A separate type for string length range.
    • Not using MooseX::Types::Parameterizable
    • A sugar of parametrizing the type straight with arrayref, NOT hashref:
      • This: isa=>Varchar[1, 15]
      • Not this: isa=>Varchar[{min=>1, max=>15,}]


      这是我到目前为止的内容:
      文件MyTypesTiny.pm


      That's what I have so far:
      File 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;
      

      文件test_varchar.pl

      File test_varchar.pl

      #!/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  
      );
      

      好的,VarcharRange有效. 现在,我必须添加Varchar本身.这就是我立即卡住的地方:
      添加到MyTypesTiny.pm:

      Ok, VarcharRange works. Now I have to add Varchar itself. And that's where I get stuck instantly:
      added to 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是一种类型-名称标记一组约束和强制规则.它本身并不对应于对象.类型的对象是在创建类属性时创建的,但这里没有任何类.

      My brain is boiling. I have my ArrayRef ready. All I need is a VarcharRange (which is basically a HashRef) object to be made from it. But VarcharRange is a type - a name marking set of constraints and coercion rules. It does not correspond to an object per se. Objects for types are created when class attributes are created, but I don't have any class in play here.

      推荐答案

      这是一个答案,使您能够为"Varchar"类型提供参数.启用参数化类型的魔术是为该类型提供constraint_generator.此解决方案没有中间的hashref,只有一种类型.

      This is an answer that gives you the ability to give parameters to the "Varchar" type. The magic that enables parameterised types is to provide a constraint_generator to the type. This solution does not have the intermediate hashref, and it only has one type.

      MyTypesTiny.pm:

      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:

      MyClass.pm:

      package MyClass;
      
      use Moo;
      use MyTypesTiny -all;
      
      has my_string  => (
        is => 'ro',
        isa => Varchar[9, 10],
      );
      
      1;
      

      tester.pl:

      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
      

      这篇关于使用Type :: Tiny参数化类型与另一种类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆