Getting list of fields from pragma "use fields"?

So, I am familiar with the pragma fields in Perl, which can be used to limit the fields stored in the class:

package Fruit; use fields qw( color shape taste ); sub new { my ( $class, $params ) = @_; my $self = fields::new( $class ) unless ref $class; foreach my $name ( keys %$params ) { $self->{ $name } = $params->{ $name }; } return $self; } 

As soon as I declare the fields at the top, how can I return the list, tell me, because I want to dynamically generate accessors? Is keys %FIELDS only way?

Secondly, is there a more efficient way to pre-populate fields in the constructor than a loop and the purpose of each parameter, as I do above?

+6
perl
source share
3 answers

If you work in Perl 5.10 and higher (indeed 5.9 and higher, but I do not take into account development releases), fields creates a limited hash. See Hash :: Util for information on restricted hashes.

To get all the fields available for a restricted hash, use the legal_keys or legal_ref_keys :

 use Hash::Util qw( legal_ref_keys ); my $froot = Fruit->new(); my @attribs = legal_ref_keys($froot); 

You can do several things to automatically create your methods:

  • Create a temporary object at build time and request it for legal keys so you can create attributes --- UGLY
  • AUTOLOAD attributes, requesting an object for a list of legal keys. CODE SMELL ALERT:, it is assumed that all subclasses will use the same underlying data structure.
  • Access to the %FIELDS hash in the module for generating methods at compile time or through AUTOLOAD. MORE PROBLEMS - it is assumed that the unpublished bits of the fields pragma remain.
  • Define an array of attributes at compile time and auto-generation methods and set the fields based on the value.
  • Stop writing this whole template and use Moose.

Option 4:

 package Fruit; use strict; use warnings; my @ATTRIBUTES; BEGIN { @ATTRIBUTES = qw( color shape taste ); } use fields @ATTRIBUTES; for my $attrib ( @ATTRIBUTES ) { my $getset = sub { my $self = shift; if( @_ ) { $self->{$attrib} = shift; } return $self->{$attrib}; }; { no strict 'refs'; *{$attrib} = $getset; } } sub new { my ( $class, $params ) = @_; my $self = fields::new( $class ) unless ref $class; foreach my $name ( keys %$params ) { $self->{ $name } = $params->{ $name }; } return $self; } 

Option 5

 package Fruit; use Moose; has 'color' => ( is => 'rw', isa => 'Str', ); has 'shape' => ( is => 'rw', isa => 'Str', ); has 'taste' => ( is => 'rw', isa => 'Str', ); 
+6
source share

Each object created where fields pragma is used will have these fields (and only those fields), even if you do not initialize them. Therefore, you do not need to worry about the %FIELDS table %FIELDS outdated.

  DB<1> $apple = Fruit->new( {qw(color red shape apple taste like-an-apple)} ) DB<2> p join' ',keys %$apple color taste shape DB<3> $kiwi = Fruit->new() DB<4> p join' ',keys %$kiwi color taste shape 
+1
source share

Currently, the best working solution I have is something like this:

 # Return the fields for this object sub fields { my ( $self ) = @_; my $class = ref( $self ) || $self; return [ keys %{ "${class}::FIELDS" } ]; } 
+1
source share

All Articles