1 package MooseX::Role::Parameterized;
3 extends => { -as => 'moose_extends' },
4 around => { -as => 'moose_around' },
7 moose_extends 'Moose::Exporter';
11 use MooseX::Role::Parameterized::Meta::Role::Parameterizable;
13 our $CURRENT_METACLASS;
15 __PACKAGE__->setup_import_methods(
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' ],
25 confess "'parameter' may not be used inside of the role block"
26 if $CURRENT_METACLASS;
28 my $meta = Class::MOP::Class->initialize($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->initialize($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->initialize($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->initialize($caller);
71 my $method = $meta->method_metaclass->wrap(
72 package_name => $caller,
77 $meta->add_method($name => $method);
82 my $meta = $CURRENT_METACLASS || Class::MOP::Class->initialize($caller);
87 Carp::croak "Roles do not currently support "
89 . " references for before method modifiers"
91 $meta->add_before_method_modifier($_, $code);
97 my $meta = $CURRENT_METACLASS || Class::MOP::Class->initialize($caller);
102 Carp::croak "Roles do not currently support "
104 . " references for after method modifiers"
106 $meta->add_after_method_modifier($_, $code);
112 my $meta = $CURRENT_METACLASS || Class::MOP::Class->initialize($caller);
117 Carp::croak "Roles do not currently support "
119 . " references for around method modifiers"
121 $meta->add_around_method_modifier($_, $code);
127 my $meta = $CURRENT_METACLASS || Class::MOP::Class->initialize($caller);
129 Moose::Util::apply_all_roles($meta, @_);
134 my $meta = $CURRENT_METACLASS || Class::MOP::Class->initialize($caller);
136 Carp::croak "Must specify at least one method" unless @_;
137 $meta->add_required_methods(@_);
142 my $meta = $CURRENT_METACLASS || Class::MOP::Class->initialize($caller);
144 Carp::croak "Must specify at least one role" unless @_;
145 $meta->add_excluded_roles(@_);
148 # see Moose.pm for discussion
150 return unless $Moose::SUPER_BODY;
151 $Moose::SUPER_BODY->(@Moose::SUPER_ARGS);
156 my $meta = $CURRENT_METACLASS || Class::MOP::Class->initialize($caller);
158 my ($name, $code) = @_;
159 $meta->add_override_method_modifier($name, $code);
162 sub extends { Carp::croak "Roles do not currently support 'extends'" }
164 sub inner { Carp::croak "Roles cannot support 'inner'" }
166 sub augment { Carp::croak "Roles cannot support 'augment'" }
174 MooseX::Role::Parameterized - parameterized roles
178 package MyRole::Counter;
179 use MooseX::Role::Parameterized;
197 method "increment_$name" => sub {
199 $self->$name($self->$name + 1);
202 method "decrement_$name" => sub {
204 $self->$name($self->$name - 1);
208 package MyGame::Tile;
211 with 'MyRole::Counter' => { name => 'stepped_on' };
213 =head1 L<MooseX::Role::Parameterized::Tutorial>
215 B<Stop!> If you're new here, please read
216 L<MooseX::Role::Parameterized::Tutorial>.
220 Your parameterized role consists of two new things: parameter declarations
223 Parameters are declared using the L</parameter> keyword which very much
224 resembles L<Moose/has>. You can use any option that L<Moose/has> accepts. The
225 default value for the C<is> option is C<ro> as that's a very common case. These
226 parameters will get their values when the consuming class (or role) uses
227 L<Moose/with>. A parameter object will be constructed with these values, and
228 passed to the C<role> block.
230 The C<role> block then uses the usual L<Moose::Role> keywords to build up a
231 role. You can shift off the parameter object to inspect what the consuming
232 class provided as parameters. You use the parameters to customize your
233 role however you wish.
235 There are many possible implementations for parameterized roles (hopefully with
236 a consistent enough API); I believe this to be the easiest and most flexible
237 design. Coincidentally, Pugs originally had an eerily similar design.
239 =head2 Why a parameters object?
241 I've been asked several times "Why use a parameter I<object> and not just a
242 parameter I<hashref>? That would eliminate the need to explicitly declare your
245 The benefits of using an object are similar to the benefits of using Moose. You
246 get an easy way to specify lazy defaults, type constraint, delegation, and so
247 on. You get to use MooseX modules.
249 You also get the usual introspective and intercessory abilities that come
250 standard with the metaobject protocol. Ambitious users should be able to add
251 traits to the parameters metaclass to further customize behavior. Please let
252 me know if you're doing anything viciously complicated with this extension. :)
256 You must use this syntax to declare methods in the role block:
257 C<< method NAME => sub { ... }; >>. This is due to a limitation in Perl. In
258 return though you can use parameters I<in your methods>!
260 L<Moose::Role/alias> and L<Moose::Role/excludes> are not yet supported. I'm
261 completely unsure of whether they should be handled by this module. Until we
262 figure out a plan, either declaring or providing a parameter named C<alias> or
263 C<excludes> is an error.
267 Shawn M Moore, C<< <sartak@bestpractical.com> >>
273 =item L<MooseX::Role::Matcher>
275 =item L<MooseX::Role::XMLRPC::Client>
277 =item L<MooseX::RelatedClassRoles>
279 =item L<WWW::Mechanize::TreeBuilder>
281 =item L<TAEB::Action::Role::Item>
283 =item L<KiokuDB::Role::Scan>
285 =item L<Fey::Role::MakesAliasObjects>
287 =item L<Fey::Role::HasAliasName>
289 =item L<Fey::Role::SetOperation>