c3b92121240ac3480b8429677ad269ae5d2d680d
[gitmo/Moose.git] / lib / Moose / Meta / Attribute / Native / Trait.pm
1
2 package Moose::Meta::Attribute::Native::Trait;
3 use Moose::Role;
4 use Moose::Util::TypeConstraints;
5
6 our $VERSION   = '1.14';
7 $VERSION = eval $VERSION;
8 our $AUTHORITY = 'cpan:STEVAN';
9
10 requires '_helper_type';
11
12 before '_process_options' => sub {
13     my ( $self, $name, $options ) = @_;
14
15     $self->_check_helper_type( $options, $name );
16
17     $options->{is} = $self->_default_is
18         if !exists $options->{is} && $self->can('_default_is');
19
20     $options->{default} = $self->_default_default
21         if !exists $options->{default} && $self->can('_default_default');
22 };
23
24 sub _check_helper_type {
25     my ( $self, $options, $name ) = @_;
26
27     my $type = $self->_helper_type;
28
29     $options->{isa} = $type
30         unless exists $options->{isa};
31
32     my $isa = Moose::Util::TypeConstraints::find_or_create_type_constraint(
33         $options->{isa} );
34
35     ( $isa->is_a_type_of($type) )
36         || confess
37         "The type constraint for $name must be a subtype of $type but it's a $isa";
38 }
39
40 before 'install_accessors' => sub { (shift)->_check_handles_values };
41
42 sub _check_handles_values {
43     my $self = shift;
44
45     my $method_constructors = $self->method_constructors;
46
47     my %handles = $self->_canonicalize_handles;
48
49     for my $original_method ( values %handles ) {
50         my $name = $original_method->[0];
51
52         my $accessor_class
53             = $self->_native_accessor_class_root . '::' . $name;
54
55         ( $accessor_class->can('new') || exists $method_constructors->{$name} )
56             || confess "$name is an unsupported method type";
57     }
58 }
59
60 around '_canonicalize_handles' => sub {
61     shift;
62     my $self    = shift;
63     my $handles = $self->handles;
64
65     return unless $handles;
66
67     unless ( 'HASH' eq ref $handles ) {
68         $self->throw_error(
69             "The 'handles' option must be a HASH reference, not $handles");
70     }
71
72     return map {
73         my $to = $handles->{$_};
74         $to = [$to] unless ref $to;
75         $_ => $to
76     } keys %$handles;
77 };
78
79 around '_make_delegation_method' => sub {
80     my $next = shift;
81     my ( $self, $handle_name, $method_to_call ) = @_;
82
83     my ( $name, @curried_args ) = @$method_to_call;
84
85     my $accessor_class
86         = $self->_native_accessor_class_root . '::' . $name;
87
88     if ( $accessor_class->can('new') ) {
89         return $accessor_class->new(
90             name              => $handle_name,
91             package_name      => $self->associated_class->name,
92             attribute         => $self,
93             curried_arguments => \@curried_args,
94         );
95     }
96     else {
97         my $method_constructors = $self->method_constructors;
98
99         my $code = $method_constructors->{$name}->(
100             $self,
101             $self->get_read_method_ref,
102             $self->get_write_method_ref,
103         );
104
105         return $next->(
106             $self,
107             $handle_name,
108             sub {
109                 my $instance = shift;
110                 return $code->( $instance, @curried_args, @_ );
111             }
112         );
113     }
114 };
115
116 sub _native_accessor_class_root {
117     my $self = shift;
118
119     return 'Moose::Meta::Method::Accessor::Native::' . $self->_native_type;
120 }
121
122 has 'method_constructors' => (
123     is      => 'ro',
124     isa     => 'HashRef',
125     lazy    => 1,
126     default => sub {
127         my $self = shift;
128         return +{}
129             unless $self->can('has_method_provider')
130                 && $self->has_method_provider;
131
132         # or grab them from the role/class
133         my $method_provider = $self->method_provider->meta;
134         return +{ map { $_->name => $_ }
135                 $method_provider->_get_local_methods };
136     },
137 );
138
139 no Moose::Role;
140 no Moose::Util::TypeConstraints;
141
142 1;
143
144 __END__
145
146 =head1 NAME
147
148 Moose::Meta::Attribute::Native::Trait - Base role for helpers
149
150 =head1 BUGS
151
152 See L<Moose/BUGS> for details on reporting bugs.
153
154 =head1 SEE ALSO
155
156 Documentation for Moose native traits starts at L<Moose::Meta::Attribute Native>
157
158 =head1 AUTHORS
159
160 Yuval Kogman
161
162 Shawn M Moore
163
164 Jesse Luehrs
165
166 =head1 COPYRIGHT AND LICENSE
167
168 Copyright 2007-2009 by Infinity Interactive, Inc.
169
170 L<http://www.iinteractive.com>
171
172 This library is free software; you can redistribute it and/or modify
173 it under the same terms as Perl itself.
174
175 =cut