I'm unsuccessfully trying to create a type _Varchar which would use another type _VarcharRange as a parameter. _VarcharRange, in turn, can be coerced from one of the Moose base types.
Let me start with _Varchar_Range as an example
package MyTypes;
use strict;
use warnings;
use Moose;
use MooseX::Types::Moose qw(Str Int ArrayRef HashRef);
use MooseX::Types::Common::Numeric qw( PositiveOrZeroInt );
use MooseX::Types::Parameterizable qw(Parameterizable);
use MooseX::Types -declare=>[qw(_VarcharRange)];
subtype _VarcharRange,
as HashRef[PositiveOrZeroInt], # Must ask for it from MooseX
where {
return 0 if ( grep {$_ ne 'min' && $_ ne 'max' } keys %{$_});
return ( $_->{min} <= $_->{max} ) if ( defined $_->{max} && defined $_->{min} );
return 1;
},
message {"Trololo"};
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;
};
has 'my_range' => ( isa => _VarcharRange, is => 'ro', coerce => 1 );
1;
And the corresponding test file:
!/usr/bin/env perl
use MyTypes qw(_VarcharRange);
my $check = MyTypes->new(
#my_range => [5, 10], # works fine
#my_range => [1, 0], # fails, as expected
#my_range => [0, 1, 2], # fails, as expected
#my_range => [10], # works fine
);
So far so good, but now I try to add a type _Varchar parameterizable by _VarcharRange. Adding it to MyTypes.pm:
subtype _Varchar,
as Parameterizable[Str, _VarcharRange],
where {
my ( $string, $range ) = @_;
my $len = length($string);
return 0 if ($range->{min} && $len < $range->{min});
return 0 if ($range->{max} && $len > $range->{max});
return 1;
},
message { "'$_[0]' length is not within range $_[1]->{min} - $_[1]->{max}" };
has 'my_string' => ( isa => _Varchar[ [1, 10] ], is => 'ro' );
And this does not work.
What I expected is that _VarcharRange would be implicitly created by coercion from [1, 10] array reference. But looks like my code does not even proceed to creating _VarcharRange, since I'm trying to parameterize my _Varchar directly with ArrayRef.
Is there a way to achieve what I want? Pass an array reference as a parameter, but have intermediate type _VarcharRange coerced from it and actually be used for parameterization.
I don't want to parameterize _Varchar directly from ArrayRef because it is not very object-oriented. It feels like having an independent type for a range is the correct way.