1 package MooseX::Role::Parameterized;
6 use Scalar::Util 'blessed';
8 use MooseX::Role::Parameterized::Meta::Role::Parameterizable;
10 our $VERSION = '0.14';
11 our $CURRENT_METACLASS;
13 Moose::Exporter->setup_import_methods(
14 with_caller => ['parameter', 'role', 'method', 'has', 'with', 'extends',
15 'requires', 'excludes', 'augment', 'inner', 'before',
16 'after', 'around', 'super', 'override'],
17 as_is => [ 'confess', 'blessed' ],
20 sub current_metaclass { $CURRENT_METACLASS }
25 confess "'parameter' may not be used inside of the role block"
26 if $CURRENT_METACLASS && $CURRENT_METACLASS->genitor->name eq $caller;
28 my $meta = Class::MOP::class_of($caller);
31 $names = [$names] if !ref($names);
33 for my $name (@$names) {
34 $meta->add_parameter($name, @_);
40 my $role_generator = shift;
41 Class::MOP::class_of($caller)->role_generator($role_generator);
47 return Moose::Role->init_meta(@_,
48 metaclass => 'MooseX::Role::Parameterized::Meta::Role::Parameterizable',
54 my $meta = $CURRENT_METACLASS || Class::MOP::class_of($caller);
57 $names = [$names] if !ref($names);
59 for my $name (@$names) {
60 $meta->add_attribute($name, @_);
66 my $meta = $CURRENT_METACLASS || Class::MOP::class_of($caller);
71 my $method = $meta->method_metaclass->wrap(
72 package_name => $caller,
77 $meta->add_method($name => $method);
80 sub _add_method_modifier {
83 my $meta = $CURRENT_METACLASS || Class::MOP::class_of($caller);
88 Carp::croak "Roles do not currently support "
90 . " references for $type method modifiers"
93 my $add_method = "add_${type}_method_modifier";
94 $meta->$add_method($_, $code);
99 _add_method_modifier('before', @_);
103 _add_method_modifier('after', @_);
107 _add_method_modifier('around', @_);
112 my $meta = $CURRENT_METACLASS || Class::MOP::class_of($caller);
114 Moose::Util::apply_all_roles($meta, @_);
119 my $meta = $CURRENT_METACLASS || Class::MOP::class_of($caller);
121 Carp::croak "Must specify at least one method" unless @_;
122 $meta->add_required_methods(@_);
127 my $meta = $CURRENT_METACLASS || Class::MOP::class_of($caller);
129 Carp::croak "Must specify at least one role" unless @_;
130 $meta->add_excluded_roles(@_);
133 # see Moose.pm for discussion
135 return unless $Moose::SUPER_BODY;
136 $Moose::SUPER_BODY->(@Moose::SUPER_ARGS);
141 my $meta = $CURRENT_METACLASS || Class::MOP::class_of($caller);
143 my ($name, $code) = @_;
144 $meta->add_override_method_modifier($name, $code);
147 sub extends { Carp::croak "Roles do not currently support 'extends'" }
149 sub inner { Carp::croak "Roles cannot support 'inner'" }
151 sub augment { Carp::croak "Roles cannot support 'augment'" }
159 MooseX::Role::Parameterized - roles with composition parameters
164 use MooseX::Role::Parameterized;
182 method "increment_$name" => sub {
184 $self->$name($self->$name + 1);
187 method "reset_$name" => sub {
193 package MyGame::Weapon;
196 with Counter => { name => 'enchantment' };
198 package MyGame::Wand;
201 with Counter => { name => 'zapped' };
203 =head1 L<MooseX::Role::Parameterized::Tutorial>
205 B<Stop!> If you're new here, please read
206 L<MooseX::Role::Parameterized::Tutorial> for a much gentler introduction.
210 Your parameterized role consists of two new things: parameter declarations
213 Parameters are declared using the L</parameter> keyword which very much
214 resembles L<Moose/has>. You can use any option that L<Moose/has> accepts. The
215 default value for the C<is> option is C<ro> as that's a very common case. Use
216 C<< is => 'bare' >> if you want no accessor. These parameters will get their
217 values when the consuming class (or role) uses L<Moose/with>. A parameter
218 object will be constructed with these values, and passed to the C<role> block.
220 The C<role> block then uses the usual L<Moose::Role> keywords to build up a
221 role. You can shift off the parameter object to inspect what the consuming
222 class provided as parameters. You use the parameters to customize your
223 role however you wish.
225 There are many possible implementations for parameterized roles (hopefully with
226 a consistent enough API); I believe this to be the easiest and most flexible
227 design. Coincidentally, Pugs originally had an eerily similar design.
229 =head2 Why a parameters object?
231 I've been asked several times "Why use a parameter I<object> and not just a
232 parameter I<hashref>? That would eliminate the need to explicitly declare your
235 The benefits of using an object are similar to the benefits of using Moose. You
236 get an easy way to specify lazy defaults, type constraint, delegation, and so
237 on. You get to use MooseX modules.
239 You also get the usual introspective and intercessory abilities that come
240 standard with the metaobject protocol. Ambitious users should be able to add
241 traits to the parameters metaclass to further customize behavior. Please let
242 me know if you're doing anything viciously complicated with this extension. :)
246 You must use this syntax to declare methods in the role block:
247 C<< method NAME => sub { ... }; >>. This is due to a limitation in Perl. In
248 return though you can use parameters I<in your methods>!
250 L<Moose::Role/alias> and L<Moose::Role/excludes> are not yet supported. I'm
251 completely unsure of whether they should be handled by this module. Until we
252 figure out a plan, either declaring or providing a parameter named C<alias> or
253 C<excludes> is an error.
257 Shawn M Moore, C<sartak@gmail.com>
263 =item L<Fey::Role::HasAliasName>
265 =item L<Fey::Role::MakesAliasObjects>
267 =item L<Fey::Role::SQL::Cloneable>
269 =item L<Fey::Role::SetOperation>
271 =item L<IM::Engine::PluggableConstructor>
273 =item L<IM::Engine::RequiresPlugins>
275 =item L<KiokuDB::Role::Scan>
277 =item L<MooseX::RelatedClassRoles>
279 =item L<MooseX::Role::Matcher>
281 =item L<MooseX::Role::XMLRPC::Client>
283 =item L<MooseX::WithCache>
285 =item L<Net::Journyx::Object::Loadable>
287 =item L<NetHack::Item::Role::IncorporatesStats>
289 =item L<TAEB::Action::Role::Item>
291 =item L<WWW::Mechanize::TreeBuilder>
297 L<http://sartak.blogspot.com/2009/05/parameterized-roles.html>
299 L<http://stevan-little.blogspot.com/2009/07/thoughts-on-parameterized-roles.html>
301 L<http://sartak.org/talks/yapc-asia-2009/(parameterized)-roles/>
303 =head1 COPYRIGHT AND LICENSE
305 Copyright 2007-2009 Infinity Interactive
307 This program is free software; you can redistribute it and/or modify it
308 under the same terms as Perl itself.