How do you write wrapper module? - perl

I'm writing a download sub module, I would like it looks like this:
Download.pm
Download/Wget.pm
Download/LWP.pm
Download/Curl.pm
Download/Socket.pm
My Download.pm should provide an api sub download($url). It will look for LWP module, then wget command, then curl command, if non of these exist, it will use Socket.
How can I write wrapper module?

Here is some example, how i did it:
How it works? It checks for some condition, and creates object depends on this condition. And subroutine also checks for reference type and calls the right method
file /tmp/Adapt/Base.pm (base module):
#!/usr/bin/perl
package Adapt::Base;
use strict;
use warnings;
sub new {
my $class = shift;
my $self;
if ( time % 3 ) {
require "/tmp/Adapt/First.pm";
$self = \Adapt::First->new(#_);
}
elsif ( time % 2 ){
require "/tmp/Adapt/Second.pm";
$self = \Adapt::Second->new(#_);
}
else {
require "/tmp/Adapt/Default.pm";
$self = \Adapt::Default->new(#_);
}
bless( $self, $class );
}
sub somesub {
my $s = shift;
my $self = $$s;
if ( ref( $self ) eq 'Adapt::First' ) {
$self->firstsub();
}
elsif ( ref( $self ) eq 'Adapt::Second' ) {
$self->secondsub();
}
else {
$self->defaultsub();
}
}
1;
file /tmp/Adapt/First.pm (some module):
#!/usr/bin/perl
package Adapt::First;
use strict;
use warnings;
sub new {
my $class = shift;
my $self = {};
bless( $self, $class );
}
sub firstsub {
print "I am 1st sub.\n";
}
1;
file /tmp/Adapt/Second.pm (another module):
#!/usr/bin/perl
package Adapt::Second;
use strict;
use warnings;
sub new {
my $class = shift;
my $self = {};
bless( $self, $class );
}
sub secondsub {
print "I am 2nd sub.\n";
}
1;
and file /tmp/Adapt/Default.pm (default module):
#!/usr/bin/perl
package Adapt::Default;
use strict;
use warnings;
sub new {
my $class = shift;
my $self = {};
bless( $self, $class );
}
sub defaultsub {
print "I am default sub.\n";
}
1;
and test script:
#!/usr/bin/perl
use strict;
use warnings;
require '/tmp/Adapt/Base.pm';
for (0..10) {
my $test = Adapt::Base->new;
$test->somesub;
sleep 1;
}
output:
dev# perl /tmp/adapt.pl
I am default sub.
I am 1st sub.
I am 1st sub.
I am 2nd sub.
I am 1st sub.
I am 1st sub.
I am default sub.
I am 1st sub.
I am 1st sub.
I am 2nd sub.
I am 1st sub.
dev#

Related

How to rename perl __ANON__ sub without disabling strict 'refs'?

I found a solution to renaming anonymous subs in Perl here. It involves temporarily mangling the symbol table to insert the desired name. This solution uses a hard-coded symbol table name to be replaced. My problem is that I would like to dynamically choose the symbol table name at runtime. Something like this:
$pkg = 'MyPkg::ModA::';
$name = 'subname';
...
no strict 'refs';
local *{"${pkg}__ANON__"} = "$name [anon]";
strict refs;
The only way to make it work is to disable strict refs. If they are not disabled, the script fails with this message:
Can't use string ("MyPkg::ModA::__ANON__") as a symbol ref while "strict refs" in use at /path/to/source/File.pm line xx
Note that the equivalent statement could be used
local ${$pkg}{__ANON__} = "$name [anon]";
with the similar error message:
Can't use string ("MyPkg::ModA::") as a HASH ref while "strict refs" in use at /path/to/source/File.pm line xx
Is it possible to do the same thing without disabling strict refs?
TMI/DNR:
Here is a complete example in case you're interested. Ironically, my solution uses an anonymous sub to rename the given anonymous sub.
ModA.pm
package MyPkg::ModA;
use strict;
use warnings;
use MyPkg::Util;
# Create a new instance.
sub new
{
my ($type, $class, $self);
# allow for both ModA::new and $moda->new
$type = shift;
$class = ref $type || $type;
$self = {#_};
bless $self, $class;
# use exported Util::anon sub here
$self->{func} = anon sub
{
my ($arg);
$arg = shift;
debug "\$arg: $arg";
};
return $self;
} # new
1;
__END__
ModB.pm
package MyPkg::ModB;
use strict;
use warnings;
use MyPkg::ModA;
# Create a new instance.
sub new
{
my ($type, $class, $self);
# allow for both ModB::new and $modb->new
$type = shift;
$class = ref $type || $type;
$self = {#_};
bless $self, $class;
$self->{modA} = MyPkg::ModA->new;
return $self;
} # new
# Do something with ModA.
sub doit
{
my ($self);
$self = shift;
$self->{modA}->{func}->('What is your quest?');
} # doit
1;
__END__
Util.pm
package MyPkg::Util;
use strict;
use warnings;
require Exporter;
our (#ISA, #EXPORT);
#ISA = qw(Exporter);
#EXPORT = qw(
anon
debug);
# Temporarily mangle symbol table to replace '__ANON__'.
sub anon
{
my ($func, $sub, $pkg, $name);
$func = shift;
$sub = (caller 1)[3];
$sub =~ /(.*::)(.+)/;
$pkg = $1;
$name = $2;
return sub
{
# TODO How to do this w/o disabling strict?
#no strict 'refs';
# temp symbol table mangling here
# ${$pkg}{__ANON__} is equivalent to *{"${pkg}__ANON__"}
local *{"${pkg}__ANON__"} = "$name [anon]";
use strict;
$func->(#_);
};
} # anon
# Print a debug message.
sub debug
{
my($fname, $line, $sub);
($fname, $line) = (caller 0)[1,2];
$fname =~ s/.+\///;
$sub = (caller 1)[3] || 'main';
$sub =~ s/.*::(.+)/$1/;
printf STDERR "%-10s %s(%s) - \"%s\"\n", $fname, $sub, $line, "#_";
} # debug
1;
__END__
mytest.pl
#! /usr/bin/perl
use strict;
use warnings;
use MyPkg::ModB;
# Stuff happens here.
my ($modB);
$modB = MyPkg::ModB->new;
$modB->doit;
You can use core module Sub::Util's set_subname.
use Sub::Util qw( set_subname );
sub anon {
...
return set_subname("$name [anon]", $func);
}

Inheritance and child methods

For some reason I'm not able to access the child methods on the boundary object. I would appreciate as much detail with an answer as possible as I'm still a bit confused on inheritance with perl, especially the bless portion. Also any constructive criticism would be great about overall design.
Generic.pm (Base Class)
package AccessList::Generic;
use strict;
use warnings;
sub new {
my $class = shift;
my $self = {
rules => [],
#_
};
bless $self, $class;
return $self;
}
sub get_line_count {
my $self = shift;
return scalar #{$self->{rules}};
}
1;
Extended.pm
package AccessList::Extended;
use strict;
use warnings;
use AccessList::Generic;
use base qw(AccessList::Generic);
sub new {
my ($class, #args) = #_;
my $self = $class->SUPER::new(#args);
return $self;
}
1;
Boundary.pm
package AccessList::Extended::Boundary;
use strict;
use warnings;
use AccessList::Extended;
use base qw(AccessList::Extended);
sub new {
my ($class, #args) = #_;
my $self = $class->SUPER::new(#args);
return $self;
}
sub get_acl_information {
my ($self) = #_;
return;
}
1;
Failing Test
can_ok('AccessList::Extended::Boundary', 'get_acl_information');
Error Message
# Failed test 'AccessList::Extended::Boundary->can('get_acl_information')'
# at t/b1.t line 42.
# AccessList::Extended::Boundary->can('get_acl_information') failed
# Looks like you failed 1 test of 2.
I don't see any problems in what you posted. The problem is surely in what you didn't post. Did you forget to load AccessList::Extended::Boundary?
$ find -type f
./AccessList/Extended/Boundary.pm
./AccessList/Extended.pm
./AccessList/Generic.pm
$ perl -E'
use Test::More tests => 1;
use AccessList::Extended::Boundary;
can_ok("AccessList::Extended::Boundary", "get_acl_information");
'
1..1
ok 1 - AccessList::Extended::Boundary->can('get_acl_information')

OOP design suggestion

I have set of files that needs to either emailed or FTPed(read from config). Before doing either of these I need to so some common operation on the files, like changing filenames, sanity check, so on.
package Class::Foo::Partners;
use Carp;
use Data::Dumper;
# Sanity check and Blessing
sub new ($) {
my $class = shift;
my %attr = #_;
Carp::confess('Config undefined') unless defined $attr{cfg};
my $self = bless({}, $class);
%$self = #_;
return $self;
}
sub process {
my $self = shift;
my %filestoupload = ();
if ($self->{dbh}->sql($sql, \%filestoupload)) {
my $stats;
if (defined $self->{cfg}->{$self->{section}}->{pdf_email_rcpt}) {
$stats = Class::Foo::Email->new(section => $self->{cfg}->{$self->{section}}, filestoupload => \%filestoupload);
$stats->sendfiles;
} else {
$stats = Class::Foo::FTP->new(section => $self->{cfg}->{$self->{section}}, filestoupload => \%filestoupload);
$stats->sendfiles;
}
} elsif ($self->{dbh}->{_error}) {
Carp::confess($self->{dbh}->{_error});
} else {
print "NO FILES";
}
}
package Class::Foo::FTP;
use Carp;
use Data::Dumper;
use POSIX qw( strftime );
use File::Temp qw (tempdir) ;
use File::Copy;
use Net::FTP;
# Sanity check and Blessing
sub new ($) {
my $class = shift;
my %attr = #_;
Carp::confess('Section undefined') unless defined $attr{section};
Carp::confess('undefined ftp_host') unless defined $attr{section}->{ftp_host};
my $self = bless({}, $class);
%$self = #_;
return $self;
}
sub sendfiles {
my $self = shift;
return unless(keys %{$self->{filestoupload}});
#DO SOME COMMON TASK
..
$self->ftp_connect();
..
..
}
package Class::Foo::Email;
use Data::Dumper;
use Mail::Sender;
use POSIX qw( strftime );
use File::Temp qw (tempdir) ;
use File::Copy;
sub new ($) {
my $class = shift;
my %attr = #_;
Carp::confess('Config: undefined pdf_email_subject') unless defined $attr{section}->{pdf_email_subject};
Carp::confess('Config: undefined pdf_email_from') unless defined $attr{section}->{pdf_email_from};
my $self = bless({}, $class);
%$self = #_;
return $self;
}
sub sendfiles {
my $self = shift;
return unless(keys %{$self->{filestoupload}});
#DO SOME COMMON TASK
..
my $mailrcpt = $self->{section}->{pdf_email_rcpt};
my $sender = new Mail::Sender {smtp => 'localhost', from => $self->{section}->{pdf_email_from}};
$sender->MailFile({ to => $mailrcpt,
subject => $self->{section}->{pdf_email_subject},
msg => "Attached is A1 of today's WSJE. ",
ctype => 'application/pdf',
file => #files } );
$self->{uploaded_count} = #files;
}
Where to do the common operation and when and how to call respective child classes?
Should I use abstraction?
thanks for your help
Check out the implementation of MT::FileMgr:
https://github.com/openmelody/melody/tree/master/lib/MT
It should give you a lot of ideas on how to do Perl OOP for something like this.

How do I read args passed to the constructor and args passed by `use Module` in Perl?

Currently I am making a new module and I was wondering how could I implement in my module 2 things.
We often see the use like:
use My::Module qw(something);
for example:
use CGI::Carp qw(fatalsToBrowser);
So the first question is, how do i
retrieve this, i mean wether the
user has specified anything and what
he specified ?
Second question is, How do i pass and read the args
directly on the constructor like
this:
my $my_module = My::Module->new(arg1,arg2,arg3);
AS requested on the comment the simple module test code:
package My::Module;
# $Id$
use strict;
use Carp;
sub new {
my $class = shift;
my $self = {};
$self->{ARG1} = undef;
$self->{ARG2} = undef;
$self->{ARG3} = undef;
$self->{ARG4} = undef;
bless($self,$class);
return $self;
}
sub arg1 {
my $self = shift;
if (#_) { $self->{ARG1} = shift }
return $self->{ARG1};
}
sub arg2 {
my $self = shift;
if (#_) { $self->{ARG2} = shift }
return $self->{ARG2};
}
sub arg3 {
my $self = shift;
if (#_) { $self->{ARG3} = shift }
return $self->{ARG3};
}
sub arg4 {
my $self = shift;
if (#_) { $self->{ARG4} = shift }
return $self->{ARG4};
}
sub dump {
my $self = shift;
require Data::Dumper;
my $d = Data::Dumper->new([$self], [ref $self]);
$d->Deepcopy(1);
return $d->Dump();
}
1; # so the require or use succeeds
perldoc -f use explains that the use keyword is simply loading a module during compile-time, and then calling ->import on it. The arguments a caller gave to the use statement will be passed to the import method call.
As for your second question: constructors are just methods. Getting their arguments works like it does for any other method or function, using the #_ variable.
import subroutine gets the arguments passed in a use. The following code samples should help you.
File: My/Module.pm
package My::Module;
use warnings;
use strict;
use Data::Dumper;
sub import {
my ( $package, #args ) = #_;
print Dumper \#args;
}
1;
File: module.pl
#!/usr/bin/env perl
use warnings;
use strict;
use My::Module qw(something);
If you are programming an object oriented module, you may try Moose which will save you lots of time.

How can I use a code ref as a callback in Perl?

I have the following code in my class :
sub new {
my $class = shift;
my %args = #_;
my $self = {};
bless( $self, $class );
if ( exists $args{callback} ) {
$self->{callback} = $args{callback};
}
if ( exists $args{dir} ) {
$self->{dir} = $args{dir};
}
return $self;
}
sub test {
my $self = shift;
my $arg = shift;
&$self->{callback}($arg);
}
and a script containing the following code :
use strict;
use warnings;
use MyPackage;
my $callback = sub {
my $arg = shift;
print $arg;
};
my $obj = MyPackage->new(callback => $callback);
but I receive the following error:
Not a CODE reference ...
What am I missing? Printing ref($self->{callback}) shows CODE. It works if I use $self->{callback}->($arg), but I would like to use another way of invoking the code ref.
The ampersand is binding just to $self and not the whole thing. You can do curlies around the part that returns the reference:
&{$self->{callback}}($arg);
But the
$self->{callback}->($arg);
is generally considered cleaner, why don't you want to use it?