I learnt today (thanks to irc.perl.org #moose) that you can do this in Moose:
has cookies => (
is => 'rw',
isa => 'Bool|Int', # Bool or Int type
);
You can also state that the type should be an instance of a specific class:
has web_browser => (
is => 'rw',
isa => 'WWW::Mechanize',
);
However, you cannot use the above OR construct with class names:
has web_browser => (
is => 'rw',
isa => 'WWW::Mechanize|My::Test::Mechanize', # FAIL
);
At least, not directly out of the box ….
class_type
The quickest way to crack this nut seems to be with Moose::Util::TypeConstraints class_type.
use Moose::Util::TypeConstraints;
class_type q[WWW::Mechanize];
class_type q[My::Test::Mechanize];
no Moose::Util::TypeConstraints;
and now this will work:
has web_browser => (
is => 'rw',
isa => 'WWW::Mechanize|My::Test::Mechanize',
);
OR … Sub types
Moose::Manual::Types tells us we can create our own sub types, giving an example of a PositiveInt type.
That in turn points to Type Constraint Naming in Moose::Util::TypeConstraints which says:
Since the types created by this module are global, it is suggested that you namespace your types just as you would namespace your modules. So instead of creating a
Colortype for yourMy::Graphicsmodule, you would call the typeMy::Graphics::Types::Colorinstead
I don’t know if this is the right way to do things, but I now have the following setup:
Defining My::Types
In lib/My/Types.pm I have:
package My::Types;
use Moose::Util::TypeConstraints;
subtype 'My::Types::PositiveInt'
=> as 'Int'
=> where { $_ > 0 }
=> message { "'$_' is not a int > 0" };
subtype 'My::Types::Mech'
=> as 'Object'
=> where {
$_->isa('WWW::Mechanize')
||
$_->isa('My::Test::Mechanize')
}
=> message {
"'$_' is neither WWW::Mechanize or My::Test::Mechanize"
};
no Moose::Util::TypeConstraints;
1;
Using My::Types
And then within my other code / modules / classes, I can have:
use My::Types;
has web_browser => (
is => 'rw',
isa => 'My::Types::Mech',
);
Which will ensure $thing->web_browser is either a WWW::Mechanize object or my own My::Test::Mechanize object (used for testing purposes).
OR …. MooseX::Types
An (third) alternative approach is MooseX::Types, which allows for having custom types and choosing which ones you import in any one place.
To define your types, in lib/My/Types.pm
package My::Types;
use MooseX::Types
-declare => [qw<PositiveInt Mech>];
use MooseX::Types::Moose qw<Int Object>;
subtype PositiveInt,
as Int,
where { $_ > 0 },
message { "'$_' is not a int > 0" };
subtype Mech,
as Object,
where {
$_->isa('WWW::Mechanize')
||
$_->isa('My::Test::Mechanize')
},
message {
"'$_' is neither WWW::Mechanize or My::Test::Mechanize"
};
1;
and then to use it in your code:
use My::Types qw<Mech>;
has web_browser => (
is => 'rw',
isa => Mech,
);
Note that you do not want the quotes around Mech here else it will fail.
Which one to use?
I haven’t a clue. I think I currently favour defining my own subtype through Moose::Util::TypeConstraints but that is possibly just because it was my first working solution.
Comments welcome :)
ps. thanks again to the friendly people on #moose for putting up with my dumb questions about all this.


MooseX::Types is the way to go.
Oh the wonders of Moose. There are many more things to discover in the manual http://search.cpan.org/perldoc?Moose::Manual though not so easy to read, until now...
We've created a printable version of the Moose manual in elegant typography, easy on the eye. http://www.lulu.com/content/paperback-book/moose/7406976