Modify Moose attribute methods
I'm creating a list of attributes (more than the three shown below), all of which share common methods. Is it possible to then add a trigger to one of the methods:
# Create a bunch of attributes
for my $attr ( qw( title name address ) ) {
has $attr => ( is => 'rw', isa => 'Str' );
around $attr => sub {
# more stuff here.
}
}
# Add a trigger
has_another_method 'title' => ( trigger => \&_trigger_title );
I know I can get meta information about attributes, but I haven't found anything that would enable me to change the attribute methods (and perhaps for good reason). Being able to do this would help keep my code clean, and mean that the common bits are all defined in one place. If not, I can just create the attribute separately, and include the trigger method.
Update
The answers have made it clear that changing the attribute after it has been created is not a good idea. Instead, I've opted for a different method which allows me to keep all the attribute options in one place. This example is a little simplistic, but it demonstrates the idea:
# Create a bunch of attributes
for my $attr ( qw( title name address ) ) {
my %options = ( is =>开发者_运维问答 'rw', isa => 'Str' );
# Add a trigger to the title attribute.
$options{ 'trigger' } = \&_trigger_title
if $attr eq 'title';
has $attr => ( %options );
around $attr => sub {
# more stuff here.
}
}
Triggers are just an attribute on the attribute, but they are defined to be read only. You could find_meta( $attribute )->get_attribute('trigger')->set_value( $attribute, sub { new trigger })
, but you're really breaking encapsulation here.
I would just declare all common attributes in my for loop, and then declare the special cases elsewhere.
Attribute methods are composed when they are constructed, so it is generally a good practice to have all the options available when you create it with the has
directive. However, currently there is nothing special being done with trigger methods, so you could do this, to get around the read-onlyness of the 'trigger' option:
my $attr = __PACKAGE__->meta->get_attribute('title')->meta->get_attribute('trigger')->set_raw_value('_trigger_sub_name');
However this is delving rather excessively into the innards of Moose; if the implementation ever changes, you can be SOL (plus you would be violating constraints that are there for a reason). So it would be much better to set up your triggers as:
has $_ => (
is => 'rw', isa => 'Str',
trigger => '_trigger_' . $_,
) for (qw(title name address));
sub _trigger_title {
# implementation here
}
sub _trigger_name {
# implementation here
}
sub _trigger_address {
# implementation here
}
精彩评论