package Sub::Approx;

use strict;
use vars qw($VERSION @ISA $AUTOLOAD);
use Text::Soundex;

$VERSION = '0.03';

# import is called when another script uses this module.
# All we do here is overwrite the callers AUTOLOAD function
# with our own.
sub import  {
  no strict 'refs'; # WARNING: Deep magic here!
  my $pkg =  caller(0);
  *{"${pkg}::AUTOLOAD"} = \&AUTOLOAD;
}

# AUTOLOAD is a function which is called when a given subroutine
# name can't be found in the current package. In the import function
# above we have already arranged that our calling package will use
# this AUTOLOAD instead of its own.
sub AUTOLOAD {
  my %cache;
  my @c = caller(0);
  my ($pkg, $sub) = $AUTOLOAD =~ /^(.*)::(.*)$/;

  no strict 'refs'; # WARNING: Deep magic here!

  # Iterate across the keys of the stash for our calling package.
  # For each typeglob found, work out if it contains a function
  # definition. If it does, then work out the equivalent soundex
  # value and store it in the cache hash. Actually we store a list
  # of function names against each soundex value.
  foreach (keys %{"${pkg}::"}) {
    my $glob = $::{$_};
    
    $glob =~ s/^\*${pkg}:://;

    push @{$cache{soundex($glob)}}, $glob if defined &{"*${pkg}::$glob"};
  }

  # Now work out the soundex value for the function that has been called
  $sub = soundex($sub);

  # See if a function (or functions) exist with the same soundex value.
  # If so, pick one at random to call and call it using magic goto.
  # If not, die recreating Perl's usual behaviour.
  if (exists $cache{$sub}) {
    my @f = @{$cache{$sub}};
    $sub = "${pkg}::$f[rand @f]";
    goto &$sub;
  } else {
    die "REALLY Undefined subroutine $AUTOLOAD called at $c[1] line $c[2]\n";
  }
}

1;
__END__

=head1 NAME

Sub::Approx - Perl extension for blah blah blah

=head1 SYNOPSIS

  use Sub::Approx;
  
  sub a {
    # blah...
  }

  &aa; # executes &a if &aa doesn't exist.

=head1 DESCRIPTION

This is _really_ stupid. This module allows you to call functions by
_approximate_ names. Why you would ever want to do this is a complete
mystery to me. It was written as an experiment to see how well I 
understood typeglobs and AUTOLOADing.

To use it, simply include the line:

  use Sub::Approx;

somewhere in your program. Then each time you call a function that doesn't
exist in the the current package Perl will search for a function with
approximately the same name. Currently 'approximately' means 'with the same
soundex value as generated by Text::Soundex' - but this may change (or even
become configurable). If more than one function is found that matches, then
one is chosen at random.

I can't stress too strongly that this will make your code completely 
unmaintainable and you really shouldn't use this module unless you're 
doing something very stupid.

=head1 ACKNOWLEDGEMENTS

This idea came to me whilst sitting in Mark-Jason Dominus' "Tricks of
the Wizards" tutorial. In order to protect his reputation I should
probably point out that just as the idea was forming in my head he
clearly said that this kind of thing was a very bad idea.

=head1 AUTHOR

Dave Cross <dave@dave.org.uk>

=head1 SEE ALSO

perl(1).

=cut
