Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Calling subroutines dynamically 1

Status
Not open for further replies.

menkes

Programmer
Nov 18, 2002
47
0
0
US
I am hoping to maybe get some ideas on how to accomplish the task I have more efficiently.

I have a script that queries a DB table for new files received from clients. The script stores the info for these files in a hash of hashes, with one of the values being a unique code for that client.

Then the script loops through the hash. Each client sends a unique type or set of files, so I have a subroutine for each client which is in its own file.

For example: For clientX I create a file named "clientX.pm". In that file is a sub called "file_mod". In my main script I encounter the client code 'X' and this code is used:
Code:
# Dynamically build file name for this client
my $mod = 'client' . $ulFile{$fid}{code} . '.pm';

# Make sure the client-specific code exists
if (-e $mod)
{
    # Load the client-specific code
    require $mod;

    # Run the sub for handling the data
    file_mod($fid);
}

In general, this works fine. However, one of the problems I encounter stems from the fact that I use the same sub name 'file_mod' in every client module. Uh-oh...you can guess what happens when I have several clients in my hash. Yes, the script calls the sub for the wrong (previously called) client.

So, do I make the sub names variable, such as 'file_mod_clientX', or is there some better way to approach this?

For perspective, each client has to be handled uniquely and there are 500+ clients.

Any thoughts would be much appreciated!

Scott
 
You could do something like this (it's an example only)

Code:
#!/usr/bin/perl -w
use strict;

for my $pkg ( qw/FirstPackage SecondPackage/ ) {
   $pkg->file_mod();
}

package FirstPackage;

sub file_mod {
   print "First One\n";
   print shift, "\n";
}


package SecondPackage;
sub file_mod {
   print "Second One\n";
   print shift, "\n";
}

Note that the arguments to the subroutines are slightly different to normal. The first argument is going to be the name of the package.
 
ishnid,

Thanks for the post. Looks like that might work well.

A question on this though: Since I would be declaring the use of a package, how do I call subs from the package that are located in the primary script (shared functions)?

Would the syntax be main::some_sub()?

Sorry if this is basic, but the use of packages is new to me.
 
Well, was kind of excited so made the last post before testing. I see now that the main::some_sub() syntax works great.

Of course if there is something better, please let me know.
 
May have spoke too soon. While the syntax for calling subs in the main routine seems to be OK, I seem to have lost the reference to my hash of hashes.

The hash is %ulFile. I declare it in the main script as 'our %ulFile;'. I explicitly pass the key for each client using a file id: '$pkg->file_mod($fid);'.

Before making each client file a package, the %ulFile hash was accessible to sub file_mod. No it appears to not be. I'm sure my inexperience with packages is causing this scope problem, but I am not sure how to correct it.

The only things required by the packages from the main script are: common functions (good to go), the file key (good to go), and the %ulFile hash.
 
I'd be trying to avoid cross-package variable-sharing as much as possible. Why not pass a reference to your hash-of-hashes to each method? Using your initial setup with each client in a separate file (easier for adding new clients and debugging them without disturbing the running code), you could
Code:
# Dynamically build file name for this client
my $mod = 'client' . $ulFile{$fid}{code} . '.pm';

# Make sure the client-specific code exists
if (-e $mod)
{
    # Load the client-specific code
    eval "require $mod;"; die $@ if $@;

    die "$mod doesn't implement file_mod()"
        unless $mod->can( 'file_mod' );

    # Run the sub for handling the data
    $mod->file_mod($fid,\%ulFile);
}

The last line could perhaps have been
Code:
    $mod->file_mod($ulFile{$fid});
if your modules only need the configuration for $fid and not it's actual value.

I've added a little paranoia. The eval will help if you want the main script to recover gracefully from a faulty module (you could process $@ rather than simply die) and the can() method is inherited from the UNIVERSAL parent class and does what it says on the tin.

f

"As soon as we started programming, we found to our surprise that it wasn't as easy to get programs right as we had thought. Debugging had to be discovered. I can remember the exact instant when I realized that a large part of my life from then on was going to be spent in finding mistakes in my own programs."
--Maurice Wilkes
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top