MooX-Types-MooseLike-0.29/0000755000175000017500000000000012543356717014726 5ustar hunterhunterMooX-Types-MooseLike-0.29/META.yml0000664000175000017500000000154512543356717016206 0ustar hunterhunter---
abstract: 'some Moosish types and a type builder'
author:
- 'mateu - Mateu X. Hunter (cpan:MATEU) '
build_requires:
Moo: '1.004002'
Test::Fatal: '0.003'
Test::More: '0.96'
configure_requires:
ExtUtils::MakeMaker: '0'
dynamic_config: 1
generated_by: 'ExtUtils::MakeMaker version 7.04, CPAN::Meta::Converter version 2.150001'
license: perl
meta-spec:
url: http://module-build.sourceforge.net/META-spec-v1.4.html
version: '1.4'
name: MooX-Types-MooseLike
no_index:
directory:
- t
- inc
recommends:
strictures: '2'
requires:
Module::Runtime: '0.014'
resources:
IRC: irc://irc.perl.org/#web-simple
bugtracker: http://rt.cpan.org/NoAuth/Bugs.html?Dist=MooX-Types-MooseLike
license: http://dev.perl.org/licenses/
repository: https://github.com/mateu/MooX-Types-MooseLike.git
version: '0.29'
x_authority: cpan:MATEU
MooX-Types-MooseLike-0.29/Makefile.PL0000644000175000017500000000565712543355206016705 0ustar hunterhunteruse strict;
use warnings FATAL => 'all';
use 5.008001;
my %META = (
name => 'MooX-Types-MooseLike',
license => 'perl_5',
prereqs => {
configure => { requires => {
'ExtUtils::MakeMaker' => 0,
} },
build => { requires => {
} },
test => {
requires => {
'Test::More' => 0.96,
'Test::Fatal' => 0.003,
'Moo' => 1.004002,
},
recommends => {
'CPAN::Meta' => 0,
'CPAN::Meta::Requirements' => 0,
},
},
runtime => {
requires => {
'Module::Runtime' => 0.014,
},
recommends => {
'strictures' => 2,
},
},
develop => {
requires => {
'strictures' => 2,
'indirect' => 0,
'multidimensional' => 0,
'bareword::filehandles' => 0,
'Moo' => 1.004002,
},
},
},
resources => {
repository => {
url => 'https://github.com/mateu/MooX-Types-MooseLike.git',
web => 'https://github.com/mateu/MooX-Types-MooseLike',
type => 'git',
},
x_IRC => 'irc://irc.perl.org/#web-simple',
bugtracker => {
web => 'http://rt.cpan.org/NoAuth/Bugs.html?Dist=MooX-Types-MooseLike',
},
license => [ 'http://dev.perl.org/licenses/' ],
},
x_authority => 'cpan:MATEU',
);
my %MM_ARGS = ('DISTNAME' => 'MooX-Types-MooseLike');
## BOILERPLATE ###############################################################
require ExtUtils::MakeMaker;
(do 'maint/Makefile.PL.include' or die $@) unless -f 'META.yml';
# have to do this since old EUMM dev releases miss the eval $VERSION line
my $eumm_version = eval $ExtUtils::MakeMaker::VERSION;
my $mymeta = $eumm_version >= 6.57_02;
my $mymeta_broken = $mymeta && $eumm_version < 6.57_07;
($MM_ARGS{NAME} = $META{name}) =~ s/-/::/g;
($MM_ARGS{VERSION_FROM} = "lib/$MM_ARGS{NAME}.pm") =~ s{::}{/}g;
$META{license} = [ $META{license} ]
if $META{license} && !ref $META{license};
$MM_ARGS{LICENSE} = $META{license}[0]
if $META{license} && $eumm_version >= 6.30;
$MM_ARGS{NO_MYMETA} = 1
if $mymeta_broken;
$MM_ARGS{META_ADD} = { 'meta-spec' => { version => 2 }, %META }
unless -f 'META.yml';
for (qw(configure build test runtime)) {
my $key = $_ eq 'runtime' ? 'PREREQ_PM' : uc $_.'_REQUIRES';
my $r = $MM_ARGS{$key} = {
%{$META{prereqs}{$_}{requires} || {}},
%{delete $MM_ARGS{$key} || {}},
};
defined $r->{$_} or delete $r->{$_} for keys %$r;
}
$MM_ARGS{MIN_PERL_VERSION} = delete $MM_ARGS{PREREQ_PM}{perl} || 0;
delete $MM_ARGS{MIN_PERL_VERSION}
if $eumm_version < 6.47_01;
$MM_ARGS{BUILD_REQUIRES} = {%{$MM_ARGS{BUILD_REQUIRES}}, %{delete $MM_ARGS{TEST_REQUIRES}}}
if $eumm_version < 6.63_03;
$MM_ARGS{PREREQ_PM} = {%{$MM_ARGS{PREREQ_PM}}, %{delete $MM_ARGS{BUILD_REQUIRES}}}
if $eumm_version < 6.55_01;
delete $MM_ARGS{CONFIGURE_REQUIRES}
if $eumm_version < 6.51_03;
ExtUtils::MakeMaker::WriteMakefile(%MM_ARGS);
## END BOILERPLATE ###########################################################
MooX-Types-MooseLike-0.29/README0000664000175000017500000001140312543356717015607 0ustar hunterhunterNAME
MooX::Types::MooseLike - some Moosish types and a type builder
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]
);
DESCRIPTION
This module provides a possibility to build your own set of Moose-like
types. These custom types can then be used to describe fields in
Moo-based classes.
See MooX::Types::MooseLike::Base 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.
FUNCTIONS
register_types
register_types( types, package, moose_namespace )
Install the given types within the package. This makes the types
automatically exportable by adding them to @EXPORT_OK of the package.
Types are expected to be an array ref where every type is of the
following format:
{
name => 'MyType',
test => sub { check_the_value_somehow($_[0]) },
message => sub { "$_[0] is not the type we want!" },
subtype_of => 'SomeParentType', # Optional
from => 'Some::Parent::CoolTypes', # Optional
parameterizable => sub { ... }, # Optional
inflate => sub { ... }, # Optional
}
A type can be declared with a reference (*subtype_of*) to some
previously declared type. In this case the new type will inherit the
behaviour of the referenced type.
The referenced type can come either from the same package or from a
third party package:
MooX::Types::MooseLike::register_types([{
name => 'GreaterThan10',
subtype_of => 'Int',
from => 'MooX::Types::MooseLike::Base',
test => sub { $_[0] > 10 },
message => sub { 'not greater than 10' },
}], __PACKAGE__);
MooX::Types::MooseLike::register_types([{
name => 'Between10And20',
subtype_of => 'GreaterThan10',
from => __PACKAGE__,
test => sub { $_[0] < 20 },
message => sub { 'not an integer between 10 and 20' },
}], __PACKAGE__);
MooX::Types::MooseLike::register_types([{
name => 'Between10And30',
subtype_of => GreaterThan10(),
test => sub { $_[0] < 30 },
message => sub { 'not an integer between 10 and 30' },
}], __PACKAGE__);
exception_message
exception_message( value, part_of_the_exception_string )
Helper function to be used in a type definition:
{
...
message => sub { return exception_message($_[0], 'a HashRef' },
...
}
In the event of mismatching the type constraints it produces the
message:
" is not a HashRef!"
inflate_type
inflate_type( coderef )
Inflates the type to a Moose type. Requires Moose.
SEE ALSO
MooX::Types::MooseLike::Numeric - an example of building subtypes.
MooX::Types::SetObject - an example of building parameterized types.
MooX::Types::MooseLike::Email, MooX::Types::MooseLike::DateTime
Type::Tiny - another implementation of type constraints. Compatible with
Moo, Moose and Mouse.
AUTHOR
mateu - Mateu X. Hunter (cpan:MATEU)
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)
Dmitry Matrosov (cpan:AMIDOS)
COPYRIGHT
Copyright (c) 2011-2015 the MooX::Types::MooseLike "AUTHOR" and
"CONTRIBUTORS" as listed above.
LICENSE
This library is free software and may be distributed under the same
terms as perl itself.
MooX-Types-MooseLike-0.29/t/0000755000175000017500000000000012543356717015171 5ustar hunterhunterMooX-Types-MooseLike-0.29/t/parameterized_with_coderefs.t0000644000175000017500000000440612527130341023104 0ustar hunterhunter{
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.29/t/subtype.t0000644000175000017500000000410112527130341017026 0ustar hunterhunteruse 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.29/t/basic.t0000644000175000017500000002472612527130341016433 0ustar hunterhunterpackage 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"), 'Num string: positive int');
ok(MooX::Types::MooseLike::Test->new(a_number => "-5"), 'Num string: negative int');
ok(MooX::Types::MooseLike::Test->new(a_number => 123), 'Num: positive int');
ok(MooX::Types::MooseLike::Test->new(a_number => 3.14), 'Num: positive decimal');
ok(MooX::Types::MooseLike::Test->new(a_number => -5.26), 'Num: negative decimal');
ok(MooX::Types::MooseLike::Test->new(a_number => "+3.14"), 'Num string: positive decimal');
ok(MooX::Types::MooseLike::Test->new(a_number => ".14"), 'Num string: positive decimal, short form');
ok(MooX::Types::MooseLike::Test->new(a_number => "-.14"), 'Num string: negative decimal, short form');
ok(MooX::Types::MooseLike::Test->new(a_number => "1E1"), 'Num string: E');
ok(MooX::Types::MooseLike::Test->new(a_number => ".5e+123"), 'Num string: E');
ok(MooX::Types::MooseLike::Test->new(a_number => "12.5e-2"), 'Num string: E');
ok(MooX::Types::MooseLike::Test->new(a_number => "0123"), 'Num string: octal int');
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'
);
like(
exception { MooX::Types::MooseLike::Test->new(a_number => "0b1110011") },
qr/is not a number/,
'binary integer string is an exception when we want a number'
);
like(
exception { MooX::Types::MooseLike::Test->new(a_number => "0x1234") },
qr/is not a number/,
'hexadecimal integer string 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/s,
'The error looks like a useful stacktrace'
);
done_testing;
MooX-Types-MooseLike-0.29/t/parameterized_with_string.t0000644000175000017500000001215612527130341022621 0ustar hunterhunter{
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 ClassA;
use Moo;
has fun => (is => 'ro');
1;
}
{
package ClassB;
use Moo;
extends 'ClassA';
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['ClassA', 'ClassB'],
);
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 => ClassB->new ), 'instance of ClassA and ClassB');
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.29/t/required.t0000644000175000017500000000073612527130341017165 0ustar hunterhunter{
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.29/t/parameterized_inflate.t0000644000175000017500000000472112527130341021701 0ustar hunterhunteruse 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.29/t/version.t0000644000175000017500000000035712527130341017031 0ustar hunterhunteruse 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.29/t/inflate_sub.t0000644000175000017500000000370512527130341017637 0ustar hunterhunteruse 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.29/t/inflate_name.t0000644000175000017500000000332612527130341017765 0ustar hunterhunteruse 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.29/t/inflate_0.t0000644000175000017500000000347212527130341017206 0ustar hunterhunteruse 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.29/t/parameterized_subtype.t0000644000175000017500000000306312527130341021750 0ustar hunterhunteruse 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.29/t/default.t0000644000175000017500000000060512527130341016764 0ustar hunterhunter{
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.29/t/parameterized.t0000644000175000017500000001234112527130341020174 0ustar hunterhunter{
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.29/t/builder.t0000644000175000017500000000071012527130341016763 0ustar hunterhunter{
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.29/Changes0000644000175000017500000001051612543356547016225 0ustar hunterhunter0.29 - 2015-06-26
- Add more Num tests (meAmdios)
- Improve POD (meAmidos)
- Add DISTNAME to MakeMaker args
0.28 - 2015-02-27
- Refine POD (github.com/meAmidos)
- Bump version of Moo and Module::Runtime pre-reqs
- Modernize Makefile.PL
0.27 - 2014-08-19
- Fix tests to not use package B (haarg)
0.26 - 2014-08-18
- Bugfix for recent versions of Moo changing error messages (skaufman)
0.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.29/META.json0000664000175000017500000000363212543356717016355 0ustar hunterhunter{
"abstract" : "some Moosish types and a type builder",
"author" : [
"mateu - Mateu X. Hunter (cpan:MATEU) "
],
"dynamic_config" : 1,
"generated_by" : "ExtUtils::MakeMaker version 7.04, CPAN::Meta::Converter version 2.150001",
"license" : [
"perl_5"
],
"meta-spec" : {
"url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
"version" : "2"
},
"name" : "MooX-Types-MooseLike",
"no_index" : {
"directory" : [
"t",
"inc"
]
},
"prereqs" : {
"build" : {
"requires" : {}
},
"configure" : {
"requires" : {
"ExtUtils::MakeMaker" : "0"
}
},
"develop" : {
"requires" : {
"Moo" : "1.004002",
"bareword::filehandles" : "0",
"indirect" : "0",
"multidimensional" : "0",
"strictures" : "2"
}
},
"runtime" : {
"recommends" : {
"strictures" : "2"
},
"requires" : {
"Module::Runtime" : "0.014"
}
},
"test" : {
"recommends" : {
"CPAN::Meta" : "0",
"CPAN::Meta::Requirements" : "0"
},
"requires" : {
"Moo" : "1.004002",
"Test::Fatal" : "0.003",
"Test::More" : "0.96"
}
}
},
"release_status" : "stable",
"resources" : {
"bugtracker" : {
"web" : "http://rt.cpan.org/NoAuth/Bugs.html?Dist=MooX-Types-MooseLike"
},
"license" : [
"http://dev.perl.org/licenses/"
],
"repository" : {
"type" : "git",
"url" : "https://github.com/mateu/MooX-Types-MooseLike.git",
"web" : "https://github.com/mateu/MooX-Types-MooseLike"
},
"x_IRC" : "irc://irc.perl.org/#web-simple"
},
"version" : "0.29",
"x_authority" : "cpan:MATEU"
}
MooX-Types-MooseLike-0.29/maint/0000755000175000017500000000000012543356717016036 5ustar hunterhunterMooX-Types-MooseLike-0.29/maint/Makefile.PL.include0000644000175000017500000000030612527130341021412 0ustar hunterhunterBEGIN { -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.29/MANIFEST0000644000175000017500000000116212543356717016057 0ustar hunterhunterChanges
lib/MooX/Types/MooseLike.pm
lib/MooX/Types/MooseLike/Base.pm
maint/Makefile.PL.include
Makefile.PL
MANIFEST This list of files
t/basic.t
t/builder.t
t/default.t
t/inflate_0.t
t/inflate_name.t
t/inflate_sub.t
t/parameterized.t
t/parameterized_inflate.t
t/parameterized_subtype.t
t/parameterized_with_coderefs.t
t/parameterized_with_string.t
t/required.t
t/subtype.t
t/version.t
META.yml Module YAML meta-data (added by MakeMaker)
META.json Module JSON meta-data (added by MakeMaker)
README README file (added by Distar)
MooX-Types-MooseLike-0.29/lib/0000755000175000017500000000000012543356717015474 5ustar hunterhunterMooX-Types-MooseLike-0.29/lib/MooX/0000755000175000017500000000000012543356717016356 5ustar hunterhunterMooX-Types-MooseLike-0.29/lib/MooX/Types/0000755000175000017500000000000012543356717017462 5ustar hunterhunterMooX-Types-MooseLike-0.29/lib/MooX/Types/MooseLike.pm0000644000175000017500000002265512543354065021713 0ustar hunterhunterpackage 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.29';
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
This module provides a possibility to build your own set of Moose-like types. These custom types can then be used to describe fields in Moo-based classes.
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.
=head1 FUNCTIONS
=head2 register_types
B
Install the given types within the package. This makes the types automatically exportable by adding them to @EXPORT_OK of the package. Types are expected to be an array ref where every type is of the following format:
{
name => 'MyType',
test => sub { check_the_value_somehow($_[0]) },
message => sub { "$_[0] is not the type we want!" },
subtype_of => 'SomeParentType', # Optional
from => 'Some::Parent::CoolTypes', # Optional
parameterizable => sub { ... }, # Optional
inflate => sub { ... }, # Optional
}
A type can be declared with a reference (I) to some previously declared type. In this case the new type will inherit the behaviour of the referenced type.
The referenced type can come either from the same package or from a third party package:
MooX::Types::MooseLike::register_types([{
name => 'GreaterThan10',
subtype_of => 'Int',
from => 'MooX::Types::MooseLike::Base',
test => sub { $_[0] > 10 },
message => sub { 'not greater than 10' },
}], __PACKAGE__);
MooX::Types::MooseLike::register_types([{
name => 'Between10And20',
subtype_of => 'GreaterThan10',
from => __PACKAGE__,
test => sub { $_[0] < 20 },
message => sub { 'not an integer between 10 and 20' },
}], __PACKAGE__);
MooX::Types::MooseLike::register_types([{
name => 'Between10And30',
subtype_of => GreaterThan10(),
test => sub { $_[0] < 30 },
message => sub { 'not an integer between 10 and 30' },
}], __PACKAGE__);
=head2 exception_message
B
Helper function to be used in a type definition:
{
...
message => sub { return exception_message($_[0], 'a HashRef' },
...
}
In the event of mismatching the type constraints it produces the message:
" is not a HashRef!"
=head2 inflate_type
B
Inflates the type to a Moose type. Requires Moose.
=head1 SEE ALSO
L - an example of building subtypes.
L - an example of building parameterized types.
L, L
L - another implementation of type constraints. Compatible with L, L and L.
=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)
Dmitry Matrosov (cpan:AMIDOS)
=head1 COPYRIGHT
Copyright (c) 2011-2015 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.29/lib/MooX/Types/MooseLike/0000755000175000017500000000000012543356717021351 5ustar hunterhunterMooX-Types-MooseLike-0.29/lib/MooX/Types/MooseLike/Base.pm0000644000175000017500000004147612543354100022555 0ustar hunterhunterpackage 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.29;
# 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 - A set of basic 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 attributes 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 SEE ALSO
L - an example of building subtypes.
L - an example of building parameterized types.
L, L
=head1 AUTHOR
Mateu Hunter C
=head1 THANKS
mst has provided critical guidance on the design
=head1 COPYRIGHT
Copyright 2011-2015 Mateu Hunter
=head1 LICENSE
You may distribute this code under the same terms as Perl itself.
=cut