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