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

Update: As of 9:54pm EST, the problem has automagically resolved itself. Which is a tidgy bit frustrating, but hey, at least it works. I'm going to decide that the Perl gods were punishing me for the klugy method of adding functionality, and telling me to make an extension module, for goodness sake.

I'm trying to add a function to Dice.pm that will roll dice according to White Wolf's WOD rules and return the number of successes. I've succeeded in creating a function that does this (roughly, anyway); my problem now is that I get a "roll_whitewolf is not exported by module Games::Dice.pm" error. I can't figure out why.

Here's the altered Dice.pm, minus perldoc. My function is roll_whitewolf:

package Games::Dice; use strict; use vars qw($VERSION @ISA @EXPORT @EXPORT_OK); require Exporter; @ISA = qw(Exporter); # Items to export into callers namespace by default. Note: do not expo +rt # names by default without a very good reason. Use EXPORT_OK instead. # Do not simply export all your public functions/methods/constants. @EXPORT_OK = qw( roll roll_array roll_whitewolf ); $VERSION = '0.02'; # Preloaded methods go here. sub roll ($) { my($line, $dice_string, $sign, $offset, $sum, @throws, @result); $line = shift; return undef unless $line =~ m{ ^ # beginning of line ( # dice string in $1 (?:\d+)? # optional count [dD] # 'd' for dice (?: # type of dice: \d+ # either one or more digits | # or % # a percent sign for d% = d100 ) ) (?: # grouping-only parens ([-+xX*/bB]) # a + - * / b(est) in $2 (\d+) # an offset in $3 )? # both of those last are optional }x; # whitespace allowed $dice_string = $1; $sign = $2 || ''; $offset = $3 || 0; $sign = lc $sign; @throws = roll_array( $dice_string ); return undef unless @throws; if( $sign eq 'b' ) { $offset = 0 if $offset < 0; $offset = @throws if $offset > @throws; @throws = sort { $b <=> $a } @throws; # sort numerically, de +scending @result = @throws[ 0 .. $offset-1 ]; # pick off the $offset + first ones } else { @result = @throws; } $sum = 0; $sum += $_ foreach @result; $sum += $offset if $sign eq '+'; $sum -= $offset if $sign eq '-'; $sum *= $offset if ($sign eq '*' || $sign eq 'x'); do { $sum /= $offset; $sum = int $sum; } if $sign eq '/'; return $sum; } sub roll_array ($) { my($line, $num, $type, @throws); $line = shift; return undef unless $line =~ m{ ^ # beginning of line (\d+)? # optional count in $1 [dD] # 'd' for dice ( # type of dice in $2: \d+ # either one or more digits | # or % # a percent sign for d% = d100 ) }x; # whitespace allowed $num = $1 || 1; $type = $2; $type = 100 if $type eq '%'; @throws = (); for( 1 .. $num ) { push @throws, int (rand $type) + 1; } return @throws; } sub roll_whitewolf { my ($pool, $diff, $crits) = @_; my @rolls; my $successes = 0; my $tens = 0; return undef if (!$pool || !$diff); @rolls = roll_array($pool . 'd10'); foreach (@rolls){ if ($_ == 1){ $successes--; $tens-- if ($tens > 0); } elsif ($_ >= $diff){ $successes++; $tens++ if ($_ == 10); } } if ($crits && $tens != 0) { $successes += roll_whitewolf($tens, $diff, ''); } return $successes; } 1;

And here's the driver program:

#!/usr/bin/perl use strict; use warnings; use Games::Dice 'roll', 'roll_array', 'roll_whitewolf'; print roll_whitewolf(10, 8, 'yes');

Which produces this error message:

"roll_whitewolf" is not exported by the Games::Dice module Can't continue after import errors at dice.test.pl line 4 BEGIN failed--compilation aborted at dice.test.pl line 4.

Replies are listed 'Best First'.
Re: Dice.pm - I'm doing it wrong, somehow.
by JavaFan (Canon) on Oct 17, 2008 at 00:00 UTC
    Are you sure that your "use Games::Dice" is using your Games::Dice, and not the original one (which I presume you installed from CPAN?)

    Note that copying and adding functions to the copy isn't the best way of extending a module. I would either write a Games::Dice::Whitewolf which would either has a package Games::Dice::Whitewolf, which uses Games::Dice and (re)exports its functions, and has roll_whitewolf, or adds 'roll_whitewolf' to @Games::Dice::EXPORT_OK and has a Games::Dice::roll_whitewolf.

    In either case, if the original Games::Dice gets updated, you don't have to change your code (assuming it doesn't change its API).

      Sadly, yes, as I don't have Games::Dice installed. First thing I checked. I don't even see how it could be cached somewhere, as I've tested that altering my Dice.pm alters the program's behavior (Deleting subroutines from Dice.pm causes errors was my test).

      I'm not planning on doing it this way "For keeps." I emailed the function to the module's maintainer as a "rough draft." I'm just perplexed as to why this isn't working for me, since my function is designed identically and in the same context as the two native functions.

Re: Dice.pm - I'm doing it wrong, somehow.
by ikegami (Patriarch) on Oct 17, 2008 at 00:02 UTC
    A visual inspection didn't find anything questionable, so I tried it. It works as is. I think Perl is finding a different file than the one you think it's finding. Does the following output the right file name?
    perl -le"use Games::Dice; print $INC{'Games/Dice.pm'}"