various doc improvements
[gitmo/MooseX-Role-Parameterized.git] / lib / MooseX / Role / Parameterized.pm
CommitLineData
7b42fc96 1package MooseX::Role::Parameterized;
fc4a95b6 2use Moose (
3 extends => { -as => 'moose_extends' },
7557429d 4 around => { -as => 'moose_around' },
2293e5f1 5 qw/confess blessed/,
fc4a95b6 6);
767906ab 7moose_extends 'Moose::Exporter';
fc4a95b6 8
7b42fc96 9use Moose::Role ();
7b42fc96 10
d93bd54d 11use MooseX::Role::Parameterized::Meta::Role::Parameterizable;
5b82ffb1 12
a457ed60 13our $CURRENT_METACLASS;
4534bdce 14
5b82ffb1 15__PACKAGE__->setup_import_methods(
ff2ccd89 16 with_caller => ['parameter', 'role', 'method', 'has', 'with', 'extends',
17 'requires', 'excludes', 'augment', 'inner', 'before',
18 'after', 'around', 'super', 'override'],
19 as_is => [ 'confess', 'blessed' ],
19af6e75 20);
21
22sub parameter {
23 my $caller = shift;
4f3cfe3f 24
25 confess "'parameter' may not be used inside of the role block"
26 if $CURRENT_METACLASS;
27
ff2ccd89 28 my $meta = Class::MOP::Class->initialize($caller);
bd3dd853 29
ff2ccd89 30 my $names = shift;
bd3dd853 31 $names = [$names] if !ref($names);
32
33 for my $name (@$names) {
ff2ccd89 34 $meta->add_parameter($name, @_);
bd3dd853 35 }
19af6e75 36}
7b42fc96 37
e8e8ef39 38sub role (&) {
5b82ffb1 39 my $caller = shift;
40 my $role_generator = shift;
9a21e637 41 Class::MOP::Class->initialize($caller)->role_generator($role_generator);
5b82ffb1 42}
43
7b42fc96 44sub init_meta {
45 my $self = shift;
46
47 return Moose::Role->init_meta(@_,
d93bd54d 48 metaclass => 'MooseX::Role::Parameterized::Meta::Role::Parameterizable',
7b42fc96 49 );
50}
51
a457ed60 52sub has {
ff2ccd89 53 my $caller = shift;
54 my $meta = $CURRENT_METACLASS || Class::MOP::Class->initialize($caller);
a457ed60 55
209e00d2 56 my $names = shift;
a457ed60 57 $names = [$names] if !ref($names);
58
59 for my $name (@$names) {
ff2ccd89 60 $meta->add_attribute($name, @_);
a457ed60 61 }
62}
63
209e00d2 64sub method {
209e00d2 65 my $caller = shift;
ff2ccd89 66 my $meta = $CURRENT_METACLASS || Class::MOP::Class->initialize($caller);
67
209e00d2 68 my $name = shift;
69 my $body = shift;
70
ff2ccd89 71 my $method = $meta->method_metaclass->wrap(
209e00d2 72 package_name => $caller,
73 name => $name,
74 body => $body,
75 );
76
ff2ccd89 77 $meta->add_method($name => $method);
209e00d2 78}
79
03c4551d 80sub before {
ff2ccd89 81 my $caller = shift;
82 my $meta = $CURRENT_METACLASS || Class::MOP::Class->initialize($caller);
03c4551d 83
84 my $code = pop @_;
85
86 for (@_) {
767906ab 87 Carp::croak "Roles do not currently support "
03c4551d 88 . ref($_)
89 . " references for before method modifiers"
90 if ref $_;
ff2ccd89 91 $meta->add_before_method_modifier($_, $code);
03c4551d 92 }
93}
94
95sub after {
ff2ccd89 96 my $caller = shift;
97 my $meta = $CURRENT_METACLASS || Class::MOP::Class->initialize($caller);
03c4551d 98
99 my $code = pop @_;
100
101 for (@_) {
767906ab 102 Carp::croak "Roles do not currently support "
03c4551d 103 . ref($_)
104 . " references for after method modifiers"
105 if ref $_;
ff2ccd89 106 $meta->add_after_method_modifier($_, $code);
03c4551d 107 }
108}
109
110sub around {
ff2ccd89 111 my $caller = shift;
112 my $meta = $CURRENT_METACLASS || Class::MOP::Class->initialize($caller);
03c4551d 113
114 my $code = pop @_;
115
116 for (@_) {
767906ab 117 Carp::croak "Roles do not currently support "
03c4551d 118 . ref($_)
119 . " references for around method modifiers"
120 if ref $_;
ff2ccd89 121 $meta->add_around_method_modifier($_, $code);
03c4551d 122 }
123}
124
d55c8861 125sub with {
ff2ccd89 126 my $caller = shift;
127 my $meta = $CURRENT_METACLASS || Class::MOP::Class->initialize($caller);
128
129 Moose::Util::apply_all_roles($meta, @_);
d55c8861 130}
131
eac6d242 132sub requires {
ff2ccd89 133 my $caller = shift;
134 my $meta = $CURRENT_METACLASS || Class::MOP::Class->initialize($caller);
135
767906ab 136 Carp::croak "Must specify at least one method" unless @_;
ff2ccd89 137 $meta->add_required_methods(@_);
eac6d242 138}
139
fa627596 140sub excludes {
ff2ccd89 141 my $caller = shift;
142 my $meta = $CURRENT_METACLASS || Class::MOP::Class->initialize($caller);
143
767906ab 144 Carp::croak "Must specify at least one role" unless @_;
ff2ccd89 145 $meta->add_excluded_roles(@_);
fa627596 146}
147
20725a2d 148# see Moose.pm for discussion
149sub super {
150 return unless $Moose::SUPER_BODY;
151 $Moose::SUPER_BODY->(@Moose::SUPER_ARGS);
152}
153
154sub override {
ff2ccd89 155 my $caller = shift;
156 my $meta = $CURRENT_METACLASS || Class::MOP::Class->initialize($caller);
20725a2d 157
158 my ($name, $code) = @_;
ff2ccd89 159 $meta->add_override_method_modifier($name, $code);
20725a2d 160}
161
767906ab 162sub extends { Carp::croak "Roles do not currently support 'extends'" }
fc4a95b6 163
767906ab 164sub inner { Carp::croak "Roles cannot support 'inner'" }
fc4a95b6 165
767906ab 166sub augment { Carp::croak "Roles cannot support 'augment'" }
fc4a95b6 167
7b42fc96 1681;
169
a4ac31fa 170__END__
171
30788701 172=head1 NAME
173
174MooseX::Role::Parameterized - parameterized roles
175
a4ac31fa 176=head1 SYNOPSIS
177
178 package MyRole::Counter;
179 use MooseX::Role::Parameterized;
180
181 parameter name => (
a4ac31fa 182 isa => 'Str',
183 required => 1,
184 );
185
186 role {
187 my $p = shift;
188
189 my $name = $p->name;
190
191 has $name => (
192 is => 'rw',
193 isa => 'Int',
194 default => 0,
195 );
196
197 method "increment_$name" => sub {
198 my $self = shift;
199 $self->$name($self->$name + 1);
200 };
201
202 method "decrement_$name" => sub {
203 my $self = shift;
204 $self->$name($self->$name - 1);
205 };
206 };
207
208 package MyGame::Tile;
209 use Moose;
210
211 with 'MyRole::Counter' => { name => 'stepped_on' };
212
213=head1 L<MooseX::Role::Parameterized::Tutorial>
214
215B<Stop!> If you're new here, please read
216L<MooseX::Role::Parameterized::Tutorial>.
217
218=head1 DESCRIPTION
219
aeaaabaf 220Your parameterized role consists of two new things: parameter declarations
221and a C<role> block.
a4ac31fa 222
223Parameters are declared using the L</parameter> keyword which very much
fa2e6c00 224resembles L<Moose/has>. You can use any option that L<Moose/has> accepts. The
aeaaabaf 225default value for the C<is> option is C<ro> as that's a very common case. These
fa2e6c00 226parameters will get their values when the consuming class (or role) uses
a4ac31fa 227L<Moose/with>. A parameter object will be constructed with these values, and
228passed to the C<role> block.
229
230The C<role> block then uses the usual L<Moose::Role> keywords to build up a
231role. You can shift off the parameter object to inspect what the consuming
aeaaabaf 232class provided as parameters. You use the parameters to customize your
233role however you wish.
a4ac31fa 234
aeaaabaf 235There are many possible implementations for parameterized roles (hopefully with
236a consistent enough API); I believe this to be the easiest and most flexible
237design. Coincidentally, Pugs has an eerily similar design.
a4ac31fa 238
239=head1 CAVEATS
240
241You must use this syntax to declare methods in the role block:
08609551 242C<< method NAME => sub { ... }; >>. This is due to a limitation in Perl. In
243return though you can use parameters I<in your methods>!
a4ac31fa 244
9d029b3d 245L<Moose::Role/alias> and L<Moose::Role/excludes> are not yet supported. I'm
246completely unsure of whether they should be handled by this module. Until we
aeaaabaf 247figure out a plan, either declaring or providing a parameter named C<alias> or
9d029b3d 248C<excludes> is an error.
a4ac31fa 249
250=head1 AUTHOR
251
252Shawn M Moore, C<< <sartak@bestpractical.com> >>
253
d5487cd9 254=head1 EXAMPLES
988cddaa 255
d5487cd9 256=over 4
257
258=item L<MooseX::Role::Matcher>
259
d5487cd9 260=item L<MooseX::Role::XMLRPC::Client>
261
bfac2339 262=item L<MooseX::RelatedClassRoles>
263
d5487cd9 264=item L<WWW::Mechanize::TreeBuilder>
265
266=item L<TAEB::Action::Role::Item>
267
268=item L<KiokuDB::Role::Scan>
269
270=item L<Fey::Role::MakesAliasObjects>
271
272=item L<Fey::Role::HasAliasName>
273
274=item L<Fey::Role::SetOperation>
275
276=back
988cddaa 277
a4ac31fa 278=cut
279