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' ],
24 my $meta = Class::MOP::Class->initialize($caller);
27 $names = [$names] if !ref($names);
29 for my $name (@$names) {
30 $meta->add_parameter($name, @_);
36 my $role_generator = shift;
37 Class::MOP::Class->initialize($caller)->role_generator($role_generator);
43 return Moose::Role->init_meta(@_,
44 metaclass => 'MooseX::Role::Parameterized::Meta::Role::Parameterizable',
48 # give role a (&) prototype
49 moose_around _make_wrapper => sub {
51 my ($self, $caller, $sub, $fq_name) = @_;
53 if ($fq_name =~ /::role$/) {
54 return sub (&) { $sub->($caller, @_) };
62 my $meta = $CURRENT_METACLASS || Class::MOP::Class->initialize($caller);
65 $names = [$names] if !ref($names);
67 for my $name (@$names) {
68 $meta->add_attribute($name, @_);
74 my $meta = $CURRENT_METACLASS || Class::MOP::Class->initialize($caller);
79 my $method = $meta->method_metaclass->wrap(
80 package_name => $caller,
85 $meta->add_method($name => $method);
90 my $meta = $CURRENT_METACLASS || Class::MOP::Class->initialize($caller);
95 Carp::croak "Roles do not currently support "
97 . " references for before method modifiers"
99 $meta->add_before_method_modifier($_, $code);
105 my $meta = $CURRENT_METACLASS || Class::MOP::Class->initialize($caller);
110 Carp::croak "Roles do not currently support "
112 . " references for after method modifiers"
114 $meta->add_after_method_modifier($_, $code);
120 my $meta = $CURRENT_METACLASS || Class::MOP::Class->initialize($caller);
125 Carp::croak "Roles do not currently support "
127 . " references for around method modifiers"
129 $meta->add_around_method_modifier($_, $code);
135 my $meta = $CURRENT_METACLASS || Class::MOP::Class->initialize($caller);
137 Moose::Util::apply_all_roles($meta, @_);
142 my $meta = $CURRENT_METACLASS || Class::MOP::Class->initialize($caller);
144 Carp::croak "Must specify at least one method" unless @_;
145 $meta->add_required_methods(@_);
150 my $meta = $CURRENT_METACLASS || Class::MOP::Class->initialize($caller);
152 Carp::croak "Must specify at least one role" unless @_;
153 $meta->add_excluded_roles(@_);
156 # see Moose.pm for discussion
158 return unless $Moose::SUPER_BODY;
159 $Moose::SUPER_BODY->(@Moose::SUPER_ARGS);
164 my $meta = $CURRENT_METACLASS || Class::MOP::Class->initialize($caller);
166 my ($name, $code) = @_;
167 $meta->add_override_method_modifier($name, $code);
170 sub extends { Carp::croak "Roles do not currently support 'extends'" }
172 sub inner { Carp::croak "Roles cannot support 'inner'" }
174 sub augment { Carp::croak "Roles cannot support 'augment'" }
182 MooseX::Role::Parameterized - parameterized roles
186 package MyRole::Counter;
187 use MooseX::Role::Parameterized;
206 method "increment_$name" => sub {
208 $self->$name($self->$name + 1);
211 method "decrement_$name" => sub {
213 $self->$name($self->$name - 1);
217 package MyGame::Tile;
220 with 'MyRole::Counter' => { name => 'stepped_on' };
222 =head1 L<MooseX::Role::Parameterized::Tutorial>
224 B<Stop!> If you're new here, please read
225 L<MooseX::Role::Parameterized::Tutorial>.
229 Your parameterized role consists of two things: parameter declarations and a
232 Parameters are declared using the L</parameter> keyword which very much
233 resembles L<Moose/has>. You can use any option that L<Moose/has> accepts.
234 These parameters will get their values when the consuming class (or role) uses
235 L<Moose/with>. A parameter object will be constructed with these values, and
236 passed to the C<role> block.
238 The C<role> block then uses the usual L<Moose::Role> keywords to build up a
239 role. You can shift off the parameter object to inspect what the consuming
240 class provided as parameters. You can use the parameters to make your role
243 There are many paths to parameterized roles (hopefully with a consistent enough
244 API); I believe this to be the easiest and most flexible implementation.
245 Coincidentally, Pugs has a very similar design (I'm not yet convinced that that
250 You must use this syntax to declare methods in the role block:
251 C<< method NAME => sub { ... }; >>. This is due to a limitation in Perl. In
252 return though you can use parameters I<in your methods>!
254 L<Moose::Role/alias> and L<Moose::Role/excludes> are not yet supported. I'm
255 completely unsure of whether they should be handled by this module. Until we
256 figure out a plan, both declaring and providing a parameter named C<alias> or
257 C<excludes> is an error.
261 Shawn M Moore, C<< <sartak@bestpractical.com> >>