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 L<Moose::Role/alias> and L<Moose::Role/excludes> are not yet supported. I'm
257 completely unsure of whether they should be handled by this module. Until we
258 figure out a plan, both declaring and providing a parameter named C<alias> or
259 C<excludes> is an error.
263 Shawn M Moore, C<< <sartak@bestpractical.com> >>