How to automatically generate a bunch of setters / getters tied to a network service in the Muse?

As a training for Musa himself, I am working on a Moose object that interacts with certain equipment. Mentioned hardware accepts several different commands that set different hardware properties, all forms of PROPERTYNAME=VALUE for the setter and PROPERTYNAME? for the recipient (note that these "setters" and "getters" are in the network interface to the equipment). I want to create an object in which all these hardware properties are implemented using the attribute interface. Since getting and setting various properties takes the same form for all properties, is there a way to automatically generate setters and getters from a list of these properties?

IE: Instead:

 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 is what I want:

 # 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?'); } 
+4
source share
5 answers

Figured it out. I understand that I should not use attributes for this. Instead, I will dynamically generate methods using Class :: MOP :: Class as follows:

 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?/); } ); } 

Making this call with the has () function effectively puts the state of the object in two places - on the hardware and in the instance - and I only want it in one.

+2
source

How about enumerating properties?

 use strict; use warnings; use Moose; foreach my $prop ( qw( property1 property2 property3 property4 ) ) { has $prop => ( is => 'rw', isa => 'Str', reader => "get_$prop", writer => "set_$prop", ); } 1; 
+5
source

You do not store any value, so you do not need attributes.

You do not even want to use two subdirectories, since you want to get one name for getting and setting.

 for my $prop (qw( property1 property2 property3 )) { my $accessor = sub { my $self = shift; if (@_) { $self->_send_command("$prop=$value"); } else { return $self->_send_command("$prop?"); } }; no strict 'refs'; *$prop = $accessor; } 
+2
source

I would recommend using the has attribute rather than a separate attribute for each of your properties.

 Package MyHardware; use Moose; has properties => ( 'is' => 'rw', 'isa' => 'HashRef', 'lazy_build' => 1, ); sub _build_properties { my $self = shift; return { 'property1' => '', 'property2' => '', }; } print $self->properties->{property1}; 
+1
source

Generate Recipients and Setters for Instance Data

 BEGIN { my @attr = qw(prop1 prop2 prop3 prop4); no strict 'refs'; for my $a (@attr) { *{__PACKAGE__ . "::get_$a"} = sub { $_[0]->{$a} }; *{__PACKAGE__ . "::set_$a"} = sub { $_[0]->{$a} = $_[1] }; } } 

+1
source

All Articles