Reputation: 79
I'm asking for your help on Perl stuff.
I currently have my code working well by creating a new object and then using it to run a function, but I would like to use more recent ways of coding with Perl (using class:Std
and integrated BUILD
/START
functions)
So right now my code looks like that, I call new
with a path to a log file and then run one function:
# Called from another perl script
use MyClass;
my $Obj = MyClass->new('/usr/me/path.log');
$Obj->run();
# My module
package MyClass;
sub new {
shift if ( defined($_[0] eq 'MyClass') );
my %args = validate( @_,{ LogPath => { type => SCALAR, optional => 0 }, } );
my $self;
$self->{plistPath} = $_[1];
return bless $self;
}
sub run {
my $self = shift;
...
...
}
And what I would like to have is a thing like that:
use Class::Std
sub BUILD {
my $self = shift;
my $ident = shift;
my %args = validate( @_, { LogPath => { type => SCALAR, optional => 0 }, } );
print "My log path:".$args{LogPath}."\n";
$self->{logPath} = $args{LogPath};
return bless $self;
}
sub run {
my $self = shift;
print $self->{logPath};
....
}
But this doesn't work, it prints well the log path into the BUILD
(I just wanted to check here if it works), but I can't get it to register the path into $self->{logPath}
to use it in my other functions. It tells me that it is not a Hash reference.
From the tutorials I've done, I think BUILD
shouldn't return the $self
as it is created automatically with Class::Std
, but I don't know how to do.
Your help would be greatly appreciated, if you have any advice.
Thanks a lot, Tim.
Upvotes: 1
Views: 424
Reputation: 6602
Since you are learning the more modern style, might I recommend that you give Moose or Moo a try, as they attempt to simplify the object-oriented perl experience, as we as making it much more powerful. These modules have been introduced after Class::Std
came about, and represent a more modern approach to creating object. The differences between Moose / Moo (and some others, like Mo or M (joke)) is that Moose gives you the full power of Object Meta Programming, while Moo strives for less power, but more speed.
Here is an example of your code, using Moo:
test.pl
#!/usr/bin/env perl
use strict;
use warnings;
use MyClass;
my $obj = MyClass->new(LogPath => '/var/log/messages');
$obj->run();
1;
MyClass.pm
package MyClass;
use Moo; # Moose / Mouse / Moo
has LogPath => (
is => 'ro', # Read Only
required => 1, # Required
isa => sub {
my ($path) = @_;
die "LogPath must be a SCALAR" if (ref $path);
die "LogPath [$path] must be a real path" unless -f $path;
},
);
sub run {
my ($self) = @_;
print "MyClass::run()\n";
my $path = $self->LogPath();
print "About to do something with LogPath [ $path ]\n";
}
1;
Output
perl test.pl
MyClass::run()
About to do something with LogPath [ /var/log/messages ]
As requested, for comparison, here is the same object, but this time created using Class::Std. Please note how much more code/boilerplate is required with the Class::Std
solution vs Moo
:
test_class_std.pl
#!/usr/bin/env perl
use strict;
use warnings;
use MyClassStd;
my $obj = MyClassStd->new({ LogPath => '/var/log/messages' });
$obj->run();
print $obj->get_description() . "\n";
MyClassStd.pm
package MyClassStd;
use Class::Std;
# Create storage for object attributes...
# The syntax '%foo : ATTR' applies the attribute named ATTR to the hash %foo.
# For more info on how this works, see: perldoc attributes
# Create one hash per attribute, these will be private to the class
my %log_paths : ATTR;
# These fields will be available via $obj->get_foo() methods
my %public_data : ATTR;
# Handle initialization of objects of this class...
sub BUILD {
my ($self, $object_id, $args) = @_;
my $path = check_path( $args->{ LogPath } );
$log_paths{ $object_id } = $path;
$public_data{ $object_id }{ description } = "LogPath is set to [ $path ]";
}
# Handle cleanup of objects of this class...
sub DEMOLISH {
my ($self, $object_id) = @_;
# Objects will be removed from the hashes automatically
# Add any other cleanup code here
}
# Handle unknown method calls...
sub AUTOMETHOD {
my ($self, $object_id, @args) = @_;
my $method_name = $_; # Method name passed in $_
# Return any public data...
if ( $method_name =~ m/^get_(.*)/ ) {
my $get_what = $1;
return sub {
return $public_data{$object_id}{$get_what};
}
}
warn "Can't call $method_name on ", ref $self, " object";
return; # The call is declined by not returning a sub ref
}
sub run {
my ($self) = @_;
print "MyClassStd::run()\n";
my ($path) = $log_paths{ ident $self };
print "About to do something with LogPath [ $path ]\n";
}
sub check_path {
my ($path) = @_;
die "LogPath must be a SCALAR" if ( ref $path );
die "LogPath [ $path] must be a real path" unless -f $path;
return $path;
}
1;
Output
MyClassStd::run()
About to do something with LogPath [ /var/log/messages ]
LogPath is set to [ /var/log/messages ]
Upvotes: 5