If I have a Perl class eg
package Foo;
sub new {
my ($class,$hashref) = @_;
my $self = bless $hashref, $class;
}
and initialised with
my $foo = Foo->new( { bar => 2, othervar => 8 } );
I can do
print $foo->{ bar };
which feels clunky, and
print $foo->bar
feels more preferable. However, if there are a lot of keys, I'd prefer not to have to write an accessor for every key (or is that best practice) ?
So, I can include
our $AUTOLOAD;
sub AUTOLOAD {
my $self = shift;
my $called = $AUTOLOAD =~ s/.*:://r;
die "No such attribute: $called"
unless exists $self->{$called};
return $self->{$called};
}
sub DESTROY { } # see below
In perldoc perlobj it says
# XXX - this is a terrible way to implement accessors
Are there any good ways to implement accessors like this, without using other packages, eg Moose, Class::Accessor ? I'm just after something light as its just one class that has a lot of keys.
CodePudding user response:
Are there any good ways to implement accessors like this, without using other packages ...
If you insist, then write those subs directly to the package symbol table
package AutoAccessors;
use warnings;
use strict;
use feature 'say';
my @attr_names;
BEGIN {
@attr_names = qw(name mode etc);
no strict 'refs';
foreach my $accessor (@attr_names) {
*{$accessor} = sub { do {
if (@_ == 1) { $_[0]->{$accessor} }
elsif (@_ == 2) { $_[0]->{$accessor} = $_[1] }
#elsif ...
} };
}
};
sub new {
my ($class, $args) = @_;
my $self;
foreach my $attribute (@attr_names) {
# Check, initialize, set from $args, etc
$self->{$attribute} = $args->{$attribute} if $args->{$attribute};
}
return bless $self, $class;
}
1;
Then
use warnings;
use strict;
use feature 'say';
use AutoAccessors;
my $obj = AutoAccessors->new({ mode => '007' });
$obj->name('Bond');
say "name's ", $obj->name;
say "mode: ", $obj->mode;
This is done in a number of CPAN packages (and it's usually more elaborate).
Having said that, I see no good reason to avoid good libraries, far more carefully done and complete. For instance, Moo as a full system comes in at around 5 kloc (if I recall correctly) and has barely a handful of dependencies, while Class::Accessor is just over 200 loc with one dependency that I can see.