1 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', 'has', 'with', 'extends',
19 'requires', 'excludes', 'augment', 'inner', 'before',
20 'after', 'around', 'super', 'override'],
21 as_is => [ 'confess', 'blessed' ],
26 my $meta = Class::MOP::Class->initialize($caller);
29 $names = [$names] if !ref($names);
31 for my $name (@$names) {
32 $meta->add_parameter($name, @_);
38 my $role_generator = shift;
39 Class::MOP::Class->initialize($caller)->role_generator($role_generator);
45 return Moose::Role->init_meta(@_,
46 metaclass => 'MooseX::Role::Parameterized::Meta::Role::Parameterizable',
50 # give role a (&) prototype
51 moose_around _make_wrapper => sub {
53 my ($self, $caller, $sub, $fq_name) = @_;
55 if ($fq_name =~ /::role$/) {
56 return sub (&) { $sub->($caller, @_) };
64 my $meta = $CURRENT_METACLASS || Class::MOP::Class->initialize($caller);
67 $names = [$names] if !ref($names);
69 for my $name (@$names) {
70 $meta->add_attribute($name, @_);
76 my $meta = $CURRENT_METACLASS || Class::MOP::Class->initialize($caller);
81 my $method = $meta->method_metaclass->wrap(
82 package_name => $caller,
87 $meta->add_method($name => $method);
92 my $meta = $CURRENT_METACLASS || Class::MOP::Class->initialize($caller);
97 croak "Roles do not currently support "
99 . " references for before method modifiers"
101 $meta->add_before_method_modifier($_, $code);
107 my $meta = $CURRENT_METACLASS || Class::MOP::Class->initialize($caller);
112 croak "Roles do not currently support "
114 . " references for after method modifiers"
116 $meta->add_after_method_modifier($_, $code);
122 my $meta = $CURRENT_METACLASS || Class::MOP::Class->initialize($caller);
127 croak "Roles do not currently support "
129 . " references for around method modifiers"
131 $meta->add_around_method_modifier($_, $code);
137 my $meta = $CURRENT_METACLASS || Class::MOP::Class->initialize($caller);
139 Moose::Util::apply_all_roles($meta, @_);
144 my $meta = $CURRENT_METACLASS || Class::MOP::Class->initialize($caller);
146 croak "Must specify at least one method" unless @_;
147 $meta->add_required_methods(@_);
152 my $meta = $CURRENT_METACLASS || Class::MOP::Class->initialize($caller);
154 croak "Must specify at least one role" unless @_;
155 $meta->add_excluded_roles(@_);
158 # see Moose.pm for discussion
160 return unless $Moose::SUPER_BODY;
161 $Moose::SUPER_BODY->(@Moose::SUPER_ARGS);
166 my $meta = $CURRENT_METACLASS || Class::MOP::Class->initialize($caller);
168 my ($name, $code) = @_;
169 $meta->add_override_method_modifier($name, $code);
172 sub extends { croak "Roles do not currently support 'extends'" }
174 sub inner { croak "Roles cannot support 'inner'" }
176 sub augment { croak "Roles cannot support 'augment'" }
184 MooseX::Role::Parameterized - parameterized roles
188 package MyRole::Counter;
189 use MooseX::Role::Parameterized;
208 method "increment_$name" => sub {
210 $self->$name($self->$name + 1);
213 method "decrement_$name" => sub {
215 $self->$name($self->$name - 1);
219 package MyGame::Tile;
222 with 'MyRole::Counter' => { name => 'stepped_on' };
224 =head1 L<MooseX::Role::Parameterized::Tutorial>
226 B<Stop!> If you're new here, please read
227 L<MooseX::Role::Parameterized::Tutorial>.
231 Your parameterized role consists of two things: parameter declarations and a
234 Parameters are declared using the L</parameter> keyword which very much
235 resembles L<Moose/has>. You can use any option that L<Moose/has> accepts.
236 These parameters will get their values when the consuming class (or role) uses
237 L<Moose/with>. A parameter object will be constructed with these values, and
238 passed to the C<role> block.
240 The C<role> block then uses the usual L<Moose::Role> keywords to build up a
241 role. You can shift off the parameter object to inspect what the consuming
242 class provided as parameters. You can use the parameters to make your role
245 There are many paths to parameterized roles (hopefully with a consistent enough
246 API); I believe this to be the easiest and most flexible implementation.
247 Coincidentally, Pugs has a very similar design (I'm not yet convinced that that
252 You must use this syntax to declare methods in the role block:
253 C<< method NAME => sub { ... }; >>. This is due to a limitation in Perl. In
254 return though you can use parameters I<in your methods>!
256 You must use all the keywords in the role block. If it turns out to be correct,
257 we'll compose the parameterizable role (everything outside the role block) with
258 the parameterized role (everything inside the role block). We throw an error if
259 you try to use a keyword outside of the role block, so don't worry about it for
262 L<Moose::Role/alias> and L<Moose::Role/excludes> are not yet supported. I'm
263 completely unsure of whether they should be handled by this module. Until we
264 figure out a plan, both declaring and providing a parameter named C<alias> or
265 C<excludes> is an error.
269 Shawn M Moore, C<< <sartak@bestpractical.com> >>