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

Fellow Monasterians,

I'm attempting to reuse code. I have several scripts, that all have the same exact sub routines. I want to put the common subs in one file and give all the scripts access to it. What's the best way?

SCRIPT 1

#!/usr/bin/perl use warnings; use strict; use CGI::Carp qw(fatalsToBrowser); require "common.lib"; my $name = "frodo"; $name = get_uppercase($name);

COMMON 1

sub get_uppercase { my $name = shift; return uc($name); } 1;

or

SCRIPT 2

#!/usr/bin/perl use warnings; use strict; use CGI::Carp qw(fatalsToBrowser); use Common; my $name = "frodo"; $name = Common->get_uppercase($name);

COMMON 2

package Common; sub get_uppercase { my ($class, $name) = @_; return uc($name); } 1;

Thanks!


—Brad
"The important work of moving the world forward does not wait to be done by perfect men." George Eliot

Replies are listed 'Best First'.
Re: Library file or module for sharing code?
by choedebeck (Beadle) on Dec 27, 2005 at 23:44 UTC
    I vote for option 2. This way the namespace of your scripts doesn't get polluted and anyone looking at your scripts know where the function call is coming from. The only drawback is a little more typing. I would probably call the function like this though.
    $name = Common::get_uppercase($name)
    Since it really isn't a class.
      I agree with this post (no ++ votes left today).
Re: Library file or module for sharing code?
by sgifford (Prior) on Dec 28, 2005 at 04:10 UTC
    If you use Exporter, you can get the best of both worlds by making the functions from Common available for import into your script:

    COMMON 3

    package Common; use warnings; use strict; use base 'Exporter'; our @EXPORT_OK=qw(get_uppercase); sub get_uppercase { my ($class, $name) = @_; return uc($name); } 1;

    SCRIPT 3

    #!/usr/bin/perl use warnings; use strict; use CGI::Carp qw(fatalsToBrowser); use Common qw(get_uppercase); my $name = "frodo"; $name = get_uppercase($name);

    Update: Changed use Exporter to use base 'Exporter' to inherit properly. Sorry, bradcathey!

      This looks exactly like the answer I was wanting, but I get this error:

      Undefined subroutine &main::get_uppercase called at /usr/www/users/foo +bar/cgi-bin/test.pl line 9.

      What is missing?

      Update: The only way I could get this to work was use all the code outlined in Simple Module Tutorial.

      package Common; use strict; use Exporter; use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS); @ISA = qw(Exporter); @EXPORT = (); @EXPORT_OK = qw(get_uppercase); %EXPORT_TAGS = ( All => [qw(&get_uppercase)]); sub get_uppercase { my ($name) = @_; return uc($name); } 1;

      AND

      #!/usr/bin/perl -w use warnings; use strict; use CGI::Carp qw(fatalsToBrowser); use Common qw(:All); my $name = "frodo"; $name = get_uppercase($name);

      It needed:

      use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS); @ISA = qw(Exporter); @EXPORT = ();

      —Brad
      "The important work of moving the world forward does not wait to be done by perfect men." George Eliot

        The only important part that was missing was

        @ISA= qw(Exporter);

        But a better approach would be either:

        *import= \&Exporter::import;

        or, if you know you'll have a new enough version of Perl

        use Exporter qw(import);

        Because using inheritance to get a single method is a bad idea; it brings along too much unhelpful baggage.

        - tye        

        Did you remember to include this line in your calling script?
        use Common qw(get_uppercase);
        @EXPORT_OK just says that it's "okay to export", but it doesn't actually do the exporting automatically. For that you'd want the @EXPORT array, though I don't necessarily recommend using it. Here's a good article on exporting. (Annoying pop-ups though.)
Re: Library file or module for sharing code?
by ff (Hermit) on Dec 28, 2005 at 23:44 UTC
    For good or ill, I use the first style, although I do invoke the subs from the common file via their package name (to provide that absolute path/specificity). I use a short name for the package to keep that chunk from using too much space horizontally when I invoke the sub, as in:

    SCRIPT 1

    #!/usr/bin/perl use warnings; use strict; use CGI::Carp qw(fatalsToBrowser); require "common.lib"; my $name = "frodo"; $name = cm::get_uppercase($name);
    COMMON 1

    package cm; sub get_uppercase { my $name = shift; return uc($name); } 1;

    At distribution time I run a utility script that makes a single file in which I stick
     package main;
    in as the first effective line of my script and then appends the various 'require' files to the 'sendout' file so that my users only deal with one file. (The utility also deletes the original 'require' lines from the main section.) I do a few other things, too, to the 'sendout' file....