Add smartmatch support
[gitmo/MooseX-Types.git] / lib / MooseX / Types / TypeDecorator.pm
CommitLineData
4c2125a4 1package MooseX::Types::TypeDecorator;
2
a706b0f2 3use strict;
4use warnings;
4c2125a4 5
c1260541 6
bb5b7b28 7use Carp::Clan qw( ^MooseX::Types );
475bbd1d 8use Moose::Util::TypeConstraints ();
bb5b7b28 9use Moose::Meta::TypeConstraint::Union;
371efa05 10use Scalar::Util qw(blessed);
bb5b7b28 11
4c2125a4 12use overload(
13 '""' => sub {
c1260541 14 my $self = shift @_;
15 if(blessed $self) {
16 return $self->__type_constraint->name;
17 } else {
18 return "$self";
19 }
4c2125a4 20 },
cf1a8bfa 21 '|' => sub {
686e5888 22
23 ## It's kind of ugly that we need to know about Union Types, but this
24 ## is needed for syntax compatibility. Maybe someday we'll all just do
25 ## Or[Str,Str,Int]
442e42ba 26
0d07f026 27 my @args = @_[0,1]; ## arg 3 is special, see the overload docs.
28 my @tc = grep {blessed $_} map {
29 blessed $_ ? $_ :
30 Moose::Util::TypeConstraints::find_or_parse_type_constraint($_)
3ade1c44 31 || __PACKAGE__->_throw_error( "$_ is not a type constraint")
0d07f026 32 } @args;
33
34 ( scalar @tc == scalar @args)
3ade1c44 35 || __PACKAGE__->_throw_error(
36 "one of your type constraints is bad. Passed: ". join(', ', @args) ." Got: ". join(', ', @tc));
0d07f026 37
38 ( scalar @tc >= 2 )
3ade1c44 39 || __PACKAGE__->_throw_error("You must pass in at least 2 type names to make a union");
442e42ba 40
bb5b7b28 41 my $union = Moose::Meta::TypeConstraint::Union->new(type_constraints=>\@tc);
42 return Moose::Util::TypeConstraints::register_type_constraint($union);
cf1a8bfa 43 },
f161acbe 44 ( $] >= 5.010 ? (
45 '~~' => sub {
46 my ( $self, $value ) = @_;
47 $self->__type_constraint->check($value);
48 },
49 ) : () ),
1d9a68a6 50 fallback => 1,
51
4c2125a4 52);
53
54=head1 NAME
55
56MooseX::Types::TypeDecorator - More flexible access to a Type Constraint
57
58=head1 DESCRIPTION
59
60This is a decorator object that contains an underlying type constraint. We use
61this to control access to the type constraint and to add some features.
62
a706b0f2 63=head1 METHODS
4c2125a4 64
a706b0f2 65This class defines the following methods.
4c2125a4 66
a706b0f2 67=head2 new
4c2125a4 68
a706b0f2 69Old school instantiation
4c2125a4 70
71=cut
72
a706b0f2 73sub new {
475bbd1d 74 my $class = shift @_;
75 if(my $arg = shift @_) {
371efa05 76 if(blessed $arg && $arg->isa('Moose::Meta::TypeConstraint')) {
475bbd1d 77 return bless {'__type_constraint'=>$arg}, $class;
e7d06577 78 } elsif(
79 blessed $arg &&
80 $arg->isa('MooseX::Types::UndefinedType')
81 ) {
475bbd1d 82 ## stub in case we'll need to handle these types differently
83 return bless {'__type_constraint'=>$arg}, $class;
371efa05 84 } elsif(blessed $arg) {
3ade1c44 85 __PACKAGE__->_throw_error("Argument must be ->isa('Moose::Meta::TypeConstraint') or ->isa('MooseX::Types::UndefinedType'), not ". blessed $arg);
475bbd1d 86 } else {
3ade1c44 87 __PACKAGE__->_throw_error("Argument cannot be '$arg'");
475bbd1d 88 }
bb5b7b28 89 } else {
3ade1c44 90 __PACKAGE__->_throw_error("This method [new] requires a single argument.");
bb5b7b28 91 }
a706b0f2 92}
4c2125a4 93
5a9b6d38 94=head2 __type_constraint ($type_constraint)
4c2125a4 95
e088dd03 96Set/Get the type_constraint.
4c2125a4 97
98=cut
99
475bbd1d 100sub __type_constraint {
c1260541 101 my $self = shift @_;
371efa05 102 if(blessed $self) {
103 if(defined(my $tc = shift @_)) {
104 $self->{__type_constraint} = $tc;
105 }
106 return $self->{__type_constraint};
107 } else {
3ade1c44 108 __PACKAGE__->_throw_error('cannot call __type_constraint as a class method');
a706b0f2 109 }
a706b0f2 110}
4c2125a4 111
bb5b7b28 112=head2 isa
113
114handle $self->isa since AUTOLOAD can't.
115
116=cut
117
118sub isa {
371efa05 119 my ($self, $target) = @_;
bb5b7b28 120 if(defined $target) {
c1260541 121 if(blessed $self) {
122 return $self->__type_constraint->isa($target);
123 } else {
124 return;
125 }
bb5b7b28 126 } else {
127 return;
128 }
129}
130
3ade1c44 131
bb5b7b28 132=head2 can
133
134handle $self->can since AUTOLOAD can't.
135
136=cut
137
138sub can {
139 my ($self, $target) = @_;
140 if(defined $target) {
c1260541 141 if(blessed $self) {
142 return $self->__type_constraint->can($target);
143 } else {
144 return;
145 }
bb5b7b28 146 } else {
147 return;
148 }
149}
150
c1260541 151=head2 meta
152
153have meta examine the underlying type constraints
154
155=cut
156
157sub meta {
158 my $self = shift @_;
159 if(blessed $self) {
160 return $self->__type_constraint->meta;
161 }
162}
163
3ade1c44 164=head2 _throw_error
165
166properly delegate error messages
167
168=cut
169
170sub _throw_error {
171 shift;
172 require Moose;
173 unshift @_, 'Moose';
174 goto &Moose::throw_error;
175}
c1260541 176
a706b0f2 177=head2 DESTROY
4c2125a4 178
a706b0f2 179We might need it later
4c2125a4 180
a706b0f2 181=cut
4c2125a4 182
a706b0f2 183sub DESTROY {
184 return;
185}
4c2125a4 186
a706b0f2 187=head2 AUTOLOAD
4c2125a4 188
a706b0f2 189Delegate to the decorator targe
4c2125a4 190
a706b0f2 191=cut
4c2125a4 192
e088dd03 193sub AUTOLOAD {
077ac262 194
475bbd1d 195 my ($self, @args) = @_;
a706b0f2 196 my ($method) = (our $AUTOLOAD =~ /([^:]+)$/);
077ac262 197
198 ## We delegate with this method in an attempt to support a value of
199 ## __type_constraint which is also AUTOLOADing, in particular the class
200 ## MooseX::Types::UndefinedType which AUTOLOADs during autovivication.
201
202 my $return;
203
204 eval {
205 $return = $self->__type_constraint->$method(@args);
206 }; if($@) {
3ade1c44 207 __PACKAGE__->_throw_error($@);
475bbd1d 208 } else {
077ac262 209 return $return;
475bbd1d 210 }
a706b0f2 211}
4c2125a4 212
b55332a8 213=head1 AUTHOR
4c2125a4 214
b55332a8 215See L<MooseX::Types/AUTHOR>.
4c2125a4 216
217=head1 LICENSE
218
219This program is free software; you can redistribute it and/or modify
220it under the same terms as perl itself.
221
222=cut
223
2241;