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',
52 # give role a (&) prototype
53 moose_around _make_wrapper => sub {
55 my ($self, $caller, $sub, $fq_name) = @_;
57 if ($fq_name =~ /::role$/) {
58 return sub (&) { $sub->($caller, @_) };
66 my $meta = $CURRENT_METACLASS || Class::MOP::Class->initialize($caller);
69 $names = [$names] if !ref($names);
71 for my $name (@$names) {
72 $meta->add_attribute($name, @_);
78 my $meta = $CURRENT_METACLASS || Class::MOP::Class->initialize($caller);
83 my $method = $meta->method_metaclass->wrap(
84 package_name => $caller,
89 $meta->add_method($name => $method);
94 my $meta = $CURRENT_METACLASS || Class::MOP::Class->initialize($caller);
99 Carp::croak "Roles do not currently support "
101 . " references for before method modifiers"
103 $meta->add_before_method_modifier($_, $code);
109 my $meta = $CURRENT_METACLASS || Class::MOP::Class->initialize($caller);
114 Carp::croak "Roles do not currently support "
116 . " references for after method modifiers"
118 $meta->add_after_method_modifier($_, $code);
124 my $meta = $CURRENT_METACLASS || Class::MOP::Class->initialize($caller);
129 Carp::croak "Roles do not currently support "
131 . " references for around method modifiers"
133 $meta->add_around_method_modifier($_, $code);
139 my $meta = $CURRENT_METACLASS || Class::MOP::Class->initialize($caller);
141 Moose::Util::apply_all_roles($meta, @_);
146 my $meta = $CURRENT_METACLASS || Class::MOP::Class->initialize($caller);
148 Carp::croak "Must specify at least one method" unless @_;
149 $meta->add_required_methods(@_);
154 my $meta = $CURRENT_METACLASS || Class::MOP::Class->initialize($caller);
156 Carp::croak "Must specify at least one role" unless @_;
157 $meta->add_excluded_roles(@_);
160 # see Moose.pm for discussion
162 return unless $Moose::SUPER_BODY;
163 $Moose::SUPER_BODY->(@Moose::SUPER_ARGS);
168 my $meta = $CURRENT_METACLASS || Class::MOP::Class->initialize($caller);
170 my ($name, $code) = @_;
171 $meta->add_override_method_modifier($name, $code);
174 sub extends { Carp::croak "Roles do not currently support 'extends'" }
176 sub inner { Carp::croak "Roles cannot support 'inner'" }
178 sub augment { Carp::croak "Roles cannot support 'augment'" }
186 MooseX::Role::Parameterized - parameterized roles
190 package MyRole::Counter;
191 use MooseX::Role::Parameterized;
210 method "increment_$name" => sub {
212 $self->$name($self->$name + 1);
215 method "decrement_$name" => sub {
217 $self->$name($self->$name - 1);
221 package MyGame::Tile;
224 with 'MyRole::Counter' => { name => 'stepped_on' };
226 =head1 L<MooseX::Role::Parameterized::Tutorial>
228 B<Stop!> If you're new here, please read
229 L<MooseX::Role::Parameterized::Tutorial>.
233 Your parameterized role consists of two things: parameter declarations and a
236 Parameters are declared using the L</parameter> keyword which very much
237 resembles L<Moose/has>. You can use any option that L<Moose/has> accepts.
238 These parameters will get their values when the consuming class (or role) uses
239 L<Moose/with>. A parameter object will be constructed with these values, and
240 passed to the C<role> block.
242 The C<role> block then uses the usual L<Moose::Role> keywords to build up a
243 role. You can shift off the parameter object to inspect what the consuming
244 class provided as parameters. You can use the parameters to make your role
247 There are many paths to parameterized roles (hopefully with a consistent enough
248 API); I believe this to be the easiest and most flexible implementation.
249 Coincidentally, Pugs has a very similar design (I'm not yet convinced that that
254 You must use this syntax to declare methods in the role block:
255 C<< method NAME => sub { ... }; >>. This is due to a limitation in Perl. In
256 return though you can use parameters I<in your methods>!
258 L<Moose::Role/alias> and L<Moose::Role/excludes> are not yet supported. I'm
259 completely unsure of whether they should be handled by this module. Until we
260 figure out a plan, both declaring and providing a parameter named C<alias> or
261 C<excludes> is an error.
265 Shawn M Moore, C<< <sartak@bestpractical.com> >>
269 L<MooseX::Role::Matcher>