By way of teaching myself Moose, I'm working on a Moose object that interfaces to a particular piece of hardware. Said hardware takes a number of different commands that set various properties of the hardware, all of the form PROPERTYNAME=VALUE
for a setter, and PROPERTYNAME?
for a getter (note that these 'setters' and 'getters' are on the network interface to the hardware). What I want to do is create an object where all of these properties of the hardware are implemented with an attribute-like interface. Since getting and setting the various properties takes the same form for all properties, is there a way to automatically generate the setters and getters from a list of those properties?
I.E.: Rather than this:
Package MyHardware;
use Moose;
has property1 => (
'is' => 'rw',
'reader' => 'set_property1',
'writer' => 'get_property1',
);
has property2 => (
'is' => 'rw',
'reader' => 'set_property2',
'writer' => 'get_property2',
);
# ...
has propertyN => (
'is' => 'rw',
'reader' => 'set_propertyN',
'writer' => 'get_propertyN',
);
Is there something I can do like this:
Package MyHardware;
use Moose;
attributes => (
'is' => 'rw',
'names' => [qw/property1 property2 ... propertyN/],
'reader' => sub {
my $self = shift;
my $property = shift;
return $self->_send_command("$property?");
},
'writer' => sub {
my $self = shift;
my $property = shift;
my $value = shift;
return $self->_send_command("$property=$value");
},
);
EDIT: Here's what I want to happen:
# CALLER:
my $hw = MyHardware->new();
$hw->property1('foo');
print $hw->property2 . "\n";
And "under the hood":
$hw->property1('foo');
# Becomes
sub { return $hw->_send_command('property1=foo'); }
# And
$hw->property2();
# Becomes
sub { return $hw->_send_command('property2?'); }
Figured it out. I realize that I shouldn't be using attributes at all to do this. Instead, I'll dynamically generate methods using Class::MOP::Class like so:
my $meta = Class::MOP::Class->initialize(__PACKAGE__);
foreach my $prop (qw/property1 property2 property3/) {
$meta->add_method(qq/set_$prop/, sub {
my $self = shift;
my $value = shift;
return $self->_send_command(qq/$prop=$value/);
}
);
$meta->add_method(qq/get_$prop/, sub {
my $self = shift;
return $self->_send_command(qq/$prop?/);
}
);
}
Doing it with calls to has() would have effectively put the object state in two places - on the hardware and in the instance - and I only want it in one.