Beefy Boxes and Bandwidth Generously Provided by pair Networks
We don't bite newbies here... much
 
PerlMonks  

Perl Module Problems

by davidov0009 (Scribe)
on Sep 23, 2006 at 17:00 UTC ( [id://574527]=perlquestion: print w/replies, xml ) Need Help??

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

I am writing a perl module that, when supplied a the name of a game, locates the map directory and creates an array with the map names for that specific game. I am getting several errors that are unclear to me. Here is the module.
package MAP; use diagnostics; use strict; use Exporter; use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS); $VERSION = 1.00; @ISA = qw(Exporter); @EXPORT = (); @EXPORT_OK = qw(array); # Create Map Array given an argument. sub array { # Declare Variables my $game = @_; my $user = $ENV{'USER'}; # Create Dir Path my $dir = "/home/$user/hlds_l/$game/maps/"; #Read maps from directory if (-d $dir) { opendir(MAPS, $dir) || die("Cannot open directory"); @$game= readdir(MAPS); closedir(MAPS); # Take only maps and trim .bsp @$game=grep /\.bsp/, @$game; my $map; foreach $map (@$game) { $map=~ s/\.bsp// } } return (@$game); } 1; # end
This module is saved as MAP.pm in the same directory as the script below that calls it. Here is the script (saved as loadmap.pl) to check if the array has been created.
#!/usr/bin/perl5 -w use diagnostics; # Load Module use MAP; # Call Routine MAP::array("cstrike"); # Print returned array my $map; foreach $map (@cstrike) { print "$map\n"; }
And here are the errors I receieve from running loadmap.pl
Name "main::cstrike" used only once: possible typo at ./loadmap.pl lin +e 12 (#1) (W once) Typographical errors often show up as unique variable nam +es. If you had a good reason for having a unique name, then just menti +on it again somehow to suppress the message. The our declaration is provided for this purpose. Can't use string ("1") as an ARRAY ref while "strict refs" in use at M +AP.pm line 39 (#2) (F) Only hard references are allowed by "strict refs". Symbolic references are disallowed. See perlref. Uncaught exception from user code: Can't use string ("1") as an ARRAY ref while "strict refs" in +use at MAP.pm line 39. MAP::array('cstrike') called at ./loadmap.pl line 9
If I disable strict and diagnostics and -w in both the script and the pm I receive no ouput at all. I am not using an array reference, I am passing the arg cstrike to the sub array in order to create an array for game cstrike. Any help appreciated.

Replies are listed 'Best First'.
Re: Perl Module Problems
by ikegami (Patriarch) on Sep 23, 2006 at 17:24 UTC
    • In scalar context, an array returns the number of elements it contains. That means my $game = @_; assignes the number of arguments (1) to $game. Force the assignment into a list context.
      my $game = @_;
      should be
      my ($game) = @_;

    • All instances of @$game in your sub should be @maps. Don't forget to do my @maps;. There's no reason for the array to be named after the game, which is what you are trying to do with symbolic references (which are almost always bad and causing some of your errors).

    • array is an aweful name for that sub. What about get_game_maps?

    • my $map; foreach $map (@maps)
      can be written more concisely as
      foreach my $map (@maps)

    • Your function returns a list of maps, but you discard the return value.
      MAP::array("cstrike");
      should be
      my @cstrike_maps = MAP::array("cstrike");

    • Congrats for using use strict;. You should also use use warnings;. Warnings almost always point to an error. ( Oops! I see you used -w. I'd put use warnings; in the module explicitely. You shouldn't rely on the calling script using -w. )

    • use vars qw( @ISA ); @ISA = qw( Exporter );
      can be written more concisely as
      our @ISA = qw( Exporter );

    • Handle MAPS should be localized. Better yet, it should be a lexical (my) variable.

    use strict; use warnings; use diagnostics; package MAP; use Exporter (); our $VERSION = 1.00; our @ISA = qw( Exporter ); our @EXPORT = (); our @EXPORT_OK = qw( get_game_maps ); sub get_game_maps { # Declare Variables my ($game) = @_; my $user = $ENV{'USER'}; # Create Dir Path my $dir = "/home/$user/hlds_l/$game/maps/"; # We're done if the dir does not exist. return unless -d $dir; opendir(my $maps_dh, $dir) || die("Cannot open directory"); my @maps = readdir($maps_dh); closedir($maps_dh); # Take only maps and trim .bsp @maps = grep /\.bsp\z/, @maps; foreach my $map (@maps) { $map =~ s/\.bsp\z//; } return @maps; } 1; # end
    #!/usr/bin/perl5 use strict; use warnings; use diagnostics; # Load Module use MAP; # Call Routine my @cstrike_maps = MAP::get_game_maps("cstrike"); # Print returned array foreach my $map (@cstrike_maps) { print "$map\n"; }

    Update: A more consice version of the sub:

    use List::Util qw( apply ); sub get_game_maps { my ($game) = @_; my $user = $ENV{'USER'}; my $dir = "/home/$user/hlds_l/$game/maps/"; # We're done if the dir does not exist. return unless -d $dir; opendir(my $maps_dh, $dir) or die("Cannot open directory"); return apply { s/\.bsp\z// } grep { /\.bsp\z/ } readdir($maps_dh); }
      Thanks for the help. The reason it creates @$game is because this sub is used multiple times to create arrays for many different games within the same script.
        On second thought, I see why you can call the @maps array within the function because the retruned values are dumped into their own arrays within the script that calls the function.
      Using most of your suggestions I have fixed up my Module and made it give no errors when run using the debugger. I am receiving this error however from the testing script:
      Can't use string ("cstrike") as an ARRAY ref while "strict refs" in us +e at HLDS.pm line 34 (#1) (F) Only hard references are allowed by "strict refs". Symbolic references are disallowed. See perlref. Uncaught exception from user code: Can't use string ("cstrike") as an ARRAY ref while "strict ref +s" in use at HLDS.pm line 34. HLDS::GameMaps('cstrike') called at test.pl line 11
      When I leave the string unquoted it gives this error:
      Bareword "cstrike" not allowed while "strict subs" in use at test.pl l +ine 11. Execution of test.pl aborted due to compilation errors (#1) Uncaught exception from user code: Bareword "cstrike" not allowed while "strict subs" in use at t +est.pl line 11. Execution of test.pl aborted due to compilation errors.
      I am not referring to an array, just passing an argument as a string. What to do?
        That error is caused by @$game. $game is treated as a reference, but it contains a string. This is known as a symbolic reference. Symbolic references are disallowed by use strict; (or more specifically, use strict 'vars';) for the reasons explained in Why it's stupid to `use a variable as a variable name'.
    A reply falls below the community's threshold of quality. You may see it by logging in.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://574527]
Approved by shenme
Front-paged by diotalevi
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others about the Monastery: (4)
As of 2024-04-23 07:13 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found