The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
package Module::Filename;
use strict;
use warnings;
use base qw{Exporter};
use Path::Class qw{file};

our $VERSION = '0.02';
our @EXPORT_OK = qw(module_filename);

=head1 NAME

Module::Filename - Provides an object oriented, cross platform interface for getting a module's filename

=head1 SYNOPSIS

  use Module::Filename;
  my $filename=Module::Filename->new->filename("Test::More"); #isa Path::Class::File

  use Module::Filename qw{module_filename};
  my $filename=module_filename("Test::More");                 #isa Path::Class::File

=head1 DESCRIPTION

This module returns the filename as a L<Path::Class::File> object.  It does not load any packages as it scans.  It simply scans @INC looking for a module of the same name as the package passed.

=head1 USAGE

  use Module::Filename;
  my $filename=Module::Filename->new->filename("Test::More"); #isa Path::Class::File
  print "Test::More can be found at $filename\n";

=head1 CONSTRUCTOR

=head2 new

  my $mf=Module::Filename->new();

=cut

sub new {
  my $this = shift();
  my $class = ref($this) || $this;
  my $self = {};
  bless $self, $class;
  $self->initialize(@_);
  return $self;
}

=head1 METHODS

=head2 initialize

You can inherit the filename method in your package.

  use base qw{Module::Filename};
  sub initialize{do_something_else()};

=cut

sub initialize {
  my $self = shift();
  %$self=@_;
}

=head2 filename

Returns a L<Path::Class::File> object for the first filename that matches the module in the @INC path array.

  my $filename=Module::Filename->new->filename("Test::More"); #isa Path::Class::File
  print "Filename: $filename\n";

=cut

sub filename {
  my $self=shift;
  return module_filename(@_);
}

=head1 FUNCTIONS

=head2 module_filename

Returns a L<Path::Class::File> object for the first filename that matches the module in the @INC path array.

  my $filname=module_filename("Test::More"); #isa Path::Class::File
  print "Filename: $filename\n";

=cut


sub module_filename {
  die("Error: Module name required.") unless @_;
  my $module=shift;
  my $file=file(split("::", $module.".pm"));
  my $return=undef;
  foreach my $path (@INC) {
    next unless defined $path;
    next if ref($path);
    my $filename=file($path,  $file);
    if (-f $filename) {
     $return=$filename;
     last; #return the first match in @INC
    }
  }
  return $return;
}


=head1 LIMITATIONS

The algorithm does not scan inside module files for provided packages.

=head1 BUGS

Submit to RT and email author.

=head1 SUPPORT

DavisNetworks.com supports all Perl applications including this package.

=head1 AUTHOR

  Michael R. Davis
  CPAN ID: MRDVT
  STOP, LLC
  domain=>michaelrdavis,tld=>com,account=>perl
  http://www.stopllc.com/

=head1 COPYRIGHT

This program is free software licensed under the...

  The BSD License

The full text of the license can be found in the LICENSE file included with this module.

=head1 SEE ALSO

Module::Filename predates L<Module::Path> by almost 4 years but it appears more people prefer L<Module::Path> over Module::Filename as it does not have the dependency on L<Path::Class>.  After the reviews on L<http://neilb.org/reviews/module-path.html>. I added the functional API to Module::Filename.  So, your decision is simply an object/non-object decision.   The operations with the file system that both packages perform outweigh the performance of the object creation in Module::Filename.  So, any performance penalty should not be measurable.  Since Module::Filename does not need three extra file test operations that Module::Path 0.18 performs on each @INC directory, Module::Filename may actually be faster than L<Module::Path> for most applications.

=head2 Similar Capabilities

L<Module::Path>, L<perlvar> %INC, L<pmpath>, L<Module::Info> constructor=>new_from_module, method=>file, L<Module::InstalledVersion> property=>"dir", L<Module::Locate> method=>locate, L<Module::Util> method=>find_installed

=head2 Comparison

CPAN modules for getting a module's path L<http://neilb.org/reviews/module-path.html>

=cut

1;