use warnings;
use Carp ();
-use List::MoreUtils qw( all );
+use List::MoreUtils qw( all any );
use Scalar::Util qw( blessed reftype );
use Moose::Exporter;
# type constructors
sub type {
- if ( all { ( reftype($_) || '' ) eq 'CODE' || ! ref $_ } @_ ) {
- # back-compat version, called without sugar
- _create_type_constraint( $_[0], undef, $_[1] );
+ # back-compat version, called without sugar
+ if ( ! any { ( reftype($_) || '' ) eq 'HASH' } @_ ) {
+ return _create_type_constraint( $_[0], undef, $_[1] );
}
- else {
- my $name = shift;
- my %p = map { %{$_} } @_;
+ my $name = shift;
- _create_type_constraint( $name, undef, $p{check}, $p{message}, $p{optimized} );
- }
+ my %p = map { %{$_} } @_;
+
+ return _create_type_constraint( $name, undef, $p{where}, $p{message}, $p{optimize_as} );
}
sub subtype {
my %p = map { %{$_} } @_;
# subtype Str => where { ... };
- if ( ! exists $p{parent} ) {
- $p{parent} = $name;
+ if ( ! exists $p{as} ) {
+ $p{as} = $name;
$name = undef;
}
- _create_type_constraint( $name, $p{parent}, $p{check}, $p{message}, $p{optimized} );
+ return _create_type_constraint( $name, $p{as}, $p{where}, $p{message}, $p{optimize_as} );
}
sub class_type {
_install_type_coercions($type_name, \@coercion_map);
}
-sub as ($) { { parent => $_[0] } }
-sub where (&) { { check => $_[0] } }
-sub message (&) { { message => $_[0] } }
-sub optimize_as (&) { { optimized => $_[0] } }
+sub as ($) { { as => $_[0] } }
+sub where (&) { { where => $_[0] } }
+sub message (&) { { message => $_[0] } }
+sub optimize_as (&) { { optimize_as => $_[0] } }
sub from {@_}
sub via (&) { $_[0] }
For instance, this is how you could use it with
L<Declare::Constraints::Simple> to declare a completely new type.
- type 'HashOfArrayOfObjects'
- => IsHashRef(
+ type 'HashOfArrayOfObjects',
+ {
+ where => IsHashRef(
-keys => HasLength,
- -values => IsArrayRef( IsObject ));
+ -values => IsArrayRef(IsObject)
+ )
+ };
For more examples see the F<t/200_examples/204_example_w_DCS.t>
test file.
This creates a base type, which has no parent.
-Note that calling C<type> I<without> the sugar helpers (C<where>,
-C<message>, etc), is deprecated.
+The C<type> function should either be called with the sugar helpers
+(C<where>, C<message>, etc), or with a name and a hashref of
+parameters:
+
+ type( 'Foo', { where => ..., message => ... } );
+
+The valid hashref keys are C<where>, C<message>, and C<optimize_as>.
=item B<subtype 'Name' => as 'Parent' => where { } ...>
If you provide a parent that Moose does not recognize, it will
automatically create a new class type constraint for this name.
-Note that calling C<subtype> I<without> the sugar helpers (C<where>,
-C<message>, etc), is deprecated.
+When creating a named type, the C<subtype> function should either be
+called with the sugar helpers (C<where>, C<message>, etc), or with a
+name and a hashref of parameters:
+
+ subtype( 'Foo', { where => ..., message => ... } );
+
+The valid hashref keys are C<as> (the parent), C<where>, C<message>,
+and C<optimize_as>.
=item B<subtype as 'Parent' => where { } ...>
constraint meta-object, which will be an instance of
L<Moose::Meta::TypeConstraint>.
+When creating an anonymous type, the C<subtype> function should either
+be called with the sugar helpers (C<where>, C<message>, etc), or with
+just a hashref of parameters:
+
+ subtype( { where => ..., message => ... } );
+
=item B<class_type ($class, ?$options)>
Creates a new subtype of C<Object> with the name C<$class> and the
use strict;
use warnings;
-use Test::More tests => 73;
+use Test::More tests => 84;
use Test::Exception;
use Scalar::Util ();
ok( $subtype->has_message, 'subtype does have a message' );
}
+# alternative sugar-less calling style which is documented as legit:
+{
+ my $subtype = subtype( 'MyStr', { as => 'Str' } );
+ isa_ok( $subtype, 'Moose::Meta::TypeConstraint', 'got a subtype' );
+ is( $subtype->name, 'MyStr', 'name is MyStr' );
+ is( $subtype->parent->name, 'Str', 'parent is Str' );
+}
+
+{
+ my $subtype = subtype( { as => 'Str' } );
+ isa_ok( $subtype, 'Moose::Meta::TypeConstraint', 'got a subtype' );
+ is( $subtype->name, '__ANON__', 'name is __ANON__' );
+ is( $subtype->parent->name, 'Str', 'parent is Str' );
+}
+
+{
+ my $subtype = subtype( { as => 'Str', where => sub { /X/ } } );
+ isa_ok( $subtype, 'Moose::Meta::TypeConstraint', 'got a subtype' );
+ is( $subtype->name, '__ANON__', 'name is __ANON__' );
+ is( $subtype->parent->name, 'Str', 'parent is Str' );
+ ok( $subtype->check('FooX'), 'constraint accepts FooX' );
+ ok( ! $subtype->check('Foo'), 'constraint reject Foo' );
+}
+
+
# Back-compat for being called without sugar. Previously, calling with
# sugar was indistinguishable from calling directly.