Add set method to Counter and let inc/dec take args.
[gitmo/MooseX-AttributeHelpers.git] / lib / MooseX / AttributeHelpers / Base.pm
CommitLineData
d26633fc 1
2package MooseX::AttributeHelpers::Base;
3use Moose;
8ba40fb0 4use Moose::Util::TypeConstraints;
d26633fc 5
999f34a9 6our $VERSION = '0.04';
d26633fc 7our $AUTHORITY = 'cpan:STEVAN';
8
9extends 'Moose::Meta::Attribute';
10
8e3fab6d 11# this is the method map you define ...
d26633fc 12has 'provides' => (
9810162d 13 is => 'ro',
14 isa => 'HashRef',
15 default => sub {{}}
d26633fc 16);
17
c43a2317 18has 'curries' => (
19 is => 'ro',
20 isa => 'HashRef',
21 default => sub {{}}
22);
23
8e3fab6d 24
999f34a9 25# these next two are the possible methods
8e3fab6d 26# you can use in the 'provides' map.
27
999f34a9 28# provide a Class or Role which we can
29# collect the method providers from
8e3fab6d 30has 'method_provider' => (
31 is => 'ro',
32 isa => 'ClassName',
33 predicate => 'has_method_provider',
34);
35
36# or you can provide a HASH ref of anon subs
37# yourself. This will also collect and store
999f34a9 38# the methods from a method_provider as well
8e3fab6d 39has 'method_constructors' => (
40 is => 'ro',
41 isa => 'HashRef',
42 lazy => 1,
43 default => sub {
44 my $self = shift;
45 return +{} unless $self->has_method_provider;
46 # or grab them from the role/class
47 my $method_provider = $self->method_provider->meta;
48 return +{
999f34a9 49 map {
8e3fab6d 50 $_ => $method_provider->get_method($_)
51 } $method_provider->get_method_list
999f34a9 52 };
e295d072 53 },
8e3fab6d 54);
55
999f34a9 56# extend the parents stuff to make sure
8881a8d3 57# certain bits are now required ...
d26633fc 58has '+$!default' => (required => 1);
59has '+type_constraint' => (required => 1);
60
8ba40fb0 61## Methods called prior to instantiation
62
63sub helper_type { () }
d26633fc 64
8ba40fb0 65sub process_options_for_provides {
d26633fc 66 my ($self, $options) = @_;
999f34a9 67
8ba40fb0 68 if (my $type = $self->helper_type) {
69 (exists $options->{isa})
999f34a9 70 || confess "You must define a type with the $type metaclass";
8ba40fb0 71
999f34a9 72 my $isa = $options->{isa};
8ba40fb0 73
74 unless (blessed($isa) && $isa->isa('Moose::Meta::TypeConstraint')) {
999f34a9 75 $isa = Moose::Util::TypeConstraints::find_or_create_type_constraint($isa);
8ba40fb0 76 }
77
78 ($isa->is_a_type_of($type))
79 || confess "The type constraint for a $type ($options->{isa}) must be a subtype of $type";
80 }
d26633fc 81}
82
83before '_process_options' => sub {
88aaf2bd 84 my ($self, $name, $options) = @_;
38abf787 85 $self->process_options_for_provides($options, $name);
d26633fc 86};
87
8ba40fb0 88## methods called after instantiation
89
999f34a9 90# this confirms that provides has
8ba40fb0 91# all valid possibilities in it
92sub check_provides_values {
93 my $self = shift;
999f34a9 94
8ba40fb0 95 my $method_constructors = $self->method_constructors;
999f34a9 96
8ba40fb0 97 foreach my $key (keys %{$self->provides}) {
98 (exists $method_constructors->{$key})
99 || confess "$key is an unsupported method type";
100 }
101}
102
c43a2317 103sub _curry {
104 my $self = shift;
105 my $code = shift;
106
107 #warn "_curry: "; use DDS; warn Dump($self);
108 my @args = @_;
109 return sub { my $self = shift; $code->($self, @args, @_) };
110}
111
d26633fc 112after 'install_accessors' => sub {
113 my $attr = shift;
114 my $class = $attr->associated_class;
999f34a9 115
457dc4fb 116 # grab the reader and writer methods
999f34a9 117 # as well, this will be useful for
457dc4fb 118 # our method provider constructors
9a976497 119 my $attr_reader = $attr->get_read_method_ref;
120 my $attr_writer = $attr->get_write_method_ref;
999f34a9 121
d26633fc 122
88aaf2bd 123 # before we install them, lets
124 # make sure they are valid
999f34a9 125 $attr->check_provides_values;
c43a2317 126# $attr->check_curries_values;
88aaf2bd 127
d26633fc 128 my $method_constructors = $attr->method_constructors;
999f34a9 129
dc4333e9 130 my $class_name = $class->name;
131
c43a2317 132 foreach my $key (keys %{$attr->curries}) {
133
134 my ($curried_name, @curried_args) = @{ $attr->curries->{$key} };
135
136 if ($class->has_method($curried_name)) {
137 confess "The method ($curried_name) already exists in class (" . $class->name . ")";
138 }
139
140 my $method = MooseX::AttributeHelpers::Meta::Method::Curried->wrap(
141 $attr->_curry($method_constructors->{$key}->(
142 $attr,
143 $attr_reader,
144 $attr_writer,
145 ), @curried_args),
146 package_name => $class_name,
147 name => $curried_name,
148 );
149
150#use DDS; warn Dump($method);
151
152 $attr->associate_method($method);
153 $class->add_method($curried_name => $method);
154 }
155
d26633fc 156 foreach my $key (keys %{$attr->provides}) {
999f34a9 157
158 my $method_name = $attr->provides->{$key};
159
9a976497 160 if ($class->has_method($method_name)) {
161 confess "The method ($method_name) already exists in class (" . $class->name . ")";
999f34a9 162 }
163
164 my $method = MooseX::AttributeHelpers::Meta::Method::Provided->wrap(
165 $method_constructors->{$key}->(
166 $attr,
167 $attr_reader,
168 $attr_writer,
dc4333e9 169 ),
170 package_name => $class_name,
171 name => $method_name,
d26633fc 172 );
999f34a9 173
174 $attr->associate_method($method);
175 $class->add_method($method_name => $method);
176 }
177};
178
179after 'remove_accessors' => sub {
180 my $attr = shift;
181 my $class = $attr->associated_class;
182 foreach my $key (keys %{$attr->provides}) {
183 my $method_name = $attr->provides->{$key};
184 my $method = $class->get_method($method_name);
185 $class->remove_method($method_name)
186 if blessed($method) &&
187 $method->isa('MooseX::AttributeHelpers::Meta::Method::Provided');
d26633fc 188 }
189};
190
191no Moose;
8ba40fb0 192no Moose::Util::TypeConstraints;
d26633fc 193
1941;
195
196__END__
197
198=pod
199
200=head1 NAME
201
5431dff2 202MooseX::AttributeHelpers::Base - Base class for attribute helpers
999f34a9 203
d26633fc 204=head1 DESCRIPTION
205
5431dff2 206Documentation to come.
e295d072 207
208=head1 ATTRIBUTES
209
5431dff2 210=over 4
211
212=item B<provides>
e295d072 213
5431dff2 214=item B<method_provider>
e295d072 215
5431dff2 216=item B<method_constructors>
217
218=back
e295d072 219
220=head1 EXTENDED ATTRIBUTES
221
5431dff2 222=over 4
223
224=item B<$!default>
e295d072 225
226C<$!default> is now required.
227
5431dff2 228=item B<type_constraint>
e295d072 229
230C<type_constraint> is now required.
231
5431dff2 232=back
233
d26633fc 234=head1 METHODS
235
5431dff2 236=over 4
237
b91f57af 238=item B<meta>
239
5431dff2 240=item B<helper_type>
241
242=item B<check_provides_values>
243
244=item B<has_default>
245
246=item B<has_method_provider>
247
248=item B<has_type_constraint>
249
250=item B<install_accessors>
251
999f34a9 252=item B<remove_accessors>
253
5431dff2 254=item B<process_options_for_provides>
255
256=back
e295d072 257
d26633fc 258=head1 BUGS
259
999f34a9 260All complex software has bugs lurking in it, and this module is no
d26633fc 261exception. If you find a bug please either email me, or add the bug
262to cpan-RT.
263
264=head1 AUTHOR
265
266Stevan Little E<lt>stevan@iinteractive.comE<gt>
267
268=head1 COPYRIGHT AND LICENSE
269
99c62fb8 270Copyright 2007-2008 by Infinity Interactive, Inc.
d26633fc 271
272L<http://www.iinteractive.com>
273
274This library is free software; you can redistribute it and/or modify
275it under the same terms as Perl itself.
276
8a9cea9b 277=cut