"Fossies" - the Fresh Open Source Software Archive

Member "Module-Build-0.4229/inc/Module/Metadata.pm" (15 Apr 2019, 20801 Bytes) of package /linux/privat/Module-Build-0.4229.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Perl source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "Metadata.pm" see the Fossies "Dox" file reference documentation.

    1 # -*- mode: cperl; tab-width: 8; indent-tabs-mode: nil; basic-offset: 2 -*-
    2 # vim:ts=8:sw=2:et:sta:sts=2
    3 package Module::Metadata;
    4 
    5 # stolen from Module::Build::Version and ::Base - this is perl licensed code,
    6 # copyright them.
    7 
    8 # This module provides routines to gather information about
    9 # perl modules (assuming this may be expanded in the distant
   10 # parrot future to look at other types of modules).
   11 
   12 use strict;
   13 use vars qw($VERSION);
   14 $VERSION = '1.000002';
   15 $VERSION = eval $VERSION;
   16 
   17 use File::Spec;
   18 use version 0.87;
   19 BEGIN {
   20   if ($INC{'Log/Contextual.pm'}) {
   21     Log::Contextual->import('log_info');
   22   } else {
   23     *log_info = sub (&) { warn $_[0]->() };
   24   }
   25 }
   26 use File::Find qw(find);
   27 
   28 my $V_NUM_REGEXP = qr{v?[0-9._]+};  # crudely, a v-string or decimal
   29 
   30 my $PKG_REGEXP  = qr{   # match a package declaration
   31   ^[\s\{;]*             # intro chars on a line
   32   package               # the word 'package'
   33   \s+                   # whitespace
   34   ([\w:]+)              # a package name
   35   \s*                   # optional whitespace
   36   ($V_NUM_REGEXP)?        # optional version number
   37   \s*                   # optional whitesapce
   38   ;                     # semicolon line terminator
   39 }x;
   40 
   41 my $VARNAME_REGEXP = qr{ # match fully-qualified VERSION name
   42   ([\$*])         # sigil - $ or *
   43   (
   44     (             # optional leading package name
   45       (?:::|\')?  # possibly starting like just :: (  la $::VERSION)
   46       (?:\w+(?:::|\'))*  # Foo::Bar:: ...
   47     )?
   48     VERSION
   49   )\b
   50 }x;
   51 
   52 my $VERS_REGEXP = qr{ # match a VERSION definition
   53   (?:
   54     \(\s*$VARNAME_REGEXP\s*\) # with parens
   55   |
   56     $VARNAME_REGEXP           # without parens
   57   )
   58   \s*
   59   =[^=~]  # = but not ==, nor =~
   60 }x;
   61 
   62 
   63 sub new_from_file {
   64   my $class    = shift;
   65   my $filename = File::Spec->rel2abs( shift );
   66 
   67   return undef unless defined( $filename ) && -f $filename;
   68   return $class->_init(undef, $filename, @_);
   69 }
   70 
   71 sub new_from_module {
   72   my $class   = shift;
   73   my $module  = shift;
   74   my %props   = @_;
   75 
   76   $props{inc} ||= \@INC;
   77   my $filename = $class->find_module_by_name( $module, $props{inc} );
   78   return undef unless defined( $filename ) && -f $filename;
   79   return $class->_init($module, $filename, %props);
   80 }
   81 
   82 {
   83   
   84   my $compare_versions = sub {
   85     my ($v1, $op, $v2) = @_;
   86     $v1 = version->new($v1)
   87       unless eval { $v1->isa('version') };
   88   
   89     my $eval_str = "\$v1 $op \$v2";
   90     my $result   = eval $eval_str;
   91     log_info { "error comparing versions: '$eval_str' $@" } if $@;
   92   
   93     return $result;
   94   };
   95 
   96   my $normalize_version = sub {
   97     my ($version) = @_;
   98     if ( $version =~ /[=<>!,]/ ) { # logic, not just version
   99       # take as is without modification
  100     }
  101     elsif ( ref $version eq 'version' ) { # version objects
  102       $version = $version->is_qv ? $version->normal : $version->stringify;
  103     }
  104     elsif ( $version =~ /^[^v][^.]*\.[^.]+\./ ) { # no leading v, multiple dots
  105       # normalize string tuples without "v": "1.2.3" -> "v1.2.3"
  106       $version = "v$version";
  107     }
  108     else {
  109       # leave alone
  110     }
  111     return $version;
  112   };
  113 
  114   # separate out some of the conflict resolution logic
  115 
  116   my $resolve_module_versions = sub {
  117     my $packages = shift;
  118   
  119     my( $file, $version );
  120     my $err = '';
  121       foreach my $p ( @$packages ) {
  122         if ( defined( $p->{version} ) ) {
  123     if ( defined( $version ) ) {
  124       if ( $compare_versions->( $version, '!=', $p->{version} ) ) {
  125         $err .= "  $p->{file} ($p->{version})\n";
  126       } else {
  127         # same version declared multiple times, ignore
  128       }
  129     } else {
  130       $file    = $p->{file};
  131       $version = $p->{version};
  132     }
  133         }
  134         $file ||= $p->{file} if defined( $p->{file} );
  135       }
  136   
  137     if ( $err ) {
  138       $err = "  $file ($version)\n" . $err;
  139     }
  140   
  141     my %result = (
  142       file    => $file,
  143       version => $version,
  144       err     => $err
  145     );
  146   
  147     return \%result;
  148   };
  149 
  150   sub package_versions_from_directory {
  151     my ( $class, $dir, $files ) = @_;
  152 
  153     my @files;
  154 
  155     if ( $files ) {
  156       @files = @$files;
  157     } else {
  158       find( {
  159         wanted => sub {
  160           push @files, $_ if -f $_ && /\.pm$/;
  161         },
  162         no_chdir => 1,
  163       }, $dir );
  164     }
  165 
  166     # First, we enumerate all packages & versions,
  167     # separating into primary & alternative candidates
  168     my( %prime, %alt );
  169     foreach my $file (@files) {
  170       my $mapped_filename = File::Spec->abs2rel( $file, $dir );
  171       my @path = split( /\//, $mapped_filename );
  172       (my $prime_package = join( '::', @path )) =~ s/\.pm$//;
  173   
  174       my $pm_info = $class->new_from_file( $file );
  175   
  176       foreach my $package ( $pm_info->packages_inside ) {
  177         next if $package eq 'main';  # main can appear numerous times, ignore
  178         next if $package eq 'DB';    # special debugging package, ignore
  179         next if grep /^_/, split( /::/, $package ); # private package, ignore
  180   
  181         my $version = $pm_info->version( $package );
  182   
  183         if ( $package eq $prime_package ) {
  184           if ( exists( $prime{$package} ) ) {
  185             # M::B::ModuleInfo will handle this conflict
  186             die "Unexpected conflict in '$package'; multiple versions found.\n";
  187           } else {
  188             $prime{$package}{file} = $mapped_filename;
  189             $prime{$package}{version} = $version if defined( $version );
  190           }
  191         } else {
  192           push( @{$alt{$package}}, {
  193                                     file    => $mapped_filename,
  194                                     version => $version,
  195                                    } );
  196         }
  197       }
  198     }
  199   
  200     # Then we iterate over all the packages found above, identifying conflicts
  201     # and selecting the "best" candidate for recording the file & version
  202     # for each package.
  203     foreach my $package ( keys( %alt ) ) {
  204       my $result = $resolve_module_versions->( $alt{$package} );
  205   
  206       if ( exists( $prime{$package} ) ) { # primary package selected
  207   
  208         if ( $result->{err} ) {
  209     # Use the selected primary package, but there are conflicting
  210     # errors among multiple alternative packages that need to be
  211     # reported
  212           log_info {
  213         "Found conflicting versions for package '$package'\n" .
  214         "  $prime{$package}{file} ($prime{$package}{version})\n" .
  215         $result->{err}
  216           };
  217   
  218         } elsif ( defined( $result->{version} ) ) {
  219     # There is a primary package selected, and exactly one
  220     # alternative package
  221   
  222     if ( exists( $prime{$package}{version} ) &&
  223          defined( $prime{$package}{version} ) ) {
  224       # Unless the version of the primary package agrees with the
  225       # version of the alternative package, report a conflict
  226       if ( $compare_versions->(
  227                  $prime{$package}{version}, '!=', $result->{version}
  228                )
  229              ) {
  230 
  231             log_info {
  232               "Found conflicting versions for package '$package'\n" .
  233           "  $prime{$package}{file} ($prime{$package}{version})\n" .
  234           "  $result->{file} ($result->{version})\n"
  235             };
  236       }
  237   
  238     } else {
  239       # The prime package selected has no version so, we choose to
  240       # use any alternative package that does have a version
  241       $prime{$package}{file}    = $result->{file};
  242       $prime{$package}{version} = $result->{version};
  243     }
  244   
  245         } else {
  246     # no alt package found with a version, but we have a prime
  247     # package so we use it whether it has a version or not
  248         }
  249   
  250       } else { # No primary package was selected, use the best alternative
  251   
  252         if ( $result->{err} ) {
  253           log_info {
  254             "Found conflicting versions for package '$package'\n" .
  255         $result->{err}
  256           };
  257         }
  258   
  259         # Despite possible conflicting versions, we choose to record
  260         # something rather than nothing
  261         $prime{$package}{file}    = $result->{file};
  262         $prime{$package}{version} = $result->{version}
  263       if defined( $result->{version} );
  264       }
  265     }
  266   
  267     # Normalize versions.  Can't use exists() here because of bug in YAML::Node.
  268     # XXX "bug in YAML::Node" comment seems irrelvant -- dagolden, 2009-05-18
  269     for (grep defined $_->{version}, values %prime) {
  270       $_->{version} = $normalize_version->( $_->{version} );
  271     }
  272   
  273     return \%prime;
  274   }
  275 } 
  276   
  277 
  278 sub _init {
  279   my $class    = shift;
  280   my $module   = shift;
  281   my $filename = shift;
  282   my %props = @_;
  283 
  284   my( %valid_props, @valid_props );
  285   @valid_props = qw( collect_pod inc );
  286   @valid_props{@valid_props} = delete( @props{@valid_props} );
  287   warn "Unknown properties: @{[keys %props]}\n" if scalar( %props );
  288 
  289   my %data = (
  290     module       => $module,
  291     filename     => $filename,
  292     version      => undef,
  293     packages     => [],
  294     versions     => {},
  295     pod          => {},
  296     pod_headings => [],
  297     collect_pod  => 0,
  298 
  299     %valid_props,
  300   );
  301 
  302   my $self = bless(\%data, $class);
  303 
  304   $self->_parse_file();
  305 
  306   unless($self->{module} and length($self->{module})) {
  307     my ($v, $d, $f) = File::Spec->splitpath($self->{filename});
  308     if($f =~ /\.pm$/) {
  309       $f =~ s/\..+$//;
  310       my @candidates = grep /$f$/, @{$self->{packages}};
  311       $self->{module} = shift(@candidates); # punt
  312     }
  313     else {
  314       if(grep /main/, @{$self->{packages}}) {
  315         $self->{module} = 'main';
  316       }
  317       else {
  318         $self->{module} = $self->{packages}[0] || '';
  319       }
  320     }
  321   }
  322 
  323   $self->{version} = $self->{versions}{$self->{module}}
  324       if defined( $self->{module} );
  325 
  326   return $self;
  327 }
  328 
  329 # class method
  330 sub _do_find_module {
  331   my $class   = shift;
  332   my $module  = shift || die 'find_module_by_name() requires a package name';
  333   my $dirs    = shift || \@INC;
  334 
  335   my $file = File::Spec->catfile(split( /::/, $module));
  336   foreach my $dir ( @$dirs ) {
  337     my $testfile = File::Spec->catfile($dir, $file);
  338     return [ File::Spec->rel2abs( $testfile ), $dir ]
  339     if -e $testfile and !-d _;  # For stuff like ExtUtils::xsubpp
  340     return [ File::Spec->rel2abs( "$testfile.pm" ), $dir ]
  341     if -e "$testfile.pm";
  342   }
  343   return;
  344 }
  345 
  346 # class method
  347 sub find_module_by_name {
  348   my $found = shift()->_do_find_module(@_) or return;
  349   return $found->[0];
  350 }
  351 
  352 # class method
  353 sub find_module_dir_by_name {
  354   my $found = shift()->_do_find_module(@_) or return;
  355   return $found->[1];
  356 }
  357 
  358 
  359 # given a line of perl code, attempt to parse it if it looks like a
  360 # $VERSION assignment, returning sigil, full name, & package name
  361 sub _parse_version_expression {
  362   my $self = shift;
  363   my $line = shift;
  364 
  365   my( $sig, $var, $pkg );
  366   if ( $line =~ $VERS_REGEXP ) {
  367     ( $sig, $var, $pkg ) = $2 ? ( $1, $2, $3 ) : ( $4, $5, $6 );
  368     if ( $pkg ) {
  369       $pkg = ($pkg eq '::') ? 'main' : $pkg;
  370       $pkg =~ s/::$//;
  371     }
  372   }
  373 
  374   return ( $sig, $var, $pkg );
  375 }
  376 
  377 sub _parse_file {
  378   my $self = shift;
  379 
  380   my $filename = $self->{filename};
  381   open( my $fh, '<', $filename )
  382     or die( "Can't open '$filename': $!" );
  383 
  384   $self->_parse_fh($fh);
  385 }
  386 
  387 sub _parse_fh {
  388   my ($self, $fh) = @_;
  389 
  390   my( $in_pod, $seen_end, $need_vers ) = ( 0, 0, 0 );
  391   my( @pkgs, %vers, %pod, @pod );
  392   my $pkg = 'main';
  393   my $pod_sect = '';
  394   my $pod_data = '';
  395 
  396   while (defined( my $line = <$fh> )) {
  397     my $line_num = $.;
  398 
  399     chomp( $line );
  400     next if $line =~ /^\s*#/;
  401 
  402     $in_pod = ($line =~ /^=(?!cut)/) ? 1 : ($line =~ /^=cut/) ? 0 : $in_pod;
  403 
  404     # Would be nice if we could also check $in_string or something too
  405     last if !$in_pod && $line =~ /^__(?:DATA|END)__$/;
  406 
  407     if ( $in_pod || $line =~ /^=cut/ ) {
  408 
  409       if ( $line =~ /^=head\d\s+(.+)\s*$/ ) {
  410     push( @pod, $1 );
  411     if ( $self->{collect_pod} && length( $pod_data ) ) {
  412           $pod{$pod_sect} = $pod_data;
  413           $pod_data = '';
  414         }
  415     $pod_sect = $1;
  416 
  417 
  418       } elsif ( $self->{collect_pod} ) {
  419     $pod_data .= "$line\n";
  420 
  421       }
  422 
  423     } else {
  424 
  425       $pod_sect = '';
  426       $pod_data = '';
  427 
  428       # parse $line to see if it's a $VERSION declaration
  429       my( $vers_sig, $vers_fullname, $vers_pkg ) =
  430       $self->_parse_version_expression( $line );
  431 
  432       if ( $line =~ $PKG_REGEXP ) {
  433         $pkg = $1;
  434         push( @pkgs, $pkg ) unless grep( $pkg eq $_, @pkgs );
  435         $vers{$pkg} = (defined $2 ? $2 : undef)  unless exists( $vers{$pkg} );
  436         $need_vers = defined $2 ? 0 : 1;
  437 
  438       # VERSION defined with full package spec, i.e. $Module::VERSION
  439       } elsif ( $vers_fullname && $vers_pkg ) {
  440     push( @pkgs, $vers_pkg ) unless grep( $vers_pkg eq $_, @pkgs );
  441     $need_vers = 0 if $vers_pkg eq $pkg;
  442 
  443     unless ( defined $vers{$vers_pkg} && length $vers{$vers_pkg} ) {
  444       $vers{$vers_pkg} =
  445         $self->_evaluate_version_line( $vers_sig, $vers_fullname, $line );
  446     } else {
  447       # Warn unless the user is using the "$VERSION = eval
  448       # $VERSION" idiom (though there are probably other idioms
  449       # that we should watch out for...)
  450       warn <<"EOM" unless $line =~ /=\s*eval/;
  451 Package '$vers_pkg' already declared with version '$vers{$vers_pkg}',
  452 ignoring subsequent declaration on line $line_num.
  453 EOM
  454     }
  455 
  456       # first non-comment line in undeclared package main is VERSION
  457       } elsif ( !exists($vers{main}) && $pkg eq 'main' && $vers_fullname ) {
  458     $need_vers = 0;
  459     my $v =
  460       $self->_evaluate_version_line( $vers_sig, $vers_fullname, $line );
  461     $vers{$pkg} = $v;
  462     push( @pkgs, 'main' );
  463 
  464       # first non-comment line in undeclared package defines package main
  465       } elsif ( !exists($vers{main}) && $pkg eq 'main' && $line =~ /\w+/ ) {
  466     $need_vers = 1;
  467     $vers{main} = '';
  468     push( @pkgs, 'main' );
  469 
  470       # only keep if this is the first $VERSION seen
  471       } elsif ( $vers_fullname && $need_vers ) {
  472     $need_vers = 0;
  473     my $v =
  474       $self->_evaluate_version_line( $vers_sig, $vers_fullname, $line );
  475 
  476 
  477     unless ( defined $vers{$pkg} && length $vers{$pkg} ) {
  478       $vers{$pkg} = $v;
  479     } else {
  480       warn <<"EOM";
  481 Package '$pkg' already declared with version '$vers{$pkg}'
  482 ignoring new version '$v' on line $line_num.
  483 EOM
  484     }
  485 
  486       }
  487 
  488     }
  489 
  490   }
  491 
  492   if ( $self->{collect_pod} && length($pod_data) ) {
  493     $pod{$pod_sect} = $pod_data;
  494   }
  495 
  496   $self->{versions} = \%vers;
  497   $self->{packages} = \@pkgs;
  498   $self->{pod} = \%pod;
  499   $self->{pod_headings} = \@pod;
  500 }
  501 
  502 {
  503 my $pn = 0;
  504 sub _evaluate_version_line {
  505   my $self = shift;
  506   my( $sigil, $var, $line ) = @_;
  507 
  508   # Some of this code came from the ExtUtils:: hierarchy.
  509 
  510   # We compile into $vsub because 'use version' would cause
  511   # compiletime/runtime issues with local()
  512   my $vsub;
  513   $pn++; # everybody gets their own package
  514   my $eval = qq{BEGIN { q#  Hide from _packages_inside()
  515     #; package Module::Metadata::_version::p$pn;
  516     use version;
  517     no strict;
  518 
  519     local $sigil$var;
  520     \$$var=undef;
  521       \$vsub = sub {
  522         $line;
  523         \$$var
  524       };
  525   }};
  526 
  527   local $^W;
  528   # Try to get the $VERSION
  529   eval $eval;
  530   # some modules say $VERSION = $Foo::Bar::VERSION, but Foo::Bar isn't
  531   # installed, so we need to hunt in ./lib for it
  532   if ( $@ =~ /Can't locate/ && -d 'lib' ) {
  533     local @INC = ('lib',@INC);
  534     eval $eval;
  535   }
  536   warn "Error evaling version line '$eval' in $self->{filename}: $@\n"
  537     if $@;
  538   (ref($vsub) eq 'CODE') or
  539     die "failed to build version sub for $self->{filename}";
  540   my $result = eval { $vsub->() };
  541   die "Could not get version from $self->{filename} by executing:\n$eval\n\nThe fatal error was: $@\n"
  542     if $@;
  543 
  544   # Upgrade it into a version object
  545   my $version = eval { _dwim_version($result) };
  546 
  547   die "Version '$result' from $self->{filename} does not appear to be valid:\n$eval\n\nThe fatal error was: $@\n"
  548     unless defined $version; # "0" is OK!
  549 
  550   return $version;
  551 }
  552 }
  553 
  554 # Try to DWIM when things fail the lax version test in obvious ways
  555 {
  556   my @version_prep = (
  557     # Best case, it just works
  558     sub { return shift },
  559 
  560     # If we still don't have a version, try stripping any
  561     # trailing junk that is prohibited by lax rules
  562     sub {
  563       my $v = shift;
  564       $v =~ s{([0-9])[a-z-].*$}{$1}i; # 1.23-alpha or 1.23b
  565       return $v;
  566     },
  567 
  568     # Activestate apparently creates custom versions like '1.23_45_01', which
  569     # cause version.pm to think it's an invalid alpha.  So check for that
  570     # and strip them
  571     sub {
  572       my $v = shift;
  573       my $num_dots = () = $v =~ m{(\.)}g;
  574       my $num_unders = () = $v =~ m{(_)}g;
  575       my $leading_v = substr($v,0,1) eq 'v';
  576       if ( ! $leading_v && $num_dots < 2 && $num_unders > 1 ) {
  577         $v =~ s{_}{}g;
  578         $num_unders = () = $v =~ m{(_)}g;
  579       }
  580       return $v;
  581     },
  582 
  583     # Worst case, try numifying it like we would have before version objects
  584     sub {
  585       my $v = shift;
  586       no warnings 'numeric';
  587       return 0 + $v;
  588     },
  589 
  590   );
  591 
  592   sub _dwim_version {
  593     my ($result) = shift;
  594 
  595     return $result if ref($result) eq 'version';
  596 
  597     my ($version, $error);
  598     for my $f (@version_prep) {
  599       $result = $f->($result);
  600       $version = eval { version->new($result) };
  601       $error ||= $@ if $@; # capture first failure
  602       last if defined $version;
  603     }
  604 
  605     die $error unless defined $version;
  606 
  607     return $version;
  608   }
  609 }
  610 
  611 ############################################################
  612 
  613 # accessors
  614 sub name            { $_[0]->{module}           }
  615 
  616 sub filename        { $_[0]->{filename}         }
  617 sub packages_inside { @{$_[0]->{packages}}      }
  618 sub pod_inside      { @{$_[0]->{pod_headings}}  }
  619 sub contains_pod    { $#{$_[0]->{pod_headings}} }
  620 
  621 sub version {
  622     my $self = shift;
  623     my $mod  = shift || $self->{module};
  624     my $vers;
  625     if ( defined( $mod ) && length( $mod ) &&
  626      exists( $self->{versions}{$mod} ) ) {
  627     return $self->{versions}{$mod};
  628     } else {
  629     return undef;
  630     }
  631 }
  632 
  633 sub pod {
  634     my $self = shift;
  635     my $sect = shift;
  636     if ( defined( $sect ) && length( $sect ) &&
  637      exists( $self->{pod}{$sect} ) ) {
  638     return $self->{pod}{$sect};
  639     } else {
  640     return undef;
  641     }
  642 }
  643 
  644 1;
  645 
  646 =head1 NAME
  647 
  648 Module::Metadata - Gather package and POD information from perl module files
  649 
  650 =head1 DESCRIPTION
  651 
  652 =over 4
  653 
  654 =item new_from_file($filename, collect_pod => 1)
  655 
  656 Construct a C<ModuleInfo> object given the path to a file. Takes an optional
  657 argument C<collect_pod> which is a boolean that determines whether
  658 POD data is collected and stored for reference. POD data is not
  659 collected by default. POD headings are always collected.
  660 
  661 =item new_from_module($module, collect_pod => 1, inc => \@dirs)
  662 
  663 Construct a C<ModuleInfo> object given a module or package name. In addition
  664 to accepting the C<collect_pod> argument as described above, this
  665 method accepts a C<inc> argument which is a reference to an array of
  666 of directories to search for the module. If none are given, the
  667 default is @INC.
  668 
  669 =item name()
  670 
  671 Returns the name of the package represented by this module. If there
  672 are more than one packages, it makes a best guess based on the
  673 filename. If it's a script (i.e. not a *.pm) the package name is
  674 'main'.
  675 
  676 =item version($package)
  677 
  678 Returns the version as defined by the $VERSION variable for the
  679 package as returned by the C<name> method if no arguments are
  680 given. If given the name of a package it will attempt to return the
  681 version of that package if it is specified in the file.
  682 
  683 =item filename()
  684 
  685 Returns the absolute path to the file.
  686 
  687 =item packages_inside()
  688 
  689 Returns a list of packages.
  690 
  691 =item pod_inside()
  692 
  693 Returns a list of POD sections.
  694 
  695 =item contains_pod()
  696 
  697 Returns true if there is any POD in the file.
  698 
  699 =item pod($section)
  700 
  701 Returns the POD data in the given section.
  702 
  703 =item find_module_by_name($module, \@dirs)
  704 
  705 Returns the path to a module given the module or package name. A list
  706 of directories can be passed in as an optional parameter, otherwise
  707 @INC is searched.
  708 
  709 Can be called as either an object or a class method.
  710 
  711 =item find_module_dir_by_name($module, \@dirs)
  712 
  713 Returns the entry in C<@dirs> (or C<@INC> by default) that contains
  714 the module C<$module>. A list of directories can be passed in as an
  715 optional parameter, otherwise @INC is searched.
  716 
  717 Can be called as either an object or a class method.
  718 
  719 =item package_versions_from_directory($dir, \@files?)
  720 
  721 Scans C<$dir> for .pm files (unless C<@files> is given, in which case looks
  722 for those files in C<$dir> - and reads each file for packages and versions,
  723 returning a hashref of the form:
  724 
  725   {
  726     'Package::Name' => {
  727       version => '0.123',
  728       file => 'Package/Name.pm'
  729     },
  730     'OtherPackage::Name' => ...
  731   }
  732 
  733 =item log_info (internal)
  734 
  735 Used internally to perform logging; imported from Log::Contextual if
  736 Log::Contextual has already been loaded, otherwise simply calls warn.
  737 
  738 =back
  739 
  740 =head1 AUTHOR
  741 
  742 Ken Williams <kwilliams@cpan.org>, Randy W. Sims <RandyS@ThePierianSpring.org>
  743 
  744 Released as Module::Metadata by Matt S Trout (mst) <mst@shadowcat.co.uk> with
  745 assistance from David Golden (xdg) <dagolden@cpan.org>
  746 
  747 =head1 COPYRIGHT
  748 
  749 Copyright (c) 2001-2006 Ken Williams.  All rights reserved.
  750 
  751 This library is free software; you can redistribute it and/or
  752 modify it under the same terms as Perl itself.
  753 
  754 =head1 SEE ALSO
  755 
  756 perl(1), L<Module::Build::ModuleInfo>(3)
  757 
  758 =cut
  759