http://qs321.pair.com?node_id=242026

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

I am trying to get my head around creating my own module. I have got the following out of the Perl Cookbook and am having some difficulties. I have gone through SuperSearch but have not been able to find my answers

Given the following module which I called Test.pm and located in the c:/perl/site/lib dir ...
##Test Module package Test; use strict; use warnings; require Exporter; use vars qw(@ISA @EXPORT); my @ISA = qw(Exporter); my @EXPORT = qw( Prt Time ); sub Prt { my $string = shift; print &Time() . "- $string\n"; } sub Time { my @localdate = localtime(time); my $tme = sprintf("%02d:%02d:%02d", $localdate[2], $localdate[1], +$localdate[0]); return($tme); } 1;
I am using the following code to try and call a subroutine and pass it a string(only for this VERY BASIC test)..
#! /usr/bin/perl use strict; use warnings; use Test; print "About to use Module\n"; &Prt("This is a test in the Mod"); print "Finished\n";
This is what I get...

About to use Module Undefined subroutine &main::Prt called at C:\dev\Source_Perl\MiscTests +\mod.pl line 8.
I tried changing line 8. to
&Test::Prt("This is a test in the Mod");
as well as

Test::Prt("This is a test in the Mod");

as was suggested in a previous post but still get the same output.

Any help would be greatly appreciated.
J9

Replies are listed 'Best First'.
Re: Undefined subroutine
by blokhead (Monsignor) on Mar 11, 2003 at 14:20 UTC
    A few things wrong: you don't want these to be lexical (my) variables!

    my @ISA    = qw(Exporter);
    my @EXPORT = qw(Prt Time);
    

    They are not available to Exporter as lexicals, they need to be global symbol-table vars (thus the use vars).

    Heh, but the real reason Test::Prt still won't work is because Test is a very, very bad name for your first module. There is already a Test module in your Perl distribution, and your script is most likely loading that instead. A use lib '.' line in the script will tell Perl to look in the current directory to load modules first. Either do that, or change the name of your module's namespace.

    blokhead

      Hehe.. <REDFACE MODE ON>

      I have fixed the lexical variable this, that is after all why I used the use vars declaration.

      I have also renamed my module to J9Test.pm now I KNOW there isn't another module there with that name..(I checked)

      <REDFACE MODE OFF>
Re: Undefined subroutine
by Wonko the sane (Deacon) on Mar 11, 2003 at 14:33 UTC
    Corrected and tested version of your code.
    ############################################## package J9Test; use strict; use warnings; use vars qw(@ISA @EXPORT); use Exporter; @ISA = qw(Exporter); @EXPORT = qw( Prt Time ); sub Prt { my $string = shift; print &Time() . "- $string\n"; } sub Time { my @localdate = localtime(time); my $tme = sprintf("%02d:%02d:%02d", $localdate[2], $localdate[1], +$localdate[0]); return($tme); } 1; ############################################## ############################################## #!/usr/bin/perl use strict; use warnings; use lib q{.}; use J9Test; print "About to use Module\n"; Prt("This is a test in the Mod"); print "Finished\n"; ##############################################

    Damian Conway's Object Oriented Perl has one of the better explanations of how all this works.
    I always highly recomend that book.

    Wonko

Re: Undefined subroutine
by broquaint (Abbot) on Mar 11, 2003 at 14:11 UTC
    Try the following bit of code (with appropriate quoting rules per prompt)
    shell> perl -MTest -le 'print $INC{"Test.pm"};
    If you get something like
    /usr/lib/perl5/5.6.1/Test.pm
    Then you either need to force the @INC to look for your module first with a liberal use of use lib or rename your module.
    HTH

    _________
    broquaint

      I have run
      perl -MTest -le print $INC{"J9Test.pm"};
      (as I renamed my module) on my MS machine but get a blank line returned.
        ... (as I renamed my module) on my MS machine but get a blank line returned.
        That's to be expected as you're no longer including Test.pm. If you change the -M switch to -MJ9Test it will output the path to J9Test.pm relative to @INC.
        HTH

        _________
        broquaint

Re: Undefined subroutine
by mattriff (Chaplain) on Mar 11, 2003 at 14:11 UTC
    Perl already has a Test module. I believe your second piece of code is finding that first and using it.

    You can add:

    use lib '.';
    to your script to make sure it finds your module first (assuming Test.pm is in the same directory as the script).

    You probably just want to rename your module, though.

    - Matt Riffle

      Renamed the module to J9Test.pm and changed the use part of the script to use J9Test.pm

      Still get the same result though.
Re: Undefined subroutine
by nite_man (Deacon) on Mar 11, 2003 at 14:51 UTC
    I think that problem is in following. Your module has name like the module Test.pm from in standart perl library and this module doesn't have function Prt. Try to put this module in some dir and use it like this:
    use MyTest::Test;
    And It doesn't need to use my with @ISA and @EXPORT and maybe more efficient to use BEGIN:
    package MyTest::Test; use strict; use warnings; BEGIN { use Exporter(); vars qw(@ISA, @EXPORT); @ISA = qw(Exporter); @Export = qw(Prt Time); }

    ==================
    { firstname => 'Michael',
    quote => 'Mice were crying and stinging but went on nibbling the cactus', }

Re: Undefined subroutine
by J9 (Beadle) on Mar 11, 2003 at 14:45 UTC
    Many Thanks everyone,

    I have (with all the help offered) successfully used a module that you all wrote. Now if only I can write one myself. hehe
Re: Undefined subroutine
by hiseldl (Priest) on Mar 11, 2003 at 14:15 UTC

    In order to use OO to it's fullest, you will need to create a constructor ('new' method) and then you can instantiate an object with your class:

    package Test; ... sub new { my $self = {}; bless $self; return $self; } ... use Test; my $test_var = new Test; $test_var->Prt("This is a test in the Mod\n");

    You should also take a look at perltoot which has some more details about how to create constructors.

    Update: You should make sure that your module does not have the same name as an already installed module, or else you can cause yourself some unneeded confusion.

    Update: why do I need to use OO stuff? You don't need to use the OO stuff. Your statement was 'Any help would be greatly appreciated' and I was simply offering another solution. Sorry for the confusion.

    --
    hiseldl
    What time is it? It's Camel Time!

      I'll give this a bash, but I can't help wondering why I need to use OO stuff though. I just want to use a module straight like I would with
      #! /use/bin/perl use strict; use Term::ReadKey; ReadMode( "noecho"); print "Enter pwd please :"; chomp (my $pwd = <>); ReadMode ("original") ; print "\nYou typed $pwd!\n";
      where ReadMode is a subroutine in the Term::ReadKey module.
      Isn't a Module != Object?

      -- zigdon

        Yes, you are correct, a module is not an object, but you can use a module to instantiate an object. e.g. use MyMod; $object = new MyMod;

        --
        hiseldl
        What time is it? It's Camel Time!