Skip to content

Commit

Permalink
Add a type_default attribute and provide some type defaults for built…
Browse files Browse the repository at this point in the history
…in types (addresses issue #95)
  • Loading branch information
tobyink committed Aug 30, 2022
1 parent 5ca75e0 commit 90f47a2
Show file tree
Hide file tree
Showing 6 changed files with 211 additions and 7 deletions.
41 changes: 40 additions & 1 deletion lib/Type/Tiny.pm
Original file line number Diff line number Diff line change
Expand Up @@ -558,6 +558,15 @@ sub find_constraining_type {
$self;
}

sub type_default {
my $self = shift;
return $self->{type_default} if exists $self->{type_default};
if ( my $parent = $self->parent ) {
return $parent->type_default if $self->_is_null_constraint;
}
return undef;
}

our @CMP;

sub CMP_SUPERTYPE () { -1 }
Expand Down Expand Up @@ -1038,9 +1047,11 @@ sub is_parameterized {
if $compiled;
$options{inlined} = $self->inline_generator->( @_ )
if $self->has_inline_generator;
$options{type_default} = $self->{type_default_generator}->( @_ )
if exists $self->{type_default_generator}; # undocumented
exists $options{$_} && !defined $options{$_} && delete $options{$_}
for keys %options;

$P = $self->create_child_type( %options );

if ( $self->has_coercion_generator ) {
Expand Down Expand Up @@ -1769,6 +1780,34 @@ The idea is to allow for:
@sorted = Int->sort( 2, 1, 11 ); # => 1, 2, 11
@sorted = Str->sort( 2, 1, 11 ); # => 1, 11, 2
=item C<< type_default >>
A coderef which returns a sensible default value for this type. For example,
for a B<Counter> type, a sensible default might be "0":
my $Size = Type::Tiny->new(
name => 'Size',
parent => Types::Standard::Enum[ qw( XS S M L XL ) ],
type_default => sub { return 'M'; },
);
package Tshirt {
use Moo;
has size => (
is => 'ro',
isa => $Size,
default => $Size->type_default,
);
}
Child types will inherit a type default from their parent unless the child
has a C<constraint>. If a type neither has nor inherits a type default, then
calling C<type_default> will return undef.
Many of the types defined in L<Types::Standard> and other bundled type
libraries have type defaults, but discovering them is left as an exercise
for the reader.
=item C<< my_methods >>
Experimental hashref of additional methods that can be called on the type
Expand Down
5 changes: 5 additions & 0 deletions lib/Types/Common/Numeric.pm
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ $meta->add_type(
constraint => sub { $_ >= 0 },
inlined => sub { undef, qq($_ >= 0) },
message => sub { "Must be a number greater than or equal to zero" },
type_default => sub { return 0; },
);

my ( $pos_int, $posz_int );
Expand Down Expand Up @@ -82,6 +83,7 @@ $meta->add_type(
},
message => sub { "Must be an integer greater than or equal to zero" },
$posz_int ? ( compiled_type_constraint => $posz_int ) : (),
type_default => sub { return 0; },
);

$meta->add_type(
Expand All @@ -98,6 +100,7 @@ $meta->add_type(
constraint => sub { $_ <= 0 },
inlined => sub { undef, qq($_ <= 0) },
message => sub { "Must be a number less than or equal to zero" },
type_default => sub { return 0; },
);

$meta->add_type(
Expand All @@ -114,6 +117,7 @@ $meta->add_type(
constraint => sub { $_ <= 0 },
inlined => sub { undef, qq($_ <= 0) },
message => sub { "Must be an integer less than or equal to zero" },
type_default => sub { return 0; },
);

$meta->add_type(
Expand All @@ -122,6 +126,7 @@ $meta->add_type(
constraint => sub { $_ >= -9 and $_ <= 9 },
inlined => sub { undef, qq($_ >= -9), qq($_ <= 9) },
message => sub { "Must be a single digit" },
type_default => sub { return 0; },
);

for my $base ( qw/Num Int/ ) {
Expand Down
1 change: 1 addition & 0 deletions lib/Types/Common/String.pm
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ $meta->add_type(
constraint => sub { length( $_ ) <= 255 and not /\n/ },
inlined => sub { undef, qq(length($_) <= 255), qq($_ !~ /\\n/) },
message => sub { "Must be a single line of no more than 255 chars" },
type_default => sub { return ''; },
);

$meta->add_type(
Expand Down
39 changes: 33 additions & 6 deletions lib/Types/Standard.pm
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ my $_any = $meta->$add_core_type(
name => "Any",
inlined => sub { "!!1" },
complement_name => 'None',
type_default => sub { return undef; },
}
);

Expand All @@ -233,6 +234,7 @@ my $_bool = $meta->$add_core_type(
inlined => sub {
"!ref $_[1] and (!defined $_[1] or $_[1] eq q() or $_[1] eq '0' or $_[1] eq '1')";
},
type_default => sub { return !!0; },
}
);

Expand All @@ -244,6 +246,7 @@ my $_undef = $meta->$add_core_type(
parent => $_item,
constraint => sub { !defined $_ },
inlined => sub { "!defined($_[1])" },
type_default => sub { return undef; },
}
);

Expand Down Expand Up @@ -276,10 +279,11 @@ my $_str = $meta->$add_core_type(
constraint => sub {
ref( \$_ ) eq 'SCALAR' or ref( \( my $val = $_ ) ) eq 'SCALAR';
},
inlined => sub {
inlined => sub {
"defined($_[1]) and do { ref(\\$_[1]) eq 'SCALAR' or ref(\\(my \$val = $_[1])) eq 'SCALAR' }";
},
sorter => sub { $_[0] cmp $_[1] }
sorter => sub { $_[0] cmp $_[1] },
type_default => sub { return ''; },
}
);

Expand All @@ -296,7 +300,8 @@ my $_laxnum = $meta->add_type(
: "defined($_[1]) && !ref($_[1]) && Scalar::Util::looks_like_number($_[1]) && ref(\\($_[1])) ne 'GLOB'"
);
},
sorter => sub { $_[0] <=> $_[1] }
sorter => sub { $_[0] <=> $_[1] },
type_default => sub { return 0; },
}
);

Expand All @@ -316,7 +321,7 @@ my $_strictnum = $meta->add_type(
\z/x
);
},
inlined => sub {
inlined => sub {
'my $val = '
. $_[1] . ';'
. Value()->inline_check( '$val' )
Expand All @@ -328,7 +333,8 @@ my $_strictnum = $meta->add_type(
(?:[Ee](?:[+-]?[0-9]+))? # matches E1 or e1 or e-1 or e+1 etc
\z/x ); '
},
sorter => sub { $_[0] <=> $_[1] }
sorter => sub { $_[0] <=> $_[1] },
type_default => sub { return 0; },
}
);

