------------------------------------------------------------------------------- Hints tips, problems and solutions to Perl 5 library modules ------------------------------------------------------------------------------- Perl Module destructors not called on signal interupt The destructors are only called on a normal exit() or die() (the shell equivelent of ''trap 0'' ), not when a signal kills the program or if the program calls exec(). The solution is to provide some signal handlers which will call die() or exit() when finished, in which case signal exits will occur as expected. Alturnativally add... use sigtrap qw(die normal-signals error-signals); And a die() handler will be installed on most 'kill program' signals, which will then croak(), thus allowing destructors to finish up. NOTE: I would only use the above sigtrap module on simple programs that have no critical period involved. Also see "general.txt" for "Signal Handling" ------------------------------------------------------------------------------- Deparse (well not exactly) The following will parse the perl code and deparse the source from the internal compilation. Note that because of this inlined functions and other added constructs (like -p or -n loops) will also be included. perl -MO=Deparse,i2 script.pl See manpage B::Deparse for more info ------------------------------------------------------------------------------- Getopt::Std fails when you do not define ALL options. If the getopt option string does NOT define all the options that a program could recieve, IE: you only define those you are interested in, It cand easilly get confused and return completely bogus results. Example for a program called with program -a1 -sstring -ffile -edfsl But in the program you only want the options -s and -f (the rest being passed to a different sub-program), you may be tempted to use getopt("s:f:", \%args); However getopt will see the option "-edfsl" and by default think it is a multi-option switch. That is it will see it as.. -e -d -fsl It knows "-f" has arguments so it will return $args{f} = 'sl' instead of the previous and correct argument $args{f} = 'file' I do NOT recomend the use of getopt. I do however recomend any option handled correctly deal with options such as '-?' (help), '--' (end of options) and '-' (file from stdin). ------------------------------------------------------------------------------- IO::Select after IO::Handle Closed WARNING: If a IO::Handle has closed you can NOT remove it from a IO::Select structure, after the fact! Basically as it is closed it no longer has a valid file descriptor, and thus can not be indexed by the IO::Select module to remove descriptor from event selector data structure. If it is still in the structure, it is imposible to remove that specific file handle, unless you remove all the IO::Handles, and re-add those you want (which can be a difficult thing to decide). :-( ------------------------------------------------------------------------------- Term::ANSIColor Converts names into ANSI color sequences use Term::ANSIColor; print color('bold blue'), print "text is bold blue.\n", color('reset'); print colored("This text is colored", 'yellow on_magenta'), "\n"; print colored(['bright_red on_black'], 'Aliens approahing', "\n"); # extras that can also be imported colorvalid('red'); # return true if color sequence can be determined colorstrip("string"); # remove color sequences from string coloralias('warning','red on_yellow'); # create a simpler name use Term::ANSIColor qw(:constants); print BOLD, BLUE, "This text is in bold blue.\n", RESET; ------------------------------------------------------------------------------- Expect -- unblessed referance for 'timeout' bug.... The a direct sub-routine callback for 'timeout' is not passing a blessed array reference! That is this does NOT work as it is supposed to... finished() { my($fh, $reason) = @_; ... } ... $fh->expect(60, [ timeout => \&finish, "FAILED LOGIN - Timeout" ], The $fh in finished() will be an array referance, but will not be blessed resulting in a error: Can't call method "expect" on unblessed reference at ... To fix this you need to use "sub { ... }" and call the sub-routine with the original variable. $fh->expect(60, [ timeout => sub { &finish($fh, "FAILED LOGIN - Timeout") } ], Note that this also does NOT work (the shifted vaule is also unblessed) $fh->expect(60, [ timeout => sub { &finish(shift, "FAILED LOGIN - Timeout") } ], Arrrgghhhhhh...... ------------------------------------------------------------------------------- dbmopen() and DBM tie modules... The perl DBM routines do NOT understand the `exists()' method for DBM files. However as you can NOT store a undef value in a DBM file the `defined()' method is equivelent. ------------------------------------------------------------------------------- Time in Seconds and MicroSeconds See FineTime module (Perl Cookbook recipe 12.14) ------------------------------------------------------------------------------- Decode Base 64 Encoded files (mime mail) perl -MMIME::Base64 -pe '$_ = decode_base64($_)' file.b64 > decoded_file ------------------------------------------------------------------------------- FileCache -- output to huge numbers of files. When you are dealing with a HUGE number of output files, more than 64 under solaris or 1024 under linux, then you need to use something to open, close and re-open file handles as you require them. Filecache exports a cacheout() function which will ensure the given file is opened (trucated when first seen and open for append there after) and thus ready for printing to. When FileCache runs out of file descriptors, it will sort and close the oldest unused 1/3rd of all the opened files handles it is handling. use FileCache; # Set the correct maximum number of file descriptors available - 5; $FileCache::cacheout_maxopen = `csh -c limit | awk '\$1 == "descriptors" {printf "%d", \$2 - 5}'`; cacheout $file_path; print $file_path "Output Line\n"; # This function should have been part of the FileCache module but was not # provided. It ensures the close only happens on files which are open # (according to the module) and notifies the module of that fact. sub cache_close { if( $FileCache::isopen{$_[0]} ) { close $_[0]; delete $FileCache::isopen{$_[0]}; $FileCache::cacheout_numopen--; } } NOTE There are other multiple IO file handle modules in the CPAN library. which may allow multiple files to be opened for input, or purly for append, or maybe have other styles of selecting files to be closed when the program runs out of descriptors. WARNING: I have been told the above was fixed in perl 5.8 and the above no longer works for perl 5.8 ------------------------------------------------------------------------------- Generate Fractal images with PDL module. use PDL; use PDL::IO::Pic; $a=zeroes 300,300; $r=$a->xlinvals(-1.5,0.5); $i=$a->ylinvals(-1,1); $t=$r; $u=$i; for(1..30){ $q=$r**2-$i**2+$t; $h=2*$r*$i+$u; $d=$r**2+$i**2; $a=lclip($a,$_*($d>2.0)*($a==0)); ($r,$i)=map{$_->clip(-5,5)}($q,$h); } $a->wpic("mandel.gif"); Courtesy of Tuomas J.Lukka ------------------------------------------------------------------------------- Timing Perl Proceedures (Benchmarking) # Timing test of extract first character from a string use Benchmark; timethese( 100000, { 'regex1' => '$str="ABCDEFG"; $str =~ s/^(.)//; $ch = $1', 'regex2' => '$str="ABCDEFG"; $str =~ s/^.//; $ch = $&', 'substr1' => '$str="ABCDEFG"; $ch=substr($str,0,1); substr($str,0,1)="";', 'substr2' => '$str="ABCDEFG"; $ch=substr($str,0,1); $str=substr($str,1);', 'unpack' => '$str="ABCDEFG"; ($ch,$str) = unpack("A1A*",$str);', }); ------------------------------------------------------------------------------- List::Util and List::MoreUtil sum @F sum of elements perl -MList::Util=sum -alne 'print sum @F' print "@{[shuffle @F]}" # print a shuffle of the fields min @F Minimum max @F Maximum scalar @F # number of fields (built-in) ------------------------------------------------------------------------------- Memorizing function results Functions that depend only on the arguments, but do a lot of calculation to produce a result (even by reading files) should memorize the previous results rather than re-calculate them. Alturnativally you can use the Memoize module to record previous arguments and results. Use Memoize; memoize 'fibo'; and it'll automcatically memoize the fibo function. Memorizing can be a big save for recursive functions (like factorial() ) and for data which is being sorted (without needing the Schwartzian Transform) Example with Memoize Module (date comparision of from Use Memoize; %m2n = ( jan => 0, ..., dec => 11 ); sub to_number { my ($m, $d, $y) = ($_[0] =~ /(\w{3}) (\d+), (\d+)/); sprintf("%04d%02d%02d", $y, $m2n{$m}, $d); } memoize 'to_number'; sub compare_dates { to_number($a) <=> to_number($b); } sort \&compare_dates @dates; Example without the Memoize module. { my %cache; sub compare_dates { ($cache{$a} ||= to_number($a)) <=> ($cache{$b} ||= to_number($b)) } } sort \&compare_dates @dates; This technique is known as the "Orcish Maneuver", dubbed by Joseph Hall, author of "Effective Perl Programming". It can also be used for profiling... EG: if a memorized function makes the program faster then rewriting the function for speed makes good sense, otherwise it will have little effect! For a simpler module look at MiniMemoise Reference... http://perl.plover.com/yak/hw1/Hardware.html -------------------------------------------------------------------------------