How to use an array as an attribute of an object in Perl?

I need help regarding arrays in Perl

This is the constructor that I have.

Buildpacket.pm

sub new { my $class = shift; my $Packet = { _PacketName => shift, _Platform => shift, _Version => shift, _IncludePath => [@_], }; bless $Packet, $class; return $Packet; } sub SetPacketName { my ( $Packet, $PacketName ) = @_; $Packet->{_PacketName} = $PacketName if defined($PacketName); return $Packet->{_PacketName}; } sub SetIncludePath { my ( $Packet, @IncludePath ) = @_; $Packet->{_IncludePath} = \@IncludePath; } sub GetPacketName { my( $Packet ) = @_; return $Packet->{_PacketName}; } sub GetIncludePath { my( $Packet ) = @_; @{ $Packet->{_IncludePath} }; } 

(The code has been changed as suggested by "gbacon", thanks)

I am moving relative paths to the includeobjects array in a dynamic way. Attached files are read from the XML file and placed in this array.

 # PacketInput.pm if($element eq 'Include') { while( my( $key, $value ) = each( %attrs )) { if($key eq 'Path') push(@includeobjects, $value); } } 

So, the include object will be like this:

 @includeobjects = ( "./input/myMockPacketName", "./input/myPacket/my3/*.txt", "./input/myPacket/in.html", ); 

I use this line to set include path

  $newPacket->SetIncludePath(@includeobjects); 

Also in PacketInput.pm I have

 sub CreateStringPath { my $packet = shift; print "printing packet in CreateStringPath".$packet."\n"; my $append = ""; my @arr = @{$packet->GetIncludePath()}; foreach my $inc (@arr) { $append = $append + $inc; print "print append :".$append."\n"; } } 

I have many packages, so I look through each package

 # PacketCreation.pl my @packets = PacketInput::GetPackets(); foreach my $packet (PacketInput::GetPackets()) { print "printing packet in loop packet".$packet."\n"; PacketInput::CreateStringPath($packet); $packet->CreateTar($platform, $input); $packet->GetValidateOutputFile($platform); } 

The get and set methods work fine for PacketName. But since IncludePath is an array, I could not get it to work, I mean, relative paths are not printed.

+7
arrays constructor perl
source share
3 answers

If you enable strict pragma, the code does not even compile:

  Global symbol "@_IncludePath" requires explicit package name at Packet.pm line 15.
 Global symbol "@_IncludePath" requires explicit package name at Packet.pm line 29.
 Global symbol "@_IncludePath" requires explicit package name at Packet.pm line 30.
 Global symbol "@_IncludePath" requires explicit package name at Packet.pm line 40. 

Do not use @ without quotes in your keys, because this confuses the parser. I recommend deleting them completely so as not to confuse readers with the people of your code.

It seems you want to output all attribute values โ€‹โ€‹from the arguments to the constructor, so keep discarding scalar values โ€‹โ€‹with shift , and then everything else should be included in the path.

I assume that the components of the include path will be simple scalars, not links; if so, you will want to make deep copies for security.

 sub new { my $class = shift; my $Packet = { _PacketName => shift, _Platform => shift, _Version => shift, _IncludePath => [ @_ ], }; bless $Packet, $class; } 

Note that there is no need to store the blessed object in a temporary variable, and then immediately return it due to the semantics of Perl subnets :

If there is no return and if the last statement is an expression, its value is returned.

The methods below will also use this function.

Given the constructor above, GetIncludePath becomes

 sub GetIncludePath { my( $Packet ) = @_; my @path = @{ $Packet->{_IncludePath} }; wantarray ? @path : \@path; } 

Here are a few things going on. First, note that we are trying to return a copy of the include path, not a direct link to an internal array. This way, the user can change the value returned from GetIncludePath without worrying about resetting the state of the package.

The wantarray allows a subordinate to determine the context of their call and respond accordingly. In the context of the list, GetIncludePath will return a list of values โ€‹โ€‹in the array. Otherwise, it returns a link to a copy of the array. So client code can call it either in

 foreach my $path (@{ $packet->GetIncludePath }) { ... } 

or

 foreach my $path ($packet->GetIncludePath) { ... } 

SetIncludePath then

 sub SetIncludePath { my ( $Packet, @IncludePath ) = @_; $Packet->{_IncludePath} = \@IncludePath; } 

Note that you could use the same code in the constructor and not delete one parameter at a time using shift .

You can use the class defined above, as in

 #! /usr/bin/perl use strict; use warnings; use Packet; sub print_packet { my($p) = @_; print $p->GetPacketName, "\n", map(" - [$_]\n", $p->GetIncludePath), "\n"; } my $p = Packet->new("MyName", "platform", "v1.0", qw/ foo bar baz /); print_packet $p; my @includeobjects = ( "./input/myMockPacketName", "./input/myPacket/my3/*.txt", "./input/myPacket/in.html", ); $p->SetIncludePath(@includeobjects); print_packet $p; print "In scalar context:\n"; foreach my $path (@{ $p->GetIncludePath }) { print $path, "\n"; } 

Output:

  Myname
   - [foo]
   - [bar]
   - [baz]

 Myname
   - [./input/myMockPacketName]
   - [./input/myPacket/my3/*.txt]
   - [./input/myPacket/in.html]

 In scalar context:
 ./input/myMockPacketName
 ./input/myPacket/my3/*.txt
 ./input/myPacket/in.html 
+9
source share

Another way to reduce typing is to use Moose.

 package Packet; use Moose::Policy 'Moose::Policy::JavaAccessors'; use Moose; has 'PacketName' => ( is => 'rw', isa => 'Str', required => 1, ); has 'Platform' => ( is => 'rw', isa => 'Str', required => 1, ); has 'Version' => ( is => 'rw', isa => 'Int', required => 1, ); has 'IncludePath' => ( is => 'ro', isa => 'ArrayRef[Str]', default => sub {[]}, traits => [ 'Array' ], handles => { getIncludePath => 'elements', getIncludePathMember => 'get', setIncludePathMember => 'set', }, ); __PACKAGE__->meta->make_immutable; no Moose; 1; 

See Moose :: Manual :: Unsweetened for another example of how Moose saves time.

If you tend to learn classic Perl OOP, read the following perldoc articles: perlboot , perltoot , perlfreftut, and perldsc .

Great book on classic Perl OO Damian Conway Object Oriented Perl . This will give you an idea of โ€‹โ€‹the features in a Perl object.

+4
source share

Once you understand @gbacon's answer , you can save some typing with Class :: Accessor :: Fast :

 #!/usr/bin/perl package My::Class; use strict; use warnings; use base 'Class::Accessor::Fast'; __PACKAGE__->follow_best_practice; __PACKAGE__->mk_accessors( qw( IncludePath PacketName Platform Version )); use overload '""' => 'to_string'; sub to_string { my $self = shift; sprintf( "%s [ %s:%s ]: %s", $self->get_PacketName, $self->get_Platform, $self->get_Version, join(':', @{ $self->get_IncludePath }) ); } my $obj = My::Class->new({ PacketName => 'dummy', Platform => 'Linux' }); $obj->set_IncludePath([ qw( /home/include /opt/include )]); $obj->set_Version( '1.05b' ); print "$obj\n"; 
+3
source share

All Articles