Expand All @@ -347,6 +353,7 @@ $meta->$add_core_type(
inlined => sub {
"do { my \$tmp = $_[1]; defined(\$tmp) and !ref(\$tmp) and \$tmp =~ /\\A-?[0-9]+\\z/ }";
},
type_default => sub { return 0; },
}
);

Expand Down Expand Up @@ -436,6 +443,7 @@ $meta->$add_core_type(
? "Ref::Util::XS::is_plain_coderef($_[1])"
: "ref($_[1]) eq 'CODE'";
},
type_default => sub { return sub {}; },
}
);

Expand All @@ -446,13 +454,14 @@ my $_regexp = $meta->$add_core_type(
constraint => sub {
ref( $_ ) && !!re::is_regexp( $_ ) or blessed( $_ ) && $_->isa( 'Regexp' );
},
inlined => sub {
inlined => sub {
my $v = $_[1];
$maybe_load_modules->(
qw/ Scalar::Util re /,
"ref($v) && !!re::is_regexp($v) or Scalar::Util::blessed($v) && $v\->isa('Regexp')"
);
},
type_default => sub { return qr//; },
}
);

Expand Down Expand Up @@ -501,6 +510,11 @@ my $_arr = $meta->$add_core_type(
inline_generator => LazyLoad( ArrayRef => 'inline_generator' ),
deep_explanation => LazyLoad( ArrayRef => 'deep_explanation' ),
coercion_generator => LazyLoad( ArrayRef => 'coercion_generator' ),
type_default => sub { return []; },
type_default_generator => sub {
return $Type::Tiny::parameterize_type->type_default if @_ < 2;
return undef;
},
}
);

Expand All @@ -518,6 +532,11 @@ my $_hash = $meta->$add_core_type(
inline_generator => LazyLoad( HashRef => 'inline_generator' ),
deep_explanation => LazyLoad( HashRef => 'deep_explanation' ),
coercion_generator => LazyLoad( HashRef => 'coercion_generator' ),
type_default => sub { return {}; },
type_default_generator => sub {
return $Type::Tiny::parameterize_type->type_default if @_ < 2;
return undef;
},
my_methods => {
hashref_allows_key => LazyLoad( HashRef => 'hashref_allows_key' ),
hashref_allows_value => LazyLoad( HashRef => 'hashref_allows_value' ),
Expand All @@ -535,6 +554,7 @@ $meta->$add_core_type(
inline_generator => LazyLoad( ScalarRef => 'inline_generator' ),
deep_explanation => LazyLoad( ScalarRef => 'deep_explanation' ),
coercion_generator => LazyLoad( ScalarRef => 'coercion_generator' ),
type_default => sub { my $x; return \$x; },
}
);

Expand Down Expand Up @@ -624,6 +644,10 @@ $meta->$add_core_type(
return unless $param->has_coercion;
return $param->coercion;
},
type_default => sub { return undef; },
type_default_generator => sub {
return $Type::Tiny::parameterize_type->type_default;
},
}
);

Expand All @@ -639,6 +663,9 @@ my $_map = $meta->$add_core_type(
hashref_allows_key => LazyLoad( Map => 'hashref_allows_key' ),
hashref_allows_value => LazyLoad( Map => 'hashref_allows_value' ),
},
type_default_generator => sub {
return $Type::Tiny::parameterize_type->type_default;
},
}
);

Expand Down
5 changes: 5 additions & 0 deletions lib/Types/TypeTiny.pm
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ sub StringLike () {
inlined => sub {
qq/defined($_[1]) && !ref($_[1]) or Scalar::Util::blessed($_[1]) && ${\ +_get_check_overload_sub() }($_[1], q[""])/;
},
type_default => sub { return '' },
);
if ( __XS ) {
my $xsub = Type::Tiny::XS::get_coderef_for( 'StringLike' );
Expand Down Expand Up @@ -207,6 +208,7 @@ sub HashLike (;@) {
inlined => sub {
qq/ref($_[1]) eq q[HASH] or Scalar::Util::blessed($_[1]) && ${\ +_get_check_overload_sub() }($_[1], q[\%{}])/;
},
type_default => sub { return {} },
constraint_generator => sub {
my $param = TypeTiny()->assert_coerce( shift );
my $check = $param->compiled_check;
Expand Down Expand Up @@ -288,6 +290,7 @@ sub ArrayLike (;@) {
inlined => sub {
qq/ref($_[1]) eq q[ARRAY] or Scalar::Util::blessed($_[1]) && ${\ +_get_check_overload_sub() }($_[1], q[\@{}])/;
},
type_default => sub { return [] },
constraint_generator => sub {
my $param = TypeTiny()->assert_coerce( shift );
my $check = $param->compiled_check;
Expand Down Expand Up @@ -372,6 +375,7 @@ sub CodeLike () {
inlined => sub {
qq/ref($_[1]) eq q[CODE] or Scalar::Util::blessed($_[1]) && ${\ +_get_check_overload_sub() }($_[1], q[\&{}])/;
},
type_default => sub { return sub {} },
library => __PACKAGE__,
);
if ( __XS ) {
Expand Down Expand Up @@ -406,6 +410,7 @@ sub TypeTiny () {
my $var = $_[1];
"Scalar::Util::blessed($var) && $var\->isa(q[Type::Tiny])";
},
type_default => sub { require Types::Standard; return Types::Standard::Any() },
library => __PACKAGE__,
_build_coercion => sub {
my $c = shift;
Expand Down

0 comments on commit 90f47a2

Please sign in to comment.