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.
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 written and tested 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.