MooX-Types-MooseLike-0.25/000075500000000000000000000000001217715246600153225ustar00rootroot00000000000000MooX-Types-MooseLike-0.25/.gitignore000064400000000000000000000003271217715246600173140ustar00rootroot00000000000000.includepath .project .build MooX-Types-MooseLike-* MANIFEST MANIFEST.bak META.* MYMETA.* Makefile Makefile.old README blib/ pm_to_blib Distar/ .tidyall.d/ # yes that's right, distar makes it for us MANIFEST.SKIP MooX-Types-MooseLike-0.25/Changes000064400000000000000000000076521217715246600166270ustar00rootroot000000000000000.25 - 2013-07-29 - Don't trigger bool overrides when checking for object instance type [RT#87382] (Mithaldu) - Make Moo a build dep. instead of run dep. 0.24 - 2013-07-10 - Upgrade Num test, keep in sync w/ Moose (autarch) - Improve documentation 0.23 - 2013-03-07 - Fix regression in subtypes defined with a string (for the parent test) 0.22 - 2013-03-04 - Allow subtyping of parameterized types (haarg) - Extract SetObject and Numeric types into their own distributions 0.21 - 2013-02-16 - Allow type libraries more control over inflation to Moose types (tobyink) 0.20 - 2013-02-11 - Improve documentation 0.19 - 2013-02-10 - New type: Enum 0.18 - 2013-02-09 - AnyOf now supports parameterized types API CHANGE: AnyOf no longer takes types in a string This means you should write: AnyOf[Int, CodeRef] instead of: AnyOf['Int', 'CodeRef'] - New type: AllOf (intersection of defined types) - Simplify new make_type() code (haarg) 0.17 - 2013-02-08 - New type: AnyOf (union of defined types) 0.16 - 2012-10-11 - Handle undef with grace (github issues 13 and 14) - Improve POD for: InstanceOf, ConsumerOf, HasMethods - Restrict ConsumerOf and HasMethods to something blessed (i.e. an instance) - Bump Moo requirements (better role composition and isa builder check) 0.15 - 2012-09-28 - Relax InstanceOf definition to use isa() 0.14 - 2012-09-19 - Remove pesky Set::Object from build requirements 0.13 - 2012-09-18 - Only test SetObject when Set::Object is already installed 0.12 - 2012-09-11 Release Name: Independence for Catalunya - Improve POD - Add testing dependency - Correct SetObject - Enable ConsumerOf to accept multiple roles 0.11 - 2012-09-10 - Generalize parameterizable (fREW) - Rework type string arguments to follow ['Str'] pattern (mattp) - New types: InstanceOf, ConsumerOf and HasMethods 0.10 - 2012-08-26 - Allow Type() arguments (mattp) - Improve error handling for parameterized types (mattp) - Improve documentation 0.09 - 2012-07-23 - Preserve attribute properties defined after 'isa' [github issue #7] Failing tests (xsawyerx) 0.08 - 2012-07-03 - Support for parameterized type: Maybe For example, isa => Maybe[Int] 0.07 - 2012-06-29 - Support for parameterized types: ArrayRef, HashRef, ScalarRef This means one can now write: isa => ArrayRef[HashRef] 0.06 - 2012-06-27 - Make subtype use full test [RT#78074] (SineSwiper) - Correct SingleDigit type definition [RT#78074] (SineSwiper) - Add Stack Trace on Exception [RT#77583] (Mithaldu) 0.05 - 2012-05-16 - Add Deps [RT#77225] (SymKat) - Add META (SineSwiper) 0.04 - 2012-04-27 ADDITIONS: * Add support for Moo type inflation to Moose (mst) API CHANGE: * Numeric types equivalent to MooseX::Type::Common::Numeric 0.03 - 2012-03-19 IMPROVEMENTS: * Bunches of POD [RT#73519] * Simplified Exporter usage [RT#75209] (dolmen) * Removed Data::Dumper::Concise dependency [RT#73469] (rsimoes) ADDITIONS: * Numeric Types * Experimental type building API API CHANGE: * Basic types are now found in MooX::Types::MooseLike::Base instead of MooX::Types::MooseLike 0.02 - 2011-10-21 ADDITIONS: * Most non-parameterized types of the basic Moose type hierarchy are now supported. Exceptions are ClassName and RoleName * Ability to re-use the type tests to build new ones via is_$type() IMPROVEMENTS: * Refactored generation of assert_Foo() to use a dispatch table and captures for quote_sub. FIXES: * Add AutoPrereq to dist.ini so Makefile.PL gets dependencies generated 0.01 - 2011-09-15 Initial Release MooX-Types-MooseLike-0.25/Makefile.PL000064400000000000000000000013641217715246600173000ustar00rootroot00000000000000use strict; use warnings FATAL => 'all'; use 5.008001; use ExtUtils::MakeMaker; (do 'maint/Makefile.PL.include' or die $@) unless -f 'META.yml'; my %RUN_DEPS = ( 'Module::Runtime' => 0.012, ); my %BUILD_DEPS = ( 'Moo' => 0.091010, 'Test::More' => 0.96, 'Test::Fatal' => 0.003, ); WriteMakefile( NAME => 'MooX::Types::MooseLike', VERSION_FROM => 'lib/MooX/Types/MooseLike.pm', PREREQ_PM => { %RUN_DEPS, }, BUILD_REQUIRES => { %BUILD_DEPS, }, META_ADD => { resources => { repository => 'git://github.com/mateu/MooX-Types-MooseLike.git', bugtracker => 'http://rt.cpan.org/NoAuth/Bugs.html?Dist=MooX-Types-MooseLike', IRC => 'irc://irc.perl.org/#web-simple', }, }, LICENSE => 'perl', ); MooX-Types-MooseLike-0.25/lib/000075500000000000000000000000001217715246600160705ustar00rootroot00000000000000MooX-Types-MooseLike-0.25/lib/MooX/000075500000000000000000000000001217715246600167525ustar00rootroot00000000000000MooX-Types-MooseLike-0.25/lib/MooX/Types/000075500000000000000000000000001217715246600200565ustar00rootroot00000000000000MooX-Types-MooseLike-0.25/lib/MooX/Types/MooseLike.pm000064400000000000000000000157331217715246600223140ustar00rootroot00000000000000package MooX::Types::MooseLike; use strict; use warnings FATAL => 'all'; use Exporter 5.57 'import'; our @EXPORT_OK; push @EXPORT_OK, qw( exception_message inflate_type ); use Module::Runtime qw(require_module); use Carp qw(confess croak); use List::Util qw(first); our $VERSION = '0.25'; sub register_types { my ($type_definitions, $into, $moose_namespace) = @_; foreach my $type_def (@{$type_definitions}) { my $coderefs = make_type($type_def, $moose_namespace); install_type($type_def->{name}, $coderefs, $into); } return; } sub install_type { my ($type_name, $coderefs, $namespace) = @_; my $is_type_name = 'is_' . $type_name; my $type_full_name = $namespace . '::' . $type_name; my $is_type_full_name = $namespace . '::' . $is_type_name; { no strict 'refs'; ## no critic qw(TestingAndDebugging::ProhibitNoStrict) *{$type_full_name} = $coderefs->{type}; *{$is_type_full_name} = $coderefs->{is_type}; push @{"${namespace}::EXPORT_OK"}, $type_name, $is_type_name; } return; } sub make_type { my ($type_definition, $moose_namespace) = @_; my $test = $type_definition->{test}; if (my $subtype_of = $type_definition->{subtype_of}) { if (!ref $subtype_of) { my $from = $type_definition->{from} || croak "Must define a 'from' namespace for the parent type: $subtype_of when defining type: $type_definition->{name}"; $subtype_of = do { no strict 'refs'; &{$from . '::' . $subtype_of}(); }; } # Assume a (base) test always exists even if you must write: test => sub {1} my $base_test = $test; $test = sub { my $value = shift; local $@; eval { $subtype_of->($value); 1 } or return; # TODO implement: eval { $base_test->($value); 1 } paradigm if ($base_test) { $base_test->($value) or return; } return 1; }; } my $isa = sub { return if $test->(@_); local $Carp::Internal{"MooX::Types::MooseLike"} = 1; ## no critic qw(Variables::ProhibitPackageVars) confess $type_definition->{message}->(@_) ; ## no critic qw(ErrorHandling::RequireUseOfExceptions) }; if (ref $type_definition->{inflate}) { $Moo::HandleMoose::TYPE_MAP{$isa} = $type_definition->{inflate}; } elsif (exists $type_definition->{inflate} and not $type_definition->{inflate}) { # no-op } else { my $full_name = defined $moose_namespace ? "${moose_namespace}::" . $type_definition->{name} : $type_definition->{name}; $Moo::HandleMoose::TYPE_MAP{$isa} = sub { require_module($moose_namespace) if $moose_namespace; Moose::Util::TypeConstraints::find_type_constraint($full_name); }; } return { type => sub { # If we have a parameterized type then we want to check its values if (ref($_[0]) eq 'ARRAY') { my @params = @{$_[0]}; my $parameterized_isa = sub { # Types that take other types as a parameter have a parameterizable # part with the one exception: 'AnyOf' if (my $parameterizer = $type_definition->{parameterizable}) { # Can we assume @params is a list of coderefs? if(my $culprit = first { (ref($_) ne 'CODE') } @params) { croak "Expect all parameters to be coderefs, but found: $culprit"; } # Check the containing type. We could pass @_, but it is such that: # scalar @_ = 1 always in this context. In other words, # an $isa only type checks one thing at a time. $isa->($_[0]); # Run the nested type coderefs on each value foreach my $coderef (@params) { foreach my $value ($parameterizer->($_[0])) { $coderef->($value); } } } else { # Note that while $isa only checks on value at a time # We can pass it additional parameters as we do here. # These additional parameters are then used in the type definition # For example, see InstanceOf $isa->($_[0], @params); } }; if (ref $type_definition->{inflate}) { my $inflation = $type_definition->{inflate}; $Moo::HandleMoose::TYPE_MAP{$parameterized_isa} = sub { $inflation->(\@params) }; } # Remove old $isa, but return the rest of the arguments # so any specs defined after 'isa' don't get lost shift; return ($parameterized_isa, @_); } else { return $isa; } }, is_type => sub { $test->(@_) }, }; } sub exception_message { my ($attribute_value, $type) = @_; $attribute_value = defined $attribute_value ? $attribute_value : 'undef'; return "${attribute_value} is not ${type}!"; } sub inflate_type { my $coderef = shift; if (my $inflator = $Moo::HandleMoose::TYPE_MAP{$coderef}) { return $inflator->(); } return Moose::Meta::TypeConstraint->new( constraint => sub { eval { &$coderef; 1 } } ); } 1; __END__ =head1 NAME MooX::Types::MooseLike - some Moosish types and a type builder =head1 SYNOPSIS package MyApp::Types; use MooX::Types::MooseLike; use base qw(Exporter); our @EXPORT_OK = (); # Define some types my $defs = [{ name => 'MyType', test => sub { predicate($_[0]) }, message => sub { "$_[0] is not the type we want!" } }, { name => 'VarChar', test => sub { my ($value, $param) = @_; length($value) <= $param; }, message => sub { "$_[0] is too large! It should be less than or equal to $_[1]." } }]; # Make the types available - this adds them to @EXPORT_OK automatically. MooX::Types::MooseLike::register_types($defs, __PACKAGE__); ... # Somewhere in code that uses the type package MyApp::Foo; use Moo; use MyApp::Types qw(MyType VarChar); has attribute => ( is => 'ro', isa => MyType, ); has string => ( is => 'ro', isa => VarChar[25] ); =head1 DESCRIPTION See L for a list of available base types. Its source also provides an example of how to build base types, along with both parameterizable and non-parameterizable. See L for an example of how to build subtypes. See L for an example of how to build parameterized types. =head1 AUTHOR mateu - Mateu X. Hunter (cpan:MATEU) =head1 CONTRIBUTORS mst - Matt S. Trout (cpan:MSTROUT) Mithaldu - Christian Walde (cpan:MITHALDU) Matt Phillips (cpan:MATTP) Arthur Axel fREW Schmidt (cpan:FREW) Toby Inkster (cpan:TOBYINK) Graham Knop (cpan:HAARG) =head1 COPYRIGHT Copyright (c) 2011-2013 the MooX::Types::MooseLike L and L as listed above. =head1 LICENSE This library is free software and may be distributed under the same terms as perl itself. =cut MooX-Types-MooseLike-0.25/lib/MooX/Types/MooseLike/000075500000000000000000000000001217715246600217455ustar00rootroot00000000000000MooX-Types-MooseLike-0.25/lib/MooX/Types/MooseLike/Base.pm000064400000000000000000000411511217715246600231570ustar00rootroot00000000000000package MooX::Types::MooseLike::Base; use strict; use warnings FATAL => 'all'; use Scalar::Util qw(blessed); use List::Util; use MooX::Types::MooseLike qw( exception_message inflate_type ); use Exporter 5.57 'import'; our @EXPORT_OK = (); our $VERSION = 0.25; # These types act like those found in Moose::Util::TypeConstraints. # Generally speaking, the same test is used. sub some_basic_type_definitions { return ( { name => 'Any', test => sub { 1 }, message => sub { "If you get here you've achieved the impossible, congrats." } }, { name => 'Item', test => sub { 1 }, message => sub { "If you get here you've achieved the impossible, congrats" } }, { name => 'Bool', # test => sub { $_[0] == 0 || $_[0] == 1 }, test => sub { !defined($_[0]) || $_[0] eq "" || "$_[0]" eq '1' || "$_[0]" eq '0'; }, message => sub { return exception_message($_[0], 'a Boolean') }, }, # Maybe has no test for itself, rather only the parameter type does { name => 'Maybe', test => sub { 1 }, message => sub { 'Maybe only uses its parameterized type message' }, parameterizable => sub { return if (not defined $_[0]); $_[0] }, }, { name => 'Undef', test => sub { !defined($_[0]) }, message => sub { return exception_message($_[0], 'undef') }, }, ); } sub defined_type_definitions { return ({ name => 'Defined', test => sub { defined($_[0]) }, message => sub { return exception_message($_[0], 'defined') }, }, { name => 'Value', test => sub { defined $_[0] and not ref($_[0]) }, message => sub { return exception_message($_[0], 'a value') }, }, { name => 'Str', test => sub { defined $_[0] and (ref(\$_[0]) eq 'SCALAR') }, message => sub { return exception_message($_[0], 'a string') }, }, { name => 'Num', test => sub { my $val = $_[0]; defined $val and ($val =~ /\A[+-]?[0-9]+\z/) || ( $val =~ /\A(?:[+-]?) # matches optional +- in the beginning (?=[0-9]|\.[0-9]) # matches previous +- only if there is something like 3 or .3 [0-9]* # matches 0-9 zero or more times (?:\.[0-9]+)? # matches optional .89 or nothing (?:[Ee](?:[+-]?[0-9]+))? # matches E1 or e1 or e-1 or e+1 etc \z/x ); }, message => sub { my $nbr = shift; if (not defined $nbr) { $nbr = 'undef'; } elsif (not (length $nbr)) { $nbr = 'The empty string'; } return exception_message($nbr, 'a number'); }, }, { name => 'Int', test => sub { defined $_[0] and ("$_[0]" =~ /^-?[0-9]+$/x) }, message => sub { my $nbr = shift; if (not defined $nbr) { $nbr = 'undef'; } elsif (not (length $nbr)) { $nbr = 'The empty string'; } return exception_message($nbr, 'an integer'); }, }, ); } sub ref_type_definitions { return ( { name => 'Ref', test => sub { defined $_[0] and ref($_[0]) }, message => sub { return exception_message($_[0], 'a reference') }, }, { name => 'ScalarRef', test => sub { defined $_[0] and ref($_[0]) eq 'SCALAR' }, message => sub { return exception_message($_[0], 'a ScalarRef') }, parameterizable => sub { ${ $_[0] } }, inflate => sub { require Moose::Util::TypeConstraints; if (my $params = shift) { return Moose::Util::TypeConstraints::_create_parameterized_type_constraint( Moose::Util::TypeConstraints::find_type_constraint('ScalarRef'), inflate_type(@$params), ); } return Moose::Util::TypeConstraints::find_type_constraint('ScalarRef'); }, }, { name => 'ArrayRef', test => sub { defined $_[0] and ref($_[0]) eq 'ARRAY' }, message => sub { return exception_message($_[0], 'an ArrayRef') }, parameterizable => sub { @{ $_[0] } }, inflate => sub { require Moose::Util::TypeConstraints; if (my $params = shift) { return Moose::Util::TypeConstraints::_create_parameterized_type_constraint( Moose::Util::TypeConstraints::find_type_constraint('ArrayRef'), inflate_type(@$params), ); } return Moose::Util::TypeConstraints::find_type_constraint('ArrayRef'); }, }, { name => 'HashRef', test => sub { defined $_[0] and ref($_[0]) eq 'HASH' }, message => sub { return exception_message($_[0], 'a HashRef') }, parameterizable => sub { values %{ $_[0] } }, inflate => sub { require Moose::Util::TypeConstraints; if (my $params = shift) { return Moose::Util::TypeConstraints::_create_parameterized_type_constraint( Moose::Util::TypeConstraints::find_type_constraint('HashRef'), inflate_type(@$params), ); } return Moose::Util::TypeConstraints::find_type_constraint('HashRef'); }, }, { name => 'CodeRef', test => sub { defined $_[0] and ref($_[0]) eq 'CODE' }, message => sub { return exception_message($_[0], 'a CodeRef') }, }, { name => 'RegexpRef', test => sub { defined $_[0] and ref($_[0]) eq 'Regexp' }, message => sub { return exception_message($_[0], 'a RegexpRef') }, }, { name => 'GlobRef', test => sub { defined $_[0] and ref($_[0]) eq 'GLOB' }, message => sub { return exception_message($_[0], 'a GlobRef') }, }, ); } sub filehandle_type_definitions { return ( { name => 'FileHandle', test => sub { defined $_[0] and Scalar::Util::openhandle($_[0]) or (blessed($_[0]) && $_[0]->isa("IO::Handle")); }, message => sub { return exception_message($_[0], 'a FileHandle') }, }, ); } sub blessed_type_definitions {## no critic qw(Subroutines::ProhibitExcessComplexity) return ( { name => 'Object', test => sub { defined $_[0] and blessed($_[0]) and blessed($_[0]) ne 'Regexp' }, message => sub { return exception_message($_[0], 'an Object') }, }, { name => 'InstanceOf', test => sub { my ($instance, @classes) = (shift, @_); return if not defined $instance; return if not blessed($instance); my @missing_classes = grep { !$instance->isa($_) } @classes; return (scalar @missing_classes ? 0 : 1); }, message => sub { my $instance = shift; return "No instance given" if not defined $instance; return "$instance is not blessed" if not blessed($instance); my @missing_classes = grep { !$instance->isa($_) } @_; my $s = (scalar @missing_classes) > 1 ? 'es' : ''; my $missing_classes = join ' ', @missing_classes; return "$instance is not an instance of the class${s}: $missing_classes"; }, inflate => sub { require Moose::Meta::TypeConstraint::Class; if (my $classes = shift) { if (@$classes == 1) { return Moose::Meta::TypeConstraint::Class->new(class => @$classes); } elsif (@$classes > 1) { return Moose::Meta::TypeConstraint->new( parent => Moose::Util::TypeConstraints::find_type_constraint('Object'), constraint => sub { my $instance = shift; my @missing_classes = grep { !$instance->isa($_) } @$classes; return (scalar @missing_classes ? 0 : 1); }, ); } } return Moose::Util::TypeConstraints::find_type_constraint('Object'); }, }, { name => 'ConsumerOf', test => sub { my ($instance, @roles) = (shift, @_); return if not defined $instance; return if not blessed($instance); return if (!$instance->can('does')); my @missing_roles = grep { !$instance->does($_) } @roles; return (scalar @missing_roles ? 0 : 1); }, message => sub { my $instance = shift; return "No instance given" if not defined $instance; return "$instance is not blessed" if not blessed($instance); return "$instance is not a consumer of roles" if (!$instance->can('does')); my @missing_roles = grep { !$instance->does($_) } @_; my $s = (scalar @missing_roles) > 1 ? 's' : ''; my $missing_roles = join ' ', @missing_roles; return "$instance does not consume the required role${s}: $missing_roles"; }, inflate => sub { require Moose::Meta::TypeConstraint::Role; if (my $roles = shift) { if (@$roles == 1) { return Moose::Meta::TypeConstraint::Role->new(role => @$roles); } elsif (@$roles > 1) { return Moose::Meta::TypeConstraint->new( parent => Moose::Util::TypeConstraints::find_type_constraint('Object'), constraint => sub { my $instance = shift; return if (!$instance->can('does')); my @missing_roles = grep { !$instance->does($_) } @$roles; return (scalar @missing_roles ? 0 : 1); }, ); } } return Moose::Util::TypeConstraints::find_type_constraint('Object'); }, }, { name => 'HasMethods', test => sub { my ($instance, @methods) = (shift, @_); return if not defined $instance; return if not blessed($instance); my @missing_methods = grep { !$instance->can($_) } @methods; return (scalar @missing_methods ? 0 : 1); }, message => sub { my $instance = shift; return "No instance given" if not defined $instance; return "$instance is not blessed" if not blessed($instance); my @missing_methods = grep { !$instance->can($_) } @_; my $s = (scalar @missing_methods) > 1 ? 's' : ''; my $missing_methods = join ' ', @missing_methods; return "$instance does not have the required method${s}: $missing_methods"; }, inflate => sub { require Moose::Meta::TypeConstraint::DuckType; if (my $methods = shift) { return Moose::Meta::TypeConstraint::DuckType->new(methods => $methods); } return Moose::Util::TypeConstraints::find_type_constraint('Object'); }, }, { name => 'Enum', test => sub { my ($value, @possible_values) = @_; return if not defined $value; return List::Util::first { $value eq $_ } @possible_values; }, message => sub { my ($value, @possible_values) = @_; my $possible_values = join(', ', @possible_values); return exception_message($value, "any of the possible values: ${possible_values}"); }, inflate => sub { require Moose::Meta::TypeConstraint::Enum; if (my $possible_values = shift) { return Moose::Meta::TypeConstraint::Enum->new(values => $possible_values); } die "Enum cannot be inflated to a Moose type without any possible values"; }, }, ); } sub logic_type_definitions { return ( { name => 'AnyOf', test => sub { my ($value, @types) = @_; foreach my $type (@types) { return 1 if (eval {$type->($value); 1;}); } return; }, message => sub { return exception_message($_[0], 'any of the types') }, inflate => sub { require Moose::Meta::TypeConstraint::Union; if (my $types = shift) { return Moose::Meta::TypeConstraint::Union->new( type_constraints => [ map inflate_type($_), @$types ], ); } die "AnyOf cannot be inflated to a Moose type without any possible types"; }, }, { name => 'AllOf', test => sub { return 1; }, message => sub { 'AllOf only uses its parameterized type messages' }, parameterizable => sub { $_[0] }, inflate => 0, }, ); } sub type_definitions { return [ some_basic_type_definitions() ,defined_type_definitions() ,ref_type_definitions() ,filehandle_type_definitions() ,blessed_type_definitions() ,logic_type_definitions() ]; } MooX::Types::MooseLike::register_types(type_definitions(), __PACKAGE__); # Export an 'all' tag so one can easily import all types like so: # use MooX::Types::MooseLike::Base qw(:all) our %EXPORT_TAGS = ('all' => \@EXPORT_OK); 1; __END__ =head1 NAME MooX::Types::MooseLike::Base - Moose like types for Moo =head1 SYNOPSIS package MyPackage; use Moo; use MooX::Types::MooseLike::Base qw(:all); has "beers_by_day_of_week" => ( isa => HashRef ); has "current_BAC" => ( isa => Num ); # Also supporting is_$type. For example, is_Int() can be used as follows has 'legal_age' => ( is => 'ro', isa => sub { die "$_[0] is not of legal age" unless (is_Int($_[0]) && $_[0] > 17) }, ); =head1 DESCRIPTION Moo attributes (like Moose) have an 'isa' property. This module provides some basic types for this property. One can import all types with ':all' tag or import a list of types like: use MooX::Types::MooseLike::Base qw/HashRef ArrayRef/; so one could then declare some attributtes like: has 'contact' => ( is => 'ro', isa => HashRef, ); has 'guest_list' => ( is => 'ro', isa => ArrayRef[HashRef], ); These types provide a check that the I attribute is a C reference, and that the I is an C references. =head1 TYPES (1st class functions - return a coderef) =head2 Any Any type (test is always true) =head2 Item Synonymous with Any type =head2 Undef A type that is not defined =head2 Defined A type that is defined =head2 Bool A boolean 1|0 type =head2 Value A non-reference type =head2 Ref A reference type =head2 Str A non-reference type where a reference to it is a SCALAR =head2 Num A number type =head2 Int An integer type =head2 ArrayRef An ArrayRef (ARRAY) type =head2 HashRef A HashRef (HASH) type =head2 CodeRef A CodeRef (CODE) type =head2 RegexpRef A regular expression reference type =head2 GlobRef A glob reference type =head2 FileHandle A type that is either a builtin perl filehandle or an IO::Handle object =head2 Object A type that is an object (think blessed) =head1 PARAMETERIZED TYPES =head2 Parameterizing Types With a Single Type The following types can be parameterized with other types. =head3 ArrayRef For example, ArrayRef[HashRef] =head3 HashRef =head3 ScalarRef =head3 Maybe For example, Maybe[Int] would be an integer or undef =head2 Parameterizing Types With Multiple Types =head3 AnyOf Check if the attribute is any of the listed types (think union). Takes a list of types as the argument, for example: isa => AnyOf[Int, ArrayRef[Int], HashRef[Int]] Note: AnyOf is passed an ArrayRef[CodeRef] =head3 AllOf Check if the attribute is all of the listed types (think intersection) Takes a list of types as the argument. For example: isa => AllOf[ InstanceOf['Human'], ConsumerOf['Air'], HasMethods['breath', 'dance'] ], =head2 Parameterizing Types With (Multiple) Strings In addition, we have some parameterized types that take string arguments. =head3 InstanceOf Check if the attribute is an object instance of one or more classes. Uses C and C to do so. Takes a list of class names as the argument. For example: isa => InstanceOf['MyClass','MyOtherClass'] Note: InstanceOf is passed an ArrayRef[Str] =head3 ConsumerOf Check if the attribute is blessed and consumes one or more roles. Uses C and C to do so. Takes a list of role names as the arguments. For example: isa => ConsumerOf['My::Role', 'My::AnotherRole'] =head3 HasMethods Check if the attribute is blessed and has one or more methods. Uses C and C to do so. Takes a list of method names as the arguments. For example: isa => HasMethods[qw/postulate contemplate liberate/] =head3 Enum Check if the attribute is one of the enumerated strings. Takes a list of possible string values. For example: isa => Enum['rock', 'spock', 'paper', 'lizard', 'scissors'] =head1 AUTHOR Mateu Hunter C =head1 THANKS mst has provided critical guidance on the design =head1 COPYRIGHT Copyright 2011-2013 Mateu Hunter =head1 LICENSE You may distribute this code under the same terms as Perl itself. =cut MooX-Types-MooseLike-0.25/maint/000075500000000000000000000000001217715246600164325ustar00rootroot00000000000000MooX-Types-MooseLike-0.25/maint/Makefile.PL.include000064400000000000000000000003061217715246600220250ustar00rootroot00000000000000BEGIN { -e 'Distar' or system("git clone git://git.shadowcat.co.uk/p5sagit/Distar.git") } use lib 'Distar/lib'; use Distar; author 'mateu - Mateu X. Hunter (cpan:MATEU) '; 1; MooX-Types-MooseLike-0.25/t/000075500000000000000000000000001217715246600155655ustar00rootroot00000000000000MooX-Types-MooseLike-0.25/t/basic.t000064400000000000000000000222641217715246600170410ustar00rootroot00000000000000package MooX::Types::MooseLike::Test; use strict; use warnings FATAL => 'all'; use Moo; use MooX::Types::MooseLike::Base qw(:all); has 'a_bool' => ( is => 'ro', isa => Bool, ); has 'an_undef' => ( is => 'ro', isa => Undef, ); has 'a_defined' => ( is => 'ro', isa => Defined, ); has 'a_value' => ( is => 'ro', isa => Value, ); has 'a_string' => ( is => 'ro', isa => Str, ); has 'a_number' => ( is => 'ro', isa => Num, ); has 'an_integer' => ( is => 'ro', isa => Int, ); has 'a_ref' => ( is => 'ro', isa => Ref, ); has 'an_array' => ( is => 'ro', isa => ArrayRef, ); has 'a_hash' => ( is => 'ro', isa => HashRef, ); has 'a_code' => ( is => 'ro', isa => CodeRef, ); has 'a_regex' => ( is => 'ro', isa => RegexpRef, ); has 'a_glob' => ( is => 'ro', isa => GlobRef, ); has 'a_filehandle' => ( is => 'ro', isa => FileHandle, ); has 'an_object' => ( is => 'ro', isa => Object, ); has 'legal_age' => ( is => 'ro', isa => sub { die "$_[0] is not of legal age" unless (is_Int($_[0]) && $_[0] > 17); }, ); package main; use strict; use warnings FATAL => 'all'; use Test::More; use Test::Fatal; use IO::Handle; use MooX::Types::MooseLike::Base qw(:all); ok(is_Str('x'), 'is_Str'); ok(!is_Str([]), 'is_Str fails on ArrayRef'); ok(is_Num(3.142), 'is_Num'); ok(is_Num('9'), 'is_Num'); ok(!is_Num('xxx'), 'is_Num fails on a non-numeric string'); ok(is_Int(-3), 'is_Int'); ok(!is_Int(3.142), 'is_Int fails on a Float'); ok(is_Bool('0'), '0 is_Bool'); ok(is_Bool(''), 'empty string is_Bool'); ok(is_Bool(), 'undef is_Bool'); ok(is_Bool(1), '1 is_Bool'); ok(!is_Bool(-1), 'is_Bool fails on -1'); ok(is_ArrayRef([]), 'is_ArrayRef'); ok(!is_ArrayRef('1'), 'is_ArrayRef fails on 1'); ok(is_HashRef({}), 'is_HashRef'); ok(!is_HashRef([]), 'is_HashRef fails on []'); ok(is_CodeRef(sub { }), 'is_CodeRef'); ok(!is_CodeRef({}), 'is_CodeRef fails on {}'); ok(is_Object(IO::Handle->new), 'Object'); ok(!is_Object({}), 'is_Object fails on HashRef'); # Test Bool ok(MooX::Types::MooseLike::Test->new(a_bool => undef), 'undef is a Bool'); ok(MooX::Types::MooseLike::Test->new(a_bool => 0), '0 is a Bool'); my $false_boolean_value = 0.001; like( exception { MooX::Types::MooseLike::Test->new(a_bool => $false_boolean_value); }, qr/$false_boolean_value is not a Boolean/, 'a non-boolean is an exception when we want a Bool' ); # Undef ok(MooX::Types::MooseLike::Test->new(an_undef => undef), 'Undef'); like( exception { MooX::Types::MooseLike::Test->new(an_undef => '') }, qr/is not undef/, 'empty string is an exception when we want an Undef type' ); # Defined ok(MooX::Types::MooseLike::Test->new(a_defined => ''), 'Defined'); like( exception { MooX::Types::MooseLike::Test->new(a_defined => undef) }, qr/is not defined/, 'undef is an exception when we want a Defined type' ); # Test Value ok(MooX::Types::MooseLike::Test->new(a_value => ''), 'empty string Value'); ok(MooX::Types::MooseLike::Test->new(a_value => 0), 'zero Value'); ok(MooX::Types::MooseLike::Test->new(a_value => 'yarn'), 'word Value'); like( exception { MooX::Types::MooseLike::Test->new(a_value => undef) }, qr/undef is not a value/, 'undef is an exception when we want a Value' ); like( exception { MooX::Types::MooseLike::Test->new(a_value => []) }, qr/ARRAY.*?is not a value/, 'an ArrayRef is an exception when we want a Value' ); # Test Str ok(MooX::Types::MooseLike::Test->new(a_string => ''), 'Empty string'); ok(MooX::Types::MooseLike::Test->new(a_string => '0'), 'Zero as a string'); ok(MooX::Types::MooseLike::Test->new(a_string => 'barn'), 'Word string'); like( exception { MooX::Types::MooseLike::Test->new(a_string => undef) }, qr/undef is not a string/, 'undef is an exception when we want a Str' ); like( exception { MooX::Types::MooseLike::Test->new(a_string => []) }, qr/ARRAY.*?is not a string/, 'an ArrayRef is an exception when we want a Str' ); # Test Num ok(MooX::Types::MooseLike::Test->new(a_number => 0), 'Num zero'); ok(MooX::Types::MooseLike::Test->new(a_number => 3.14), 'Num'); like( exception { MooX::Types::MooseLike::Test->new(a_number => undef) }, qr/undef is not a number/, 'undef is an exception when we want a number' ); like( exception { MooX::Types::MooseLike::Test->new(a_number => '') }, qr/The empty string is not a number/, 'The empty string is an exception when we want a number' ); like( exception { MooX::Types::MooseLike::Test->new(a_number => '5x5') }, qr/is not a number/, 'a non number is an exception when we want a number' ); # Test Int ok(MooX::Types::MooseLike::Test->new(an_integer => -1), 'Int'); like( exception { MooX::Types::MooseLike::Test->new(an_integer => undef) }, qr/undef is not an integer/, 'undef is an exception when we want an Integer' ); like( exception { MooX::Types::MooseLike::Test->new(an_integer => '') }, qr/The empty string is not an integer/, 'The empty string is an exception when we want an Integer' ); like( exception { MooX::Types::MooseLike::Test->new(an_integer => 1.01) }, qr/is not an integer/, 'a non-integer is an exception when we want an Integer' ); # Test Ref ok(MooX::Types::MooseLike::Test->new(a_ref => []), 'Ref: ArrayRef'); like( exception { MooX::Types::MooseLike::Test->new(a_ref => undef) }, qr/is not a reference/, 'undef is an exception when we want a reference' ); like( exception { MooX::Types::MooseLike::Test->new(a_ref => '') }, qr/is not a reference/, 'The empty string is an exception when we want a reference' ); like( exception { MooX::Types::MooseLike::Test->new(a_ref => 0) }, qr/is not a reference/, 'zero is an exception when we want an reference' ); # Test ArrayRef ok(MooX::Types::MooseLike::Test->new(an_array => []), 'ArrayRef'); like( exception { MooX::Types::MooseLike::Test->new(an_array => undef) }, qr/is not an ArrayRef/, 'undef is an exception when we want an ArrayRef' ); like( exception { MooX::Types::MooseLike::Test->new(an_array => '') }, qr/is not an ArrayRef/, 'The empty string is an exception when we want an ArrayRef' ); like( exception { MooX::Types::MooseLike::Test->new(an_array => 0) }, qr/is not an ArrayRef/, 'zero is an exception when we want an ArrayRef' ); like( exception { MooX::Types::MooseLike::Test->new(an_array => {}) }, qr/HASH.*?is not an ArrayRef/, 'a HashRef is an exception when we want an ArrayRef' ); like( exception { MooX::Types::MooseLike::Test->new(an_array => 'string') }, qr/string is not an ArrayRef/, 'a String is an exception when we want an ArrayRef' ); # Test HashRef ok(MooX::Types::MooseLike::Test->new(a_hash => {}), 'HashRef'); like( exception { MooX::Types::MooseLike::Test->new(a_hash => undef) }, qr/is not a HashRef/, 'undef is an exception when we want a HashRef' ); like( exception { MooX::Types::MooseLike::Test->new(a_hash => '') }, qr/is not a HashRef/, 'The empty string is an exception when we want a HashRef' ); like( exception { MooX::Types::MooseLike::Test->new(a_hash => []) }, qr/ARRAY.*?is not a HashRef/, 'an ArrayRef is an exception when we want a HashRef' ); like( exception { MooX::Types::MooseLike::Test->new(a_hash => 'string') }, qr/string is not a HashRef/, 'a String is an exception when we want a HashRef' ); # Test CodeRef ok(MooX::Types::MooseLike::Test->new(a_code => sub { }), 'CodeRef'); like( exception { MooX::Types::MooseLike::Test->new(a_code => []) }, qr/ARRAY.*?is not a CodeRef/, 'an ArrayRef is an exception when we want a CodeRef' ); # Test RegexpRef ok(MooX::Types::MooseLike::Test->new(a_regex => qr{}), 'RegexpRef'); like( exception { MooX::Types::MooseLike::Test->new(a_regex => []) }, qr/ARRAY.*?is not a RegexpRef/, 'an ArrayRef is an exception when we want a RegexpRef' ); # Test GlobRef # avoid warning for using FOO only once no warnings 'once'; ok(MooX::Types::MooseLike::Test->new(a_glob => \*FOO), 'GlobRef'); like( exception { MooX::Types::MooseLike::Test->new(a_glob => []) }, qr/ARRAY.*?is not a GlobRef/, 'an ArrayRef is an exception when we want a GlobRef' ); # Test FileHandle ok(MooX::Types::MooseLike::Test->new(a_filehandle => IO::Handle->new), 'FileHandle'); like( exception { MooX::Types::MooseLike::Test->new(a_filehandle => []) }, qr/ARRAY.*?is not a FileHandle/, 'an ArrayRef is an exception when we want a FileHandle' ); # Test Object ok(MooX::Types::MooseLike::Test->new(an_object => IO::Handle->new), 'Object'); like( exception { MooX::Types::MooseLike::Test->new(an_object => []) }, qr/ARRAY.*?is not an Object/, 'an ArrayRef is an exception when we want an Object' ); # Test legal_age attribute which has an 'isa' that uses 'is_Int' ok(MooX::Types::MooseLike::Test->new(legal_age => 18), 'Legal Age'); my $minor_age = 17; like( exception { MooX::Types::MooseLike::Test->new(legal_age => $minor_age) }, qr/$minor_age is not of legal age/, 'an integer less than 18 is an exception when we want a legal age' ); like( exception { MooX::Types::MooseLike::Test->new(an_undef => '') }, qr/is not undef.*\n.*MooX::Types::MooseLike::Test::new.*basic\.t/, 'The error looks like a useful stacktrace' ); done_testing; MooX-Types-MooseLike-0.25/t/builder.t000064400000000000000000000007101217715246600173760ustar00rootroot00000000000000{ package MyObject; use Moo; use MooX::Types::MooseLike::Base qw; has attribute_with_a_builder => ( is => 'ro', isa => ArrayRef [CodeRef], builder => '_build_attribute_properties', ); sub _build_attribute_properties { [ sub { 'pie' } ]; } } use Test::More; my $object = MyObject->new; is($object->attribute_with_a_builder->[0]->(), 'pie', 'Parameterized type with a builder'); done_testing; MooX-Types-MooseLike-0.25/t/default.t000064400000000000000000000006051217715246600173770ustar00rootroot00000000000000{ package MyObject; use Moo; use MooX::Types::MooseLike::Base qw; has attribute_with_a_default => ( is => 'ro', isa => ArrayRef [Int], default => sub { [ 52, 27, 108 ] }, ); } use Test::More; use Test::Fatal; is_deeply( MyObject->new->attribute_with_a_default, [ 52, 27, 108 ], 'Parameterized type with a default' ); done_testing; MooX-Types-MooseLike-0.25/t/inflate_0.t000064400000000000000000000034721217715246600176210ustar00rootroot00000000000000use strict; use warnings; use Test::More; use Test::Fatal; eval q{ package Local::TypeLibrary; use Exporter 'import'; use MooX::Types::MooseLike (); MooX::Types::MooseLike::register_types([{ name => 'Flibble', test => sub { $_[0] =~ /^flibble$/i }, message => sub { 'Unflibble' }, inflate => 0, }], __PACKAGE__); $INC{'Local/TypeLibrary.pm'} = __FILE__; 1; } or die $@; eval q{ package Local::TestClass; use Moo; use Local::TypeLibrary 'Flibble'; has flibble => (is => 'ro', isa => Flibble); 1; } or die $@; is( exception { Local::TestClass->new(flibble => 'fliBBle') }, undef, 'value which should not violate type constraint', ); like( exception { Local::TestClass->new(flibble => 'monkey') }, qr{^isa check for "flibble" failed: Unflibble}, 'value which should violate type constraint', ); eval q{ require Moose } or do { note "Moose not available; skipping actual inflation tests"; done_testing; exit; }; is( exception { Local::TestClass->new(flibble => 'fliBBle') }, undef, 'Moose loaded; value which should not violate type constraint', ); like( exception { Local::TestClass->new(flibble => 'monkey') }, qr{^isa check for "flibble" failed: Unflibble}, 'Moose loaded; value which should violate type constraint', ); my $tc = do { # Suppress distracting warnings from within Moose local $SIG{__WARN__} = sub { 0 }; Local::TestClass->meta->get_attribute('flibble')->type_constraint; }; is( $tc->name, '__ANON__', 'type constraint inflation results in an anonymous type', ); ok($tc->check('Flibble'), 'Moose::Meta::TypeConstraint works (1)'); ok($tc->check('FLIBBLE'), 'Moose::Meta::TypeConstraint works (2)'); ok(!$tc->check('Monkey'), 'Moose::Meta::TypeConstraint works (3)'); ok(!$tc->check([]), 'Moose::Meta::TypeConstraint works (4)'); done_testing; MooX-Types-MooseLike-0.25/t/inflate_name.t000064400000000000000000000033261217715246600204000ustar00rootroot00000000000000use strict; use warnings; use Test::More; use Test::Fatal; eval q{ package Local::TypeLibrary; use Exporter 'import'; use MooX::Types::MooseLike (); MooX::Types::MooseLike::register_types([{ name => 'Defined', test => sub { defined $_[0] }, message => sub { 'Not defined' }, }], __PACKAGE__); $INC{'Local/TypeLibrary.pm'} = __FILE__; 1; } or die $@; eval q{ package Local::TestClass; use Moo; use Local::TypeLibrary 'Defined'; has flibble => (is => 'ro', isa => Defined); 1; } or die $@; is( exception { Local::TestClass->new(flibble => 'fliBBle') }, undef, 'value which should not violate type constraint', ); like( exception { Local::TestClass->new(flibble => undef) }, qr{^isa check for "flibble" failed: Not defined}, 'value which should violate type constraint', ); eval q{ require Moose } or do { note "Moose not available; skipping actual inflation tests"; done_testing; exit; }; is( exception { Local::TestClass->new(flibble => 'fliBBle') }, undef, 'Moose loaded; value which should not violate type constraint', ); like( exception { Local::TestClass->new(flibble => undef) }, qr{^isa check for "flibble" failed: Not defined}, 'Moose loaded; value which should violate type constraint', ); my $tc = do { # Suppress distracting warnings from within Moose local $SIG{__WARN__} = sub { 0 }; Local::TestClass->meta->get_attribute('flibble')->type_constraint; }; is( $tc->name, 'Defined', 'type constraint inflation results in built in Defined type', ); ok($tc->check('Flibble'), 'Moose::Meta::TypeConstraint works (1)'); ok(!$tc->check(undef), 'Moose::Meta::TypeConstraint works (2)'); done_testing; MooX-Types-MooseLike-0.25/t/inflate_sub.t000064400000000000000000000037051217715246600202520ustar00rootroot00000000000000use strict; use warnings; use Test::More; use Test::Fatal; eval q{ package Local::TypeLibrary; use Exporter 'import'; use MooX::Types::MooseLike (); MooX::Types::MooseLike::register_types([{ name => 'Flibble', test => sub { $_[0] =~ /^flibble$/i }, message => sub { 'Unflibble' }, inflate => sub { return Moose::Meta::TypeConstraint->new( name => 'MooseFlibble', constraint => sub { $_[0] =~ /^flibble$/i }, ); }, }], __PACKAGE__); $INC{'Local/TypeLibrary.pm'} = __FILE__; 1; } or die $@; eval q{ package Local::TestClass; use Moo; use Local::TypeLibrary 'Flibble'; has flibble => (is => 'ro', isa => Flibble); 1; } or die $@; is( exception { Local::TestClass->new(flibble => 'fliBBle') }, undef, 'value which should not violate type constraint', ); like( exception { Local::TestClass->new(flibble => 'monkey') }, qr{^isa check for "flibble" failed: Unflibble}, 'value which should violate type constraint', ); eval q{ require Moose } or do { note "Moose not available; skipping actual inflation tests"; done_testing; exit; }; is( exception { Local::TestClass->new(flibble => 'fliBBle') }, undef, 'Moose loaded; value which should not violate type constraint', ); like( exception { Local::TestClass->new(flibble => 'monkey') }, qr{^isa check for "flibble" failed: Unflibble}, 'Moose loaded; value which should violate type constraint', ); my $tc = do { # Suppress distracting warnings from within Moose local $SIG{__WARN__} = sub { 0 }; Local::TestClass->meta->get_attribute('flibble')->type_constraint; }; is( $tc->name, 'MooseFlibble', 'type constraint inflation results in custom type', ); ok($tc->check('Flibble'), 'Moose::Meta::TypeConstraint works (1)'); ok($tc->check('FLIBBLE'), 'Moose::Meta::TypeConstraint works (2)'); ok(!$tc->check('Monkey'), 'Moose::Meta::TypeConstraint works (3)'); ok(!$tc->check([]), 'Moose::Meta::TypeConstraint works (4)'); done_testing; MooX-Types-MooseLike-0.25/t/parameterized.t000064400000000000000000000125531217715246600206140ustar00rootroot00000000000000{ package A; use Moo; has fun => (is => 'ro'); 1; } { package B; use Moo; extends 'A'; has funner => (is => 'ro'); 1; } { package MooX::Types::MooseLike::Test; use strict; use warnings FATAL => 'all'; use Moo; use MooX::Types::MooseLike::Base qw/ ArrayRef Int HashRef Str ScalarRef Maybe AnyOf Undef /; has an_array_of_integers => ( is => 'ro', isa => ArrayRef [Int], ); has an_array_of_hash => ( is => 'ro', isa => ArrayRef [HashRef], ); has a_hash_of_strings => ( is => 'ro', isa => HashRef [Str], ); has an_array_of_hash_of_int => ( is => 'ro', isa => ArrayRef [ HashRef [Int] ], ); has a_scalar_ref_of_int => ( is => 'ro', isa => ScalarRef [Int], ); has maybe_an_int => ( is => 'ro', isa => Maybe [Int], ); has array_maybe_a_hash => ( is => 'ro', isa => ArrayRef [ Maybe [HashRef] ], ); has array_maybe_a_hash_of_int => ( is => 'ro', isa => ArrayRef [ Maybe [ HashRef [Int] ] ], ); has maybe_an_int_or_hash => ( is => 'ro', isa => AnyOf[Int, HashRef, Undef], ); } package main; use strict; use warnings FATAL => 'all'; use Test::More; use Test::Fatal; use IO::Handle; # ArrayRef[Int] ok(MooX::Types::MooseLike::Test->new(an_array_of_integers => [ 6, 7, 10, -1 ]), 'ArrayRef[Int]'); like( exception { MooX::Types::MooseLike::Test->new(an_array_of_integers => [ 1.5, 2 ]); }, qr/is not an integer/, 'an ArrayRef of Floats is an exception when we want an ArrayRef[Int]' ); # ArrayRef[HashRef] ok( MooX::Types::MooseLike::Test->new( an_array_of_hash => [ { a => 1 }, { b => 2 } ] ), 'ArrayRef[HashRef]' ); ok( MooX::Types::MooseLike::Test->new( an_array_of_hash => [ { a => 1 }, { b => undef } ] ), 'ArrayRef[HashRef] with undef' ); like( exception { MooX::Types::MooseLike::Test->new( an_array_of_hash => [ { x => 1 }, [ 1, 2, 3 ] ]); }, qr/is not a HashRef/, 'an ArrayRef of integers is an exception when we want an ArrayRef[HashRef]' ); # HashRef[Str] ok(MooX::Types::MooseLike::Test->new(a_hash_of_strings => { a => 1, b => 'x' }), 'HashRef[Str]'); ok(MooX::Types::MooseLike::Test->new(a_hash_of_strings => {}), 'Empty HashRef'); like( exception { MooX::Types::MooseLike::Test->new(a_hash_of_strings => { a => MooX::Types::MooseLike::Test->new(), b => 'x' }); }, qr/is not a string/, 'an HashRef with Objects is an exception when we want an HashRef[Str]' ); # ArrayRef[HashRef[Int]] ok( MooX::Types::MooseLike::Test->new( an_array_of_hash_of_int => [ { a => 1 }, { b => 2 } ] ), 'ArrayRef[HashRef[Int]]' ); like( exception { MooX::Types::MooseLike::Test->new( an_array_of_hash_of_int => [ { x => 1 }, { x => 1.1 } ]); }, qr/is not an integer/, 'an ArrayRef of HashRef of Floats is an exception when we want an ArrayRef[HashRef[Int]]' ); # ScalarRef[Int] ok(MooX::Types::MooseLike::Test->new(a_scalar_ref_of_int => \1), 'ScalarRef[Int]'); like( exception { MooX::Types::MooseLike::Test->new(a_scalar_ref_of_int => \'x') }, qr/is not an integer/, 'a ScalarRef of Str is an exception when we want an ScalarRef[Int]' ); # Maybe[Int] ok(MooX::Types::MooseLike::Test->new(maybe_an_int => 41), 'Maybe[Int] as an integer'); ok(MooX::Types::MooseLike::Test->new(maybe_an_int => undef), 'Maybe[Int] as undef'); ok(MooX::Types::MooseLike::Test->new(maybe_an_int => -24), 'Maybe[Int] as undef'); like( exception { MooX::Types::MooseLike::Test->new(maybe_an_int => 'x') }, qr/is not an integer/, 'a Str is an exception when we want a Maybe[Int]' ); # AnyOf[Int, HashRef, Undef] - a stand in for Maybe[Int, HashRef] ok(MooX::Types::MooseLike::Test->new(maybe_an_int_or_hash => {nbr => 41} ), 'Maybe[Int, HahsRef, Undef] as a HashRef'); ok(MooX::Types::MooseLike::Test->new(maybe_an_int_or_hash => 41 ), 'Maybe[Int, HahsRef, Undef] as an integer'); ok(MooX::Types::MooseLike::Test->new(maybe_an_int_or_hash => undef ), 'Maybe[Int, HahsRef, Undef] as an undef'); like( exception { MooX::Types::MooseLike::Test->new(maybe_an_int_or_hash => [] ) }, qr/is not any of/, 'an ArrayRef is an exception when we want a AnyOf[Int, HashRef, Undef]' ); like( exception { MooX::Types::MooseLike::Test->new(maybe_an_int_or_hash => sub {} ) }, qr/is not any of/, 'a CodeRef is an exception when we want a AnyOf[Int, HashRef, Undef]' ); # ArrayRef[Maybe[HashRef]] ok(MooX::Types::MooseLike::Test->new(array_maybe_a_hash => [ { a => 41 } ]), 'ArrayRef[Maybe[HashRef]] as an HashRef'); ok( MooX::Types::MooseLike::Test->new( array_maybe_a_hash => [ undef, { a => 41 } ] ), 'ArrayRef[Maybe[HashRef]] with an undef' ); like( exception { MooX::Types::MooseLike::Test->new(array_maybe_a_hash => ['x']) }, qr/is not a HashRef/, 'a Str is an exception when we want a Maybe[HashRef]' ); # ArrayRef[Maybe[HashRef[Int]]] ok( MooX::Types::MooseLike::Test->new( array_maybe_a_hash_of_int => [ { a => 41 } ] ), 'ArrayRef[Maybe[HashRef]] as a HashRef[Int]' ); ok( MooX::Types::MooseLike::Test->new( array_maybe_a_hash_of_int => [ undef, { a => -1 } ] ), 'ArrayRef[Maybe[HashRef]] with an undef' ); like( exception { MooX::Types::MooseLike::Test->new( array_maybe_a_hash_of_int => [ { b => 'x' } ]); }, qr/is not an integer/, 'a Str is an exception when we want a Maybe[HashRef[Int]]' ); done_testing; MooX-Types-MooseLike-0.25/t/parameterized_inflate.t000064400000000000000000000047211217715246600223140ustar00rootroot00000000000000use strict; use warnings; use Test::More; use Test::Fatal; eval q{ package Local::TestClass; use Moo; use MooX::Types::MooseLike::Base qw( Enum AnyOf Str ArrayRef ScalarRef HashRef HasMethods ); has chipmunk => (is => 'ro', isa => Enum[qw(Alvin Simon Theodore)]); has songs => (is => 'ro', isa => AnyOf[ Str, ArrayRef[Str] ]); has complex => (is => 'ro', isa => HashRef[ArrayRef[ScalarRef[HasMethods[qw/foo bar/]]]]); 1; } or die $@; is( exception { Local::TestClass->new(chipmunk => 'Simon', songs => []) }, undef, 'values which should not violate type constraints', ); like( exception { Local::TestClass->new(chipmunk => 'Romeo') }, qr{^isa check for "chipmunk" failed: Romeo is not any of the possible values}, 'value which should violate Enum type constraint', ); like( exception { Local::TestClass->new(songs => {}) }, qr{^isa check for "songs" failed: HASH\(.+?\) is not any of the types}, 'value which should violate AnyOf type constraint', ); eval q{ require Moose } or do { note "Moose not available; skipping actual inflation tests"; done_testing; exit; }; my $tc = do { $SIG{__WARN__} = sub { 0 }; Local::TestClass->meta->get_attribute('chipmunk')->type_constraint; }; is( exception { Local::TestClass->new(chipmunk => 'Simon') }, undef, 'Moose loaded; value which should not violate type constraint', ); like( exception { Local::TestClass->new(chipmunk => 'Romeo') }, qr{^isa check for "chipmunk" failed: Romeo is not any of the possible values}, 'Moose loaded; value which should violate type constraint', ); isa_ok($tc, 'Moose::Meta::TypeConstraint::Enum'); is_deeply($tc->values, [qw/Alvin Simon Theodore/], '$tc->values'); my $tc2 = do { $SIG{__WARN__} = sub { 0 }; Local::TestClass->meta->get_attribute('songs')->type_constraint; }; ok( $tc2->name eq 'ArrayRef[Str]|Str' || $tc2->name eq 'Str|ArrayRef[Str]', 'complex type constraint (union of Str and ArrayRef[Str]) correctly inflated', ); my $tc3 = do { $SIG{__WARN__} = sub { 0 }; Local::TestClass->meta->get_attribute('complex')->type_constraint; }; is( $tc3->name, 'HashRef[ArrayRef[ScalarRef[__ANON__]]]', 'very complex type constraint correctly inflated', ); isa_ok( $tc3->type_parameter->type_parameter->type_parameter, 'Moose::Meta::TypeConstraint::DuckType', ); is_deeply( [sort @{$tc3->type_parameter->type_parameter->type_parameter->methods}], [sort qw/foo bar/], 'duck type has correct methods' ); done_testing; MooX-Types-MooseLike-0.25/t/parameterized_subtype.t000064400000000000000000000030631217715246600223630ustar00rootroot00000000000000use strict; use warnings; use Test::More; use Test::Fatal; BEGIN { package Local::TypeLibrary; use MooX::Types::MooseLike qw/ exception_message /; use MooX::Types::MooseLike::Base qw/ Object AllOf InstanceOf ConsumerOf HasMethods /; use Exporter 5.57 'import'; MooX::Types::MooseLike::register_types([{ name => 'Douche', subtype_of => AllOf[InstanceOf['Man'], ConsumerOf['Role::Dick'], HasMethods['thought', 'testosterone']], from => 'MooX::Types::MooseLike::Base', test => sub { ($_[0]->testosterone =~ /beaucou/) and ($_[0]->thought < 0.5) }, message => sub { return exception_message($_[0], 'a douche') }, }], __PACKAGE__); $INC{'Local/TypeLibrary.pm'} = __FILE__; } { package Human; use Moo; use MooX::Types::MooseLike::Base qw/ Num /; has thought => (is => 'ro', isa => Num); } { package Woman; use Moo; extends 'Human'; sub sings {}; } { package Man; use Moo; extends 'Human'; sub hunts {}; } { package Role::Dick; use Moo::Role; sub testosterone { 'beaucoupe' }; } { package Brogrammer; use Moo; extends 'Man'; with ('Role::Dick'); } { package MooX::Types::MooseLike::Test; use Moo; use Local::TypeLibrary qw/Douche/; has brogrammer => ( is => 'ro', isa => Douche, ); } ok(MooX::Types::MooseLike::Test->new(brogrammer => Brogrammer->new(thought => 0)), 'A brogrammer is a douche'); like( exception { MooX::Types::MooseLike::Test->new(brogrammer => bless {}, 'Elkman'); }, qr/is not a douche/, 'Elk man is not a douche', ); done_testing(); MooX-Types-MooseLike-0.25/t/parameterized_with_coderefs.t000064400000000000000000000044061217715246600235170ustar00rootroot00000000000000{ package MooX::Types::MooseLike::Test; use strict; use warnings FATAL => 'all'; use Moo; use MooX::Types::MooseLike::Base qw/ AnyOf AllOf Object Int ArrayRef HashRef InstanceOf HasMethods /; has any_of => ( is => 'ro', isa => AnyOf[Int, HashRef[Int], Object], ); has all_of => ( is => 'ro', isa => AllOf[InstanceOf['IO::Handle'], HasMethods['print']], ); } package main; use strict; use warnings FATAL => 'all'; use Test::More; use Test::Fatal; use IO::Handle; # AnyOf ok(MooX::Types::MooseLike::Test->new(any_of => IO::Handle->new ), 'value is AnyOf[Int, ArrayRef[Int], HashRef[Int], Object]'); ok(MooX::Types::MooseLike::Test->new(any_of => 108 ), 'Int is AnyOf[Int, ArrayRef[Int], HashRef[Int], Object]'); ok(MooX::Types::MooseLike::Test->new(any_of => {auspicious_number => 108} ), 'HashRef[Int] is AnyOf[Int, ArrayRef[Int], HashRef[Int], Object]'); ok(MooX::Types::MooseLike::Test->new(any_of => {} ), 'HashRef is AnyOf[Int, ArrayRef[Int], HashRef[Int], Object]'); my $false_value; like( exception { MooX::Types::MooseLike::Test->new(any_of => $false_value); }, qr/is not any of/, 'undef is not an any of the types given"' ); $false_value = { nada => undef }; like( exception { MooX::Types::MooseLike::Test->new(any_of => $false_value); }, qr/is not any of/, 'A HashRef with an undefined value is not an any of the types given' ); $false_value = []; like( exception { MooX::Types::MooseLike::Test->new(any_of => $false_value); }, qr/is not any of/, 'ArrayRef is not an any of the types given' ); $false_value = 'peace_treaty'; like( exception { MooX::Types::MooseLike::Test->new(any_of => $false_value); }, qr/is not any of/, 'a string is not any of the types given' ); # AllOf ok(MooX::Types::MooseLike::Test->new(all_of => IO::Handle->new ), "value is AllOf[InstanceOf('IO::Handle'), HasMethods['print']]"); $false_value = undef; like( exception { MooX::Types::MooseLike::Test->new(all_of => $false_value); }, qr/No instance given/, 'undef is not an instance of IO::Handle"' ); $false_value = 'peace_treaty'; like( exception { MooX::Types::MooseLike::Test->new(all_of => $false_value); }, qr/is not blessed/, 'a string is not an instance of IO::Handle' ); done_testing; MooX-Types-MooseLike-0.25/t/parameterized_with_string.t000064400000000000000000000121061217715246600232270ustar00rootroot00000000000000{ package NoBool; use Moo; use overload ('bool' => sub { die }); } { package MooX::Types::MooseLike::Test::Role; use Role::Tiny; sub foo { 'ja' }; sub bar { 'ara' }; } { package MooX::Types::MooseLike::Test::AnotherRole; use Role::Tiny; sub que { 'dius' }; sub quoi { 'dieu' }; } { package A; use Moo; has fun => (is => 'ro'); 1; } { package B; use Moo; extends 'A'; has funner => (is => 'ro'); 1; } { package MooX::Types::MooseLike::Test; use strict; use warnings FATAL => 'all'; use Moo; use MooX::Types::MooseLike::Base qw/ InstanceOf ConsumerOf HasMethods Enum /; with ( 'MooX::Types::MooseLike::Test::Role', 'MooX::Types::MooseLike::Test::AnotherRole' ); has instance_of_IO_Handle => ( is => 'ro', isa => InstanceOf['IO::Handle'], ); has instance_of_A_and_B => ( is => 'ro', isa => InstanceOf['A', 'B'], ); has instance_of_NoBool => ( is => 'ro', isa => InstanceOf['NoBool'], ); has consumer_of => ( is => 'ro', isa => ConsumerOf[ 'MooX::Types::MooseLike::Test::Role', 'MooX::Types::MooseLike::Test::AnotherRole' ], ); has has_methods => ( is => 'ro', isa => HasMethods['foo', 'bar'], ); has enum_type => ( is => 'ro', isa => Enum['estrella', 'lluna', 'deessa'], ); } package main; use strict; use warnings FATAL => 'all'; use Test::More; use Test::Fatal; use IO::Handle; # InstanceOf ok(MooX::Types::MooseLike::Test->new(instance_of_IO_Handle => IO::Handle->new ), 'instance of IO::Handle'); my $false_instance; like( exception { MooX::Types::MooseLike::Test->new(instance_of_IO_Handle => $false_instance); }, qr/No instance given/, 'undef is not an instance of IO::Handle' ); $false_instance = {}; like( exception { MooX::Types::MooseLike::Test->new(instance_of_IO_Handle => $false_instance); }, qr/is not blessed/, 'a hashref is not an instance of IO::Handle' ); $false_instance = bless {}, 'Foo'; like( exception { MooX::Types::MooseLike::Test->new(instance_of_IO_Handle => $false_instance); }, qr/is not an instance of the class.*IO::Handle/, 'a Foo instance is not an instance of IO::Handle' ); ok(MooX::Types::MooseLike::Test->new(instance_of_A_and_B => B->new ), 'instance of A and B'); ok(MooX::Types::MooseLike::Test->new(instance_of_NoBool => NoBool->new ), 'instance of NoBool'); # ConsumerOf ok(MooX::Types::MooseLike::Test->new(consumer_of => MooX::Types::MooseLike::Test->new ), 'consumer of a some roles'); my $false_consumer; like( exception { MooX::Types::MooseLike::Test->new(consumer_of => $false_consumer); }, qr/No instance given/, 'undef is not a consumer of roles' ); $false_consumer = IO::Handle->new; like( exception { MooX::Types::MooseLike::Test->new(consumer_of => $false_consumer); }, qr/is not a consumer of roles/, 'an IO::Handle instance is not a consumer of roles' ); like( exception { MooX::Types::MooseLike::Test->new(consumer_of => 'MooX::Types::MooseLike::Test'); }, qr/is not blessed/, 'a class name is not a consumer of roles' ); # HasMethods ok(MooX::Types::MooseLike::Test->new(has_methods => MooX::Types::MooseLike::Test->new ), 'has methods of madness'); my $false_has_methods; like( exception { MooX::Types::MooseLike::Test->new(has_methods => $false_has_methods); }, qr/No instance given/, 'undef does not have the required methods' ); $false_has_methods = IO::Handle->new; like( exception { MooX::Types::MooseLike::Test->new(has_methods => $false_has_methods); }, qr/does not have the required methods/, 'an object instance does not have the required methods' ); like( exception { MooX::Types::MooseLike::Test->new(has_methods => 'MooX::Types::MooseLike::Test'); }, qr/is not blessed/, 'a class name is does not have methods' ); # Enum ok(MooX::Types::MooseLike::Test->new(enum_type => 'estrella' ), 'has one of the possible values (enum)'); ok(MooX::Types::MooseLike::Test->new(enum_type => 'deessa' ), 'has one of the possible values (enum)'); my $false_enum = undef; like( exception { MooX::Types::MooseLike::Test->new(enum_type => $false_enum); }, qr/is not any of the possible values/, 'undef is not one of the enumerated values' ); $false_enum = IO::Handle->new; like( exception { MooX::Types::MooseLike::Test->new(enum_type => $false_enum); }, qr/is not any of the possible values/, 'an object is not one of the enumerated values' ); $false_enum = {}; like( exception { MooX::Types::MooseLike::Test->new(enum_type => $false_enum); }, qr/is not any of the possible values/, 'a HashRef is not one of the enumerated values' ); $false_enum = ''; like( exception { MooX::Types::MooseLike::Test->new(enum_type => $false_enum); }, qr/is not any of the possible values/, 'an empty string is not one of the enumerated values' ); $false_enum = 'Tot es possible'; like( exception { MooX::Types::MooseLike::Test->new(enum_type => $false_enum); }, qr/is not any of the possible values/, 'a different string is not one of the enumerated values' ); done_testing; MooX-Types-MooseLike-0.25/t/required.t000064400000000000000000000007361217715246600176000ustar00rootroot00000000000000{ package MyObject; use Moo; use MooX::Types::MooseLike::Base qw; has required_parameterized_hashref => ( is => "ro", isa => HashRef [HashRef], required => 1, ); } use Test::More; use Test::Fatal; ok(MyObject->new(required_parameterized_hashref => { a => {} }), 'Required parameterized type'); like( exception { MyObject->new }, qr/Missing required arguments/, 'A required parameterized type must exist' ); done_testing; MooX-Types-MooseLike-0.25/t/subtype.t000064400000000000000000000041011217715246600174410ustar00rootroot00000000000000use strict; use warnings; use Test::More; use Test::Fatal; BEGIN { package Local::TypeLibrary; use MooX::Types::MooseLike; use Exporter 5.57 'import'; MooX::Types::MooseLike::register_types([{ name => 'BaseType', test => sub { defined $_[0] && !ref $_[0] }, message => sub { 'not a simple string' }, }], __PACKAGE__); MooX::Types::MooseLike::register_types([{ name => 'SubType', subtype_of => 'BaseType', from => __PACKAGE__, test => sub { length $_[0] }, message => sub { 'not a string length > 0' }, }], __PACKAGE__); MooX::Types::MooseLike::register_types([{ name => 'SubSubType', subtype_of => SubType(), test => sub { $_[0] }, message => sub { 'not a true value' }, }], __PACKAGE__); $INC{'Local/TypeLibrary.pm'} = __FILE__; } { package MooX::Types::MooseLike::Test; use strict; use warnings FATAL => 'all'; use Moo; use Local::TypeLibrary qw/BaseType SubType SubSubType/; has string => ( is => 'ro', isa => BaseType, ); has string_w_length => ( is => 'ro', isa => SubType, ); has true_string => ( is => 'ro', isa => SubSubType, ); } ok(MooX::Types::MooseLike::Test->new(string => ''), 'empty string is a string'); ok(MooX::Types::MooseLike::Test->new(string_w_length => '0'), '0 is a string with length'); ok(MooX::Types::MooseLike::Test->new(true_string => '1'), '1 is true string'); like( exception { MooX::Types::MooseLike::Test->new(string => undef); }, qr/not a simple string/, 'undef is not a simple string', ); like( exception { MooX::Types::MooseLike::Test->new(string_w_length => ''); }, qr/not a string length > 0/, 'empty string has no length', ); like( exception { MooX::Types::MooseLike::Test->new(string_w_length => {}); }, qr/not a string length > 0/, 'hashref is not a simple string', ); like( exception { MooX::Types::MooseLike::Test->new(true_string => '0'); }, qr/not a true value/, '0 is not a true value', ); done_testing; MooX-Types-MooseLike-0.25/t/version.t000064400000000000000000000003571217715246600174440ustar00rootroot00000000000000use strict; use warnings FATAL => 'all'; use Test::More; use MooX::Types::MooseLike; use MooX::Types::MooseLike::Base; ok(($MooX::Types::MooseLike::Base::VERSION == $MooX::Types::MooseLike::VERSION), 'versions are equal'); done_testing; MooX-Types-MooseLike-0.25/tidyall.ini000064400000000000000000000001521217715246600174630ustar00rootroot00000000000000[PerlTidy] select = **/*.{pl,pm,t} argv = -io -i=2 [PerlCritic] select = lib/**/*.pm argv = -severity 3