2 package MooseX::Role::Parameterized;
4 extends => { -as => 'moose_extends' },
5 around => { -as => 'moose_around' },
11 moose_extends 'Moose::Exporter';
13 use MooseX::Role::Parameterized::Meta::Role::Parameterizable;
15 our $CURRENT_METACLASS;
17 __PACKAGE__->setup_import_methods(
18 with_caller => ['parameter', 'role', 'method'],
19 as_is => ['has', 'with', 'extends', 'requires', 'excludes', 'augment', 'inner', 'before', 'after', 'around', 'super', 'override', 'confess', 'blessed'],
26 $names = [$names] if !ref($names);
28 for my $name (@$names) {
29 Class::MOP::Class->initialize($caller)->add_parameter($name, @_);
35 my $role_generator = shift;
36 Class::MOP::Class->initialize($caller)->role_generator($role_generator);
42 return Moose::Role->init_meta(@_,
43 metaclass => 'MooseX::Role::Parameterized::Meta::Role::Parameterizable',
47 # give role a (&) prototype
48 moose_around _make_wrapper => sub {
50 my ($self, $caller, $sub, $fq_name) = @_;
52 if ($fq_name =~ /::role$/) {
53 return sub (&) { $sub->($caller, @_) };
60 confess "has must be called within the role { ... } block."
61 unless $CURRENT_METACLASS;
64 $names = [$names] if !ref($names);
66 for my $name (@$names) {
67 $CURRENT_METACLASS->add_attribute($name, @_);
72 confess "method must be called within the role { ... } block."
73 unless $CURRENT_METACLASS;
79 my $method = $CURRENT_METACLASS->method_metaclass->wrap(
80 package_name => $caller,
85 $CURRENT_METACLASS->add_method($name => $method);
89 confess "before must be called within the role { ... } block."
90 unless $CURRENT_METACLASS;
95 croak "Roles do not currently support "
97 . " references for before method modifiers"
99 $CURRENT_METACLASS->add_before_method_modifier($_, $code);
104 confess "after must be called within the role { ... } block."
105 unless $CURRENT_METACLASS;
110 croak "Roles do not currently support "
112 . " references for after method modifiers"
114 $CURRENT_METACLASS->add_after_method_modifier($_, $code);
119 confess "around must be called within the role { ... } block."
120 unless $CURRENT_METACLASS;
125 croak "Roles do not currently support "
127 . " references for around method modifiers"
129 $CURRENT_METACLASS->add_around_method_modifier($_, $code);
134 confess "with must be called within the role { ... } block."
135 unless $CURRENT_METACLASS;
136 Moose::Util::apply_all_roles($CURRENT_METACLASS, @_);
140 confess "requires must be called within the role { ... } block."
141 unless $CURRENT_METACLASS;
142 croak "Must specify at least one method" unless @_;
143 $CURRENT_METACLASS->add_required_methods(@_);
147 confess "excludes must be called within the role { ... } block."
148 unless $CURRENT_METACLASS;
149 croak "Must specify at least one role" unless @_;
150 $CURRENT_METACLASS->add_excluded_roles(@_);
153 # see Moose.pm for discussion
155 return unless $Moose::SUPER_BODY;
156 $Moose::SUPER_BODY->(@Moose::SUPER_ARGS);
160 confess "override must be called within the role { ... } block."
161 unless $CURRENT_METACLASS;
163 my ($name, $code) = @_;
164 $CURRENT_METACLASS->add_override_method_modifier($name, $code);
167 sub extends { croak "Roles do not currently support 'extends'" }
169 sub inner { croak "Roles cannot support 'inner'" }
171 sub augment { croak "Roles cannot support 'augment'" }
179 MooseX::Role::Parameterized - parameterized roles, at long last
183 package MyRole::Counter;
184 use MooseX::Role::Parameterized;
203 method "increment_$name" => sub {
205 $self->$name($self->$name + 1);
208 method "decrement_$name" => sub {
210 $self->$name($self->$name - 1);
214 package MyGame::Tile;
217 with 'MyRole::Counter' => { name => 'stepped_on' };
219 =head1 L<MooseX::Role::Parameterized::Tutorial>
221 B<Stop!> If you're new here, please read
222 L<MooseX::Role::Parameterized::Tutorial>.
226 Your parameterized role consists of two things: parameter declarations and a
229 Parameters are declared using the L</parameter> keyword which very much
230 resembles L<Moose/has>. You can use any option that L<Moose/has> accepts.
231 These parameters will get their values when the consuming class (or role) uses
232 L<Moose/with>. A parameter object will be constructed with these values, and
233 passed to the C<role> block.
235 The C<role> block then uses the usual L<Moose::Role> keywords to build up a
236 role. You can shift off the parameter object to inspect what the consuming
237 class provided as parameters. You can use the parameters to make your role
240 There are many paths to parameterized roles (hopefully with a consistent enough
241 API); I believe this to be the easiest and most flexible implementation.
242 Coincidentally, Pugs has a very similar design (I'm not convinced that that is
247 You must use this syntax to declare methods in the role block:
248 C<method NAME => sub { ... };>. This is due to a limitation in Perl. In return
249 though you can use parameters I<in your methods>!
251 L<Moose::Role/alias> and L<Moose::Role/excludes> are not yet supported. Because
252 I'm totally unsure of whether they should be handled by this module, both
253 declaring and providing a parameter named C<alias> or C<excludes> is an error.
257 Shawn M Moore, C<< <sartak@bestpractical.com> >>