start replacing provides/curries with handles
[gitmo/Moose.git] / lib / Moose / AttributeHelpers / Trait / Base.pm
1
2 package Moose::AttributeHelpers::Trait::Base;
3 use Moose::Role;
4 use Moose::Util::TypeConstraints;
5
6 our $VERSION   = '0.19';
7 $VERSION = eval $VERSION;
8 our $AUTHORITY = 'cpan:STEVAN';
9
10 requires 'helper_type';
11
12 # these next two are the possible methods
13 # you can use in the 'handles' map.
14
15 # provide a Class or Role which we can
16 # collect the method providers from
17
18 # requires_attr 'method_provider'
19
20 # or you can provide a HASH ref of anon subs
21 # yourself. This will also collect and store
22 # the methods from a method_provider as well
23 has 'method_constructors' => (
24     is      => 'ro',
25     isa     => 'HashRef',
26     lazy    => 1,
27     default => sub {
28         my $self = shift;
29         return +{} unless $self->has_method_provider;
30         # or grab them from the role/class
31         my $method_provider = $self->method_provider->meta;
32         return +{
33             map {
34                 $_ => $method_provider->get_method($_)
35             } $method_provider->get_method_list
36         };
37     },
38 );
39
40 # extend the parents stuff to make sure
41 # certain bits are now required ...
42 has '+default'         => (required => 1);
43 has '+type_constraint' => (required => 1);
44
45 ## Methods called prior to instantiation
46
47 sub process_options_for_handles {
48     my ($self, $options) = @_;
49
50     if (my $type = $self->helper_type) {
51         (exists $options->{isa})
52             || confess "You must define a type with the $type metaclass";
53
54         my $isa = $options->{isa};
55
56         unless (blessed($isa) && $isa->isa('Moose::Meta::TypeConstraint')) {
57             $isa = Moose::Util::TypeConstraints::find_or_create_type_constraint($isa);
58         }
59
60         ($isa->is_a_type_of($type))
61             || confess "The type constraint for a $type ($options->{isa}) must be a subtype of $type";
62     }
63 }
64
65 before '_process_options' => sub {
66     my ($self, $name, $options) = @_;
67     $self->process_options_for_handles($options, $name);
68 };
69
70 ## methods called after instantiation
71
72 sub check_handles_values {
73     my $self = shift;
74
75     my $method_constructors = $self->method_constructors;
76
77     foreach my $key (keys %{$self->handles}) {
78         (exists $method_constructors->{$key})
79             || confess "$key is an unsupported method type";
80     }
81
82 }
83
84 after 'install_accessors' => sub {
85     my $attr  = shift;
86     my $class = $attr->associated_class;
87
88     # grab the reader and writer methods
89     # as well, this will be useful for
90     # our method provider constructors
91     my $attr_reader = $attr->get_read_method_ref;
92     my $attr_writer = $attr->get_write_method_ref;
93
94     # before we install them, lets
95     # make sure they are valid
96     $attr->check_handles_values;
97
98     my $method_constructors = $attr->method_constructors;
99
100     my $class_name = $class->name;
101
102     foreach my $key (keys %{$attr->handles}) {
103
104         my $method_name = $attr->handles->{$key};
105
106         if ($class->has_method($method_name)) {
107             confess "The method ($method_name) already exists in class (" . $class->name . ")";
108         }
109
110         my $method = Moose::AttributeHelpers::Meta::Method::Provided->wrap(
111             $method_constructors->{$key}->(
112                 $attr,
113                 $attr_reader,
114                 $attr_writer,
115             ),
116             package_name => $class_name,
117             name => $method_name,
118         );
119
120         $attr->associate_method($method);
121         $class->add_method($method_name => $method);
122     }
123 };
124
125 after 'remove_accessors' => sub {
126     my $attr  = shift;
127     my $class = $attr->associated_class;
128
129     # provides accessors
130     foreach my $key (keys %{$attr->handles}) {
131         my $method_name = $attr->handles->{$key};
132         my $method = $class->get_method($method_name);
133         $class->remove_method($method_name)
134             if blessed($method) &&
135                $method->isa('Moose::AttributeHelpers::Meta::Method::Provided');
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::AttributeHelpers::Trait::Base - base role for helpers
149
150 =head1 METHODS
151
152 =head2 check_handles_values
153
154 Confirms that handles has all valid possibilities in it.
155
156 =head2 process_options_for_handles
157
158 Ensures that the type constraint (C<isa>) matches the helper type.
159
160 =head1 BUGS
161
162 All complex software has bugs lurking in it, and this module is no
163 exception. If you find a bug please either email me, or add the bug
164 to cpan-RT.
165
166 =head1 AUTHORS
167
168 Yuval Kogman
169
170 Shawn M Moore
171
172 Jesse Luehrs
173
174 =head1 COPYRIGHT AND LICENSE
175
176 Copyright 2007-2009 by Infinity Interactive, Inc.
177
178 L<http://www.iinteractive.com>
179
180 This library is free software; you can redistribute it and/or modify
181 it under the same terms as Perl itself.
182
183 =cut