Gurft has asked for the wisdom of the Perl Monks concerning the following question:

I'm currently working on a set of scripts for collecting different types of system information from a very heterogeneous network (Linux, BSD, HPUX, AIX, SGI) and building a repository. My current script is HUGE since it has to support the neuonces of all of the operating systems. What I was hoping to do was break it into separate "plug-ins" if you will that will only get loaded/run on specific platforms. I though about putting them in separate packages/namespaces and then manually editing the scripts to include only the specific packages I needed, but in that case I might as well write individual scripts for each type of host. Also, some of the systems have certain aspects that I'd like to collect data on, and others that I don't. Basically I'm looking for anyone that's had experience in writing "pluginable code" or knows of some sample code that I can look at. Any suggestions on a course of action to start working on?

Replies are listed 'Best First'.
Re: Writing Plugin-Able perl scripts
by Corion (Patriarch) on Aug 30, 2002 at 18:03 UTC

    I would think that you structure your modules like this :

    • For each feature, you have a dummy module, that returns an empty list of results, a message or undef, to indicate that the feature was not checked.
    • Each dummy module Foo also takes a look at the current platform via $^O, and checks if a module called Foo::platform exists. If it exists, it simply delegates all calls (possibly via AUTOLOAD) to the platform specific module.

    This way, you implement stub drivers for all features, and then can move on to the platform specific features. If there is common functionality across platforms, you have to decide whether you simply copy the module file to a different name, or encapsulate the common functionality in a third module used by both platform specific modules.

    Plug-in architectures has some more thoughts on plugins.

    perl -MHTTP::Daemon -MHTTP::Response -MLWP::Simple -e ' ; # The $d = new HTTP::Daemon and fork and getprint $d->url and exit;#spider ($c = $d->accept())->get_request(); $c->send_response( new #in the HTTP::Response(200,$_,$_,qq(Just another Perl hacker\n))); ' # web
Re: Writing Plugin-Able perl scripts
by dws (Chancellor) on Aug 30, 2002 at 18:33 UTC
    What I was hoping to do was break it into separate "plug-ins" if you will that will only get loaded/run on specific platforms.

    Try something like the following

    if ( $^O =~ /win32/i ) { require MySysInfo::Win32; import MySysInfo::Win32; } elsif ( $^O =~ /amiga/i ) { require MySysInfo::Amiga; import MySysInfo::Amiga; } elsif # etc.
    If there's a possibility that the required module might not be present, you can wrap the require in an eval.

    The import gives you a chance to export a common API into the top-level script's namespace (you'll need to implement an import sub in each of your packages -- examples of that abound).

    Enumerating $^O is left as an exercise.

Re: Writing Plugin-Able perl scripts
by ides (Deacon) on Aug 30, 2002 at 18:44 UTC

    I solved this same situation on an application I wrote to do remote system administration. It allows for the backend to be OS independant by having a set of modules that are written spefically for each OS.

    I then load the appropriate modules in a config file and do a

    eval "require $backend_name_from_config";

    You can see this in action at ftp://ftp.wiles.org/pub/RUM/

    -----------------------------------
    Frank Wiles <frank@wiles.org>
    http://frank.wiles.org
Re: Writing Plugin-Able perl scripts
by Gurft (Novice) on Sep 03, 2002 at 01:54 UTC
    Okay, very cool from what I've seen above I've pretty much written the plugin system as far as having the methods/variables/data I need available to the central App, thanks SO much for the help

    Now another related question/solution. Since most of this runs as sort of an "Event Loop" I've written an initialization routine for each module so that gets called when it's first included.

    what I'd like to do is have the available functions/necessary calls to be put into a hash or list where they can be called when their needed, basically the equivalent of having a pointer to a function in C, can I do something like:

    foreach (keys %FunctionHash) { $return = &callMySub($_); # Do somethign with return here }
    or would there be a better method. Basically all of the modules export the same functions, but since each plugin is configurable there may be some that the end user (myself) may not wish to execute.....

    Note: I know I could make this much simpler just by saying you have one function that does everythign and if you get more data then you want, tough cookies. However management doesn't like that method....

      To call a subref, use $subref->(args).

      Note, however, that the keys of a hash are always plain strings; they can't be references. If you try to use a ref, you'll end up getting the stringified version, which can never be reconstructed into a real reference. (Well, that isn't strictly true, but is close enough.)

      So what you probably want to say is more like:

      foreach (values %FunctionHash) { $return = $_->($data); }


      Confession: It does an Immortal Body good.

        $return = &{$_->($data)};

        is  & optional here?

        update: do you mean  &{$_{$data}} or even  &{$data{$_}} ? I think the last one looks better.