xref: /openbsd-src/gnu/usr.bin/perl/cpan/Module-Metadata/lib/Module/Metadata.pm (revision ae3cb403620ab940fbaabb3055fac045a63d56b7)
1# -*- mode: cperl; tab-width: 8; indent-tabs-mode: nil; basic-offset: 2 -*-
2# vim:ts=8:sw=2:et:sta:sts=2
3package Module::Metadata; # git description: v1.000030-2-g52f466c
4# ABSTRACT: Gather package and POD information from perl module files
5
6# Adapted from Perl-licensed code originally distributed with
7# Module-Build by Ken Williams
8
9# This module provides routines to gather information about
10# perl modules (assuming this may be expanded in the distant
11# parrot future to look at other types of modules).
12
13sub __clean_eval { eval $_[0] }
14use strict;
15use warnings;
16
17our $VERSION = '1.000031'; # TRIAL
18
19use Carp qw/croak/;
20use File::Spec;
21BEGIN {
22       # Try really hard to not depend ony any DynaLoaded module, such as IO::File or Fcntl
23       eval {
24               require Fcntl; Fcntl->import('SEEK_SET'); 1;
25       } or *SEEK_SET = sub { 0 }
26}
27use version 0.87;
28BEGIN {
29  if ($INC{'Log/Contextual.pm'}) {
30    require "Log/Contextual/WarnLogger.pm"; # Hide from AutoPrereqs
31    Log::Contextual->import('log_info',
32      '-default_logger' => Log::Contextual::WarnLogger->new({ env_prefix => 'MODULE_METADATA', }),
33    );
34  }
35  else {
36    *log_info = sub (&) { warn $_[0]->() };
37  }
38}
39use File::Find qw(find);
40
41my $V_NUM_REGEXP = qr{v?[0-9._]+};  # crudely, a v-string or decimal
42
43my $PKG_FIRST_WORD_REGEXP = qr{ # the FIRST word in a package name
44  [a-zA-Z_]                     # the first word CANNOT start with a digit
45    (?:
46      [\w']?                    # can contain letters, digits, _, or ticks
47      \w                        # But, NO multi-ticks or trailing ticks
48    )*
49}x;
50
51my $PKG_ADDL_WORD_REGEXP = qr{ # the 2nd+ word in a package name
52  \w                           # the 2nd+ word CAN start with digits
53    (?:
54      [\w']?                   # and can contain letters or ticks
55      \w                       # But, NO multi-ticks or trailing ticks
56    )*
57}x;
58
59my $PKG_NAME_REGEXP = qr{ # match a package name
60  (?: :: )?               # a pkg name can start with arisdottle
61  $PKG_FIRST_WORD_REGEXP  # a package word
62  (?:
63    (?: :: )+             ### arisdottle (allow one or many times)
64    $PKG_ADDL_WORD_REGEXP ### a package word
65  )*                      # ^ zero, one or many times
66  (?:
67    ::                    # allow trailing arisdottle
68  )?
69}x;
70
71my $PKG_REGEXP  = qr{   # match a package declaration
72  ^[\s\{;]*             # intro chars on a line
73  package               # the word 'package'
74  \s+                   # whitespace
75  ($PKG_NAME_REGEXP)    # a package name
76  \s*                   # optional whitespace
77  ($V_NUM_REGEXP)?        # optional version number
78  \s*                   # optional whitesapce
79  [;\{]                 # semicolon line terminator or block start (since 5.16)
80}x;
81
82my $VARNAME_REGEXP = qr{ # match fully-qualified VERSION name
83  ([\$*])         # sigil - $ or *
84  (
85    (             # optional leading package name
86      (?:::|\')?  # possibly starting like just :: (a la $::VERSION)
87      (?:\w+(?:::|\'))*  # Foo::Bar:: ...
88    )?
89    VERSION
90  )\b
91}x;
92
93my $VERS_REGEXP = qr{ # match a VERSION definition
94  (?:
95    \(\s*$VARNAME_REGEXP\s*\) # with parens
96  |
97    $VARNAME_REGEXP           # without parens
98  )
99  \s*
100  =[^=~>]  # = but not ==, nor =~, nor =>
101}x;
102
103sub new_from_file {
104  my $class    = shift;
105  my $filename = File::Spec->rel2abs( shift );
106
107  return undef unless defined( $filename ) && -f $filename;
108  return $class->_init(undef, $filename, @_);
109}
110
111sub new_from_handle {
112  my $class    = shift;
113  my $handle   = shift;
114  my $filename = shift;
115  return undef unless defined($handle) && defined($filename);
116  $filename = File::Spec->rel2abs( $filename );
117
118  return $class->_init(undef, $filename, @_, handle => $handle);
119
120}
121
122
123sub new_from_module {
124  my $class   = shift;
125  my $module  = shift;
126  my %props   = @_;
127
128  $props{inc} ||= \@INC;
129  my $filename = $class->find_module_by_name( $module, $props{inc} );
130  return undef unless defined( $filename ) && -f $filename;
131  return $class->_init($module, $filename, %props);
132}
133
134{
135
136  my $compare_versions = sub {
137    my ($v1, $op, $v2) = @_;
138    $v1 = version->new($v1)
139      unless UNIVERSAL::isa($v1,'version');
140
141    my $eval_str = "\$v1 $op \$v2";
142    my $result   = eval $eval_str;
143    log_info { "error comparing versions: '$eval_str' $@" } if $@;
144
145    return $result;
146  };
147
148  my $normalize_version = sub {
149    my ($version) = @_;
150    if ( $version =~ /[=<>!,]/ ) { # logic, not just version
151      # take as is without modification
152    }
153    elsif ( ref $version eq 'version' ) { # version objects
154      $version = $version->is_qv ? $version->normal : $version->stringify;
155    }
156    elsif ( $version =~ /^[^v][^.]*\.[^.]+\./ ) { # no leading v, multiple dots
157      # normalize string tuples without "v": "1.2.3" -> "v1.2.3"
158      $version = "v$version";
159    }
160    else {
161      # leave alone
162    }
163    return $version;
164  };
165
166  # separate out some of the conflict resolution logic
167
168  my $resolve_module_versions = sub {
169    my $packages = shift;
170
171    my( $file, $version );
172    my $err = '';
173      foreach my $p ( @$packages ) {
174        if ( defined( $p->{version} ) ) {
175          if ( defined( $version ) ) {
176            if ( $compare_versions->( $version, '!=', $p->{version} ) ) {
177              $err .= "  $p->{file} ($p->{version})\n";
178            }
179            else {
180              # same version declared multiple times, ignore
181            }
182          }
183          else {
184            $file    = $p->{file};
185            $version = $p->{version};
186          }
187        }
188      $file ||= $p->{file} if defined( $p->{file} );
189    }
190
191    if ( $err ) {
192      $err = "  $file ($version)\n" . $err;
193    }
194
195    my %result = (
196      file    => $file,
197      version => $version,
198      err     => $err
199    );
200
201    return \%result;
202  };
203
204  sub provides {
205    my $class = shift;
206
207    croak "provides() requires key/value pairs \n" if @_ % 2;
208    my %args = @_;
209
210    croak "provides() takes only one of 'dir' or 'files'\n"
211      if $args{dir} && $args{files};
212
213    croak "provides() requires a 'version' argument"
214      unless defined $args{version};
215
216    croak "provides() does not support version '$args{version}' metadata"
217        unless grep { $args{version} eq $_ } qw/1.4 2/;
218
219    $args{prefix} = 'lib' unless defined $args{prefix};
220
221    my $p;
222    if ( $args{dir} ) {
223      $p = $class->package_versions_from_directory($args{dir});
224    }
225    else {
226      croak "provides() requires 'files' to be an array reference\n"
227        unless ref $args{files} eq 'ARRAY';
228      $p = $class->package_versions_from_directory($args{files});
229    }
230
231    # Now, fix up files with prefix
232    if ( length $args{prefix} ) { # check in case disabled with q{}
233      $args{prefix} =~ s{/$}{};
234      for my $v ( values %$p ) {
235        $v->{file} = "$args{prefix}/$v->{file}";
236      }
237    }
238
239    return $p
240  }
241
242  sub package_versions_from_directory {
243    my ( $class, $dir, $files ) = @_;
244
245    my @files;
246
247    if ( $files ) {
248      @files = @$files;
249    }
250    else {
251      find( {
252        wanted => sub {
253          push @files, $_ if -f $_ && /\.pm$/;
254        },
255        no_chdir => 1,
256      }, $dir );
257    }
258
259    # First, we enumerate all packages & versions,
260    # separating into primary & alternative candidates
261    my( %prime, %alt );
262    foreach my $file (@files) {
263      my $mapped_filename = File::Spec::Unix->abs2rel( $file, $dir );
264      my @path = split( /\//, $mapped_filename );
265      (my $prime_package = join( '::', @path )) =~ s/\.pm$//;
266
267      my $pm_info = $class->new_from_file( $file );
268
269      foreach my $package ( $pm_info->packages_inside ) {
270        next if $package eq 'main';  # main can appear numerous times, ignore
271        next if $package eq 'DB';    # special debugging package, ignore
272        next if grep /^_/, split( /::/, $package ); # private package, ignore
273
274        my $version = $pm_info->version( $package );
275
276        $prime_package = $package if lc($prime_package) eq lc($package);
277        if ( $package eq $prime_package ) {
278          if ( exists( $prime{$package} ) ) {
279            croak "Unexpected conflict in '$package'; multiple versions found.\n";
280          }
281          else {
282            $mapped_filename = "$package.pm" if lc("$package.pm") eq lc($mapped_filename);
283            $prime{$package}{file} = $mapped_filename;
284            $prime{$package}{version} = $version if defined( $version );
285          }
286        }
287        else {
288          push( @{$alt{$package}}, {
289                                    file    => $mapped_filename,
290                                    version => $version,
291                                   } );
292        }
293      }
294    }
295
296    # Then we iterate over all the packages found above, identifying conflicts
297    # and selecting the "best" candidate for recording the file & version
298    # for each package.
299    foreach my $package ( keys( %alt ) ) {
300      my $result = $resolve_module_versions->( $alt{$package} );
301
302      if ( exists( $prime{$package} ) ) { # primary package selected
303
304        if ( $result->{err} ) {
305        # Use the selected primary package, but there are conflicting
306        # errors among multiple alternative packages that need to be
307        # reported
308          log_info {
309            "Found conflicting versions for package '$package'\n" .
310            "  $prime{$package}{file} ($prime{$package}{version})\n" .
311            $result->{err}
312          };
313
314        }
315        elsif ( defined( $result->{version} ) ) {
316        # There is a primary package selected, and exactly one
317        # alternative package
318
319        if ( exists( $prime{$package}{version} ) &&
320             defined( $prime{$package}{version} ) ) {
321          # Unless the version of the primary package agrees with the
322          # version of the alternative package, report a conflict
323        if ( $compare_versions->(
324                 $prime{$package}{version}, '!=', $result->{version}
325               )
326             ) {
327
328            log_info {
329              "Found conflicting versions for package '$package'\n" .
330              "  $prime{$package}{file} ($prime{$package}{version})\n" .
331              "  $result->{file} ($result->{version})\n"
332            };
333          }
334
335        }
336        else {
337          # The prime package selected has no version so, we choose to
338          # use any alternative package that does have a version
339          $prime{$package}{file}    = $result->{file};
340          $prime{$package}{version} = $result->{version};
341        }
342
343        }
344        else {
345        # no alt package found with a version, but we have a prime
346        # package so we use it whether it has a version or not
347        }
348
349      }
350      else { # No primary package was selected, use the best alternative
351
352        if ( $result->{err} ) {
353          log_info {
354            "Found conflicting versions for package '$package'\n" .
355            $result->{err}
356          };
357        }
358
359        # Despite possible conflicting versions, we choose to record
360        # something rather than nothing
361        $prime{$package}{file}    = $result->{file};
362        $prime{$package}{version} = $result->{version}
363          if defined( $result->{version} );
364      }
365    }
366
367    # Normalize versions.  Can't use exists() here because of bug in YAML::Node.
368    # XXX "bug in YAML::Node" comment seems irrelevant -- dagolden, 2009-05-18
369    for (grep defined $_->{version}, values %prime) {
370      $_->{version} = $normalize_version->( $_->{version} );
371    }
372
373    return \%prime;
374  }
375}
376
377
378sub _init {
379  my $class    = shift;
380  my $module   = shift;
381  my $filename = shift;
382  my %props = @_;
383
384  my $handle = delete $props{handle};
385  my( %valid_props, @valid_props );
386  @valid_props = qw( collect_pod inc );
387  @valid_props{@valid_props} = delete( @props{@valid_props} );
388  warn "Unknown properties: @{[keys %props]}\n" if scalar( %props );
389
390  my %data = (
391    module       => $module,
392    filename     => $filename,
393    version      => undef,
394    packages     => [],
395    versions     => {},
396    pod          => {},
397    pod_headings => [],
398    collect_pod  => 0,
399
400    %valid_props,
401  );
402
403  my $self = bless(\%data, $class);
404
405  if ( not $handle ) {
406    my $filename = $self->{filename};
407    open $handle, '<', $filename
408      or croak( "Can't open '$filename': $!" );
409
410    $self->_handle_bom($handle, $filename);
411  }
412  $self->_parse_fh($handle);
413
414  unless($self->{module} and length($self->{module})) {
415    my ($v, $d, $f) = File::Spec->splitpath($self->{filename});
416    if($f =~ /\.pm$/) {
417      $f =~ s/\..+$//;
418      my @candidates = grep /$f$/, @{$self->{packages}};
419      $self->{module} = shift(@candidates); # punt
420    }
421    else {
422      $self->{module} = 'main';
423    }
424  }
425
426  $self->{version} = $self->{versions}{$self->{module}}
427    if defined( $self->{module} );
428
429  return $self;
430}
431
432# class method
433sub _do_find_module {
434  my $class   = shift;
435  my $module  = shift || croak 'find_module_by_name() requires a package name';
436  my $dirs    = shift || \@INC;
437
438  my $file = File::Spec->catfile(split( /::/, $module));
439  foreach my $dir ( @$dirs ) {
440    my $testfile = File::Spec->catfile($dir, $file);
441    return [ File::Spec->rel2abs( $testfile ), $dir ]
442      if -e $testfile and !-d _;  # For stuff like ExtUtils::xsubpp
443    $testfile .= '.pm';
444    return [ File::Spec->rel2abs( $testfile ), $dir ]
445      if -e $testfile;
446  }
447  return;
448}
449
450# class method
451sub find_module_by_name {
452  my $found = shift()->_do_find_module(@_) or return;
453  return $found->[0];
454}
455
456# class method
457sub find_module_dir_by_name {
458  my $found = shift()->_do_find_module(@_) or return;
459  return $found->[1];
460}
461
462
463# given a line of perl code, attempt to parse it if it looks like a
464# $VERSION assignment, returning sigil, full name, & package name
465sub _parse_version_expression {
466  my $self = shift;
467  my $line = shift;
468
469  my( $sigil, $variable_name, $package);
470  if ( $line =~ /$VERS_REGEXP/o ) {
471    ( $sigil, $variable_name, $package) = $2 ? ( $1, $2, $3 ) : ( $4, $5, $6 );
472    if ( $package ) {
473      $package = ($package eq '::') ? 'main' : $package;
474      $package =~ s/::$//;
475    }
476  }
477
478  return ( $sigil, $variable_name, $package );
479}
480
481# Look for a UTF-8/UTF-16BE/UTF-16LE BOM at the beginning of the stream.
482# If there's one, then skip it and set the :encoding layer appropriately.
483sub _handle_bom {
484  my ($self, $fh, $filename) = @_;
485
486  my $pos = tell $fh;
487  return unless defined $pos;
488
489  my $buf = ' ' x 2;
490  my $count = read $fh, $buf, length $buf;
491  return unless defined $count and $count >= 2;
492
493  my $encoding;
494  if ( $buf eq "\x{FE}\x{FF}" ) {
495    $encoding = 'UTF-16BE';
496  }
497  elsif ( $buf eq "\x{FF}\x{FE}" ) {
498    $encoding = 'UTF-16LE';
499  }
500  elsif ( $buf eq "\x{EF}\x{BB}" ) {
501    $buf = ' ';
502    $count = read $fh, $buf, length $buf;
503    if ( defined $count and $count >= 1 and $buf eq "\x{BF}" ) {
504      $encoding = 'UTF-8';
505    }
506  }
507
508  if ( defined $encoding ) {
509    if ( "$]" >= 5.008 ) {
510      binmode( $fh, ":encoding($encoding)" );
511    }
512  }
513  else {
514    seek $fh, $pos, SEEK_SET
515      or croak( sprintf "Can't reset position to the top of '$filename'" );
516  }
517
518  return $encoding;
519}
520
521sub _parse_fh {
522  my ($self, $fh) = @_;
523
524  my( $in_pod, $seen_end, $need_vers ) = ( 0, 0, 0 );
525  my( @packages, %vers, %pod, @pod );
526  my $package = 'main';
527  my $pod_sect = '';
528  my $pod_data = '';
529  my $in_end = 0;
530
531  while (defined( my $line = <$fh> )) {
532    my $line_num = $.;
533
534    chomp( $line );
535
536    # From toke.c : any line that begins by "=X", where X is an alphabetic
537    # character, introduces a POD segment.
538    my $is_cut;
539    if ( $line =~ /^=([a-zA-Z].*)/ ) {
540      my $cmd = $1;
541      # Then it goes back to Perl code for "=cutX" where X is a non-alphabetic
542      # character (which includes the newline, but here we chomped it away).
543      $is_cut = $cmd =~ /^cut(?:[^a-zA-Z]|$)/;
544      $in_pod = !$is_cut;
545    }
546
547    if ( $in_pod ) {
548
549      if ( $line =~ /^=head[1-4]\s+(.+)\s*$/ ) {
550        push( @pod, $1 );
551        if ( $self->{collect_pod} && length( $pod_data ) ) {
552          $pod{$pod_sect} = $pod_data;
553          $pod_data = '';
554        }
555        $pod_sect = $1;
556      }
557      elsif ( $self->{collect_pod} ) {
558        $pod_data .= "$line\n";
559      }
560      next;
561    }
562    elsif ( $is_cut ) {
563      if ( $self->{collect_pod} && length( $pod_data ) ) {
564        $pod{$pod_sect} = $pod_data;
565        $pod_data = '';
566      }
567      $pod_sect = '';
568      next;
569    }
570
571    # Skip after __END__
572    next if $in_end;
573
574    # Skip comments in code
575    next if $line =~ /^\s*#/;
576
577    # Would be nice if we could also check $in_string or something too
578    if ($line eq '__END__') {
579      $in_end++;
580      next;
581    }
582
583    last if $line eq '__DATA__';
584
585    # parse $line to see if it's a $VERSION declaration
586    my( $version_sigil, $version_fullname, $version_package ) =
587      index($line, 'VERSION') >= 1
588        ? $self->_parse_version_expression( $line )
589        : ();
590
591    if ( $line =~ /$PKG_REGEXP/o ) {
592      $package = $1;
593      my $version = $2;
594      push( @packages, $package ) unless grep( $package eq $_, @packages );
595      $need_vers = defined $version ? 0 : 1;
596
597      if ( not exists $vers{$package} and defined $version ){
598        # Upgrade to a version object.
599        my $dwim_version = eval { _dwim_version($version) };
600        croak "Version '$version' from $self->{filename} does not appear to be valid:\n$line\n\nThe fatal error was: $@\n"
601          unless defined $dwim_version;  # "0" is OK!
602        $vers{$package} = $dwim_version;
603      }
604    }
605
606    # VERSION defined with full package spec, i.e. $Module::VERSION
607    elsif ( $version_fullname && $version_package ) {
608      # we do NOT save this package in found @packages
609      $need_vers = 0 if $version_package eq $package;
610
611      unless ( defined $vers{$version_package} && length $vers{$version_package} ) {
612        $vers{$version_package} = $self->_evaluate_version_line( $version_sigil, $version_fullname, $line );
613      }
614    }
615
616    # first non-comment line in undeclared package main is VERSION
617    elsif ( $package eq 'main' && $version_fullname && !exists($vers{main}) ) {
618      $need_vers = 0;
619      my $v = $self->_evaluate_version_line( $version_sigil, $version_fullname, $line );
620      $vers{$package} = $v;
621      push( @packages, 'main' );
622    }
623
624    # first non-comment line in undeclared package defines package main
625    elsif ( $package eq 'main' && !exists($vers{main}) && $line =~ /\w/ ) {
626      $need_vers = 1;
627      $vers{main} = '';
628      push( @packages, 'main' );
629    }
630
631    # only keep if this is the first $VERSION seen
632    elsif ( $version_fullname && $need_vers ) {
633      $need_vers = 0;
634      my $v = $self->_evaluate_version_line( $version_sigil, $version_fullname, $line );
635
636      unless ( defined $vers{$package} && length $vers{$package} ) {
637        $vers{$package} = $v;
638      }
639    }
640  } # end loop over each line
641
642  if ( $self->{collect_pod} && length($pod_data) ) {
643    $pod{$pod_sect} = $pod_data;
644  }
645
646  $self->{versions} = \%vers;
647  $self->{packages} = \@packages;
648  $self->{pod} = \%pod;
649  $self->{pod_headings} = \@pod;
650}
651
652{
653my $pn = 0;
654sub _evaluate_version_line {
655  my $self = shift;
656  my( $sigil, $variable_name, $line ) = @_;
657
658  # We compile into a local sub because 'use version' would cause
659  # compiletime/runtime issues with local()
660  $pn++; # everybody gets their own package
661  my $eval = qq{ my \$dummy = q#  Hide from _packages_inside()
662    #; package Module::Metadata::_version::p${pn};
663    use version;
664    sub {
665      local $sigil$variable_name;
666      $line;
667      return \$$variable_name if defined \$$variable_name;
668      return \$Module::Metadata::_version::p${pn}::$variable_name;
669    };
670  };
671
672  $eval = $1 if $eval =~ m{^(.+)}s;
673
674  local $^W;
675  # Try to get the $VERSION
676  my $vsub = __clean_eval($eval);
677  # some modules say $VERSION <equal sign> $Foo::Bar::VERSION, but Foo::Bar isn't
678  # installed, so we need to hunt in ./lib for it
679  if ( $@ =~ /Can't locate/ && -d 'lib' ) {
680    local @INC = ('lib',@INC);
681    $vsub = __clean_eval($eval);
682  }
683  warn "Error evaling version line '$eval' in $self->{filename}: $@\n"
684    if $@;
685
686  (ref($vsub) eq 'CODE') or
687    croak "failed to build version sub for $self->{filename}";
688
689  my $result = eval { $vsub->() };
690  # FIXME: $eval is not the right thing to print here
691  croak "Could not get version from $self->{filename} by executing:\n$eval\n\nThe fatal error was: $@\n"
692    if $@;
693
694  # Upgrade it into a version object
695  my $version = eval { _dwim_version($result) };
696
697  # FIXME: $eval is not the right thing to print here
698  croak "Version '$result' from $self->{filename} does not appear to be valid:\n$eval\n\nThe fatal error was: $@\n"
699    unless defined $version; # "0" is OK!
700
701  return $version;
702}
703}
704
705# Try to DWIM when things fail the lax version test in obvious ways
706{
707  my @version_prep = (
708    # Best case, it just works
709    sub { return shift },
710
711    # If we still don't have a version, try stripping any
712    # trailing junk that is prohibited by lax rules
713    sub {
714      my $v = shift;
715      $v =~ s{([0-9])[a-z-].*$}{$1}i; # 1.23-alpha or 1.23b
716      return $v;
717    },
718
719    # Activestate apparently creates custom versions like '1.23_45_01', which
720    # cause version.pm to think it's an invalid alpha.  So check for that
721    # and strip them
722    sub {
723      my $v = shift;
724      my $num_dots = () = $v =~ m{(\.)}g;
725      my $num_unders = () = $v =~ m{(_)}g;
726      my $leading_v = substr($v,0,1) eq 'v';
727      if ( ! $leading_v && $num_dots < 2 && $num_unders > 1 ) {
728        $v =~ s{_}{}g;
729        $num_unders = () = $v =~ m{(_)}g;
730      }
731      return $v;
732    },
733
734    # Worst case, try numifying it like we would have before version objects
735    sub {
736      my $v = shift;
737      no warnings 'numeric';
738      return 0 + $v;
739    },
740
741  );
742
743  sub _dwim_version {
744    my ($result) = shift;
745
746    return $result if ref($result) eq 'version';
747
748    my ($version, $error);
749    for my $f (@version_prep) {
750      $result = $f->($result);
751      $version = eval { version->new($result) };
752      $error ||= $@ if $@; # capture first failure
753      last if defined $version;
754    }
755
756    croak $error unless defined $version;
757
758    return $version;
759  }
760}
761
762############################################################
763
764# accessors
765sub name            { $_[0]->{module}            }
766
767sub filename        { $_[0]->{filename}          }
768sub packages_inside { @{$_[0]->{packages}}       }
769sub pod_inside      { @{$_[0]->{pod_headings}}   }
770sub contains_pod    { 0+@{$_[0]->{pod_headings}} }
771
772sub version {
773    my $self = shift;
774    my $mod  = shift || $self->{module};
775    my $vers;
776    if ( defined( $mod ) && length( $mod ) &&
777         exists( $self->{versions}{$mod} ) ) {
778        return $self->{versions}{$mod};
779    }
780    else {
781        return undef;
782    }
783}
784
785sub pod {
786    my $self = shift;
787    my $sect = shift;
788    if ( defined( $sect ) && length( $sect ) &&
789         exists( $self->{pod}{$sect} ) ) {
790        return $self->{pod}{$sect};
791    }
792    else {
793        return undef;
794    }
795}
796
797sub is_indexable {
798  my ($self, $package) = @_;
799
800  my @indexable_packages = grep { $_ ne 'main' } $self->packages_inside;
801
802  # check for specific package, if provided
803  return !! grep { $_ eq $package } @indexable_packages if $package;
804
805  # otherwise, check for any indexable packages at all
806  return !! @indexable_packages;
807}
808
8091;
810
811__END__
812
813=pod
814
815=encoding UTF-8
816
817=head1 NAME
818
819Module::Metadata - Gather package and POD information from perl module files
820
821=head1 VERSION
822
823version 1.000031
824
825=head1 SYNOPSIS
826
827  use Module::Metadata;
828
829  # information about a .pm file
830  my $info = Module::Metadata->new_from_file( $file );
831  my $version = $info->version;
832
833  # CPAN META 'provides' field for .pm files in a directory
834  my $provides = Module::Metadata->provides(
835    dir => 'lib', version => 2
836  );
837
838=head1 DESCRIPTION
839
840This module provides a standard way to gather metadata about a .pm file through
841(mostly) static analysis and (some) code execution.  When determining the
842version of a module, the C<$VERSION> assignment is C<eval>ed, as is traditional
843in the CPAN toolchain.
844
845=head1 CLASS METHODS
846
847=head2 C<< new_from_file($filename, collect_pod => 1) >>
848
849Constructs a C<Module::Metadata> object given the path to a file.  Returns
850undef if the filename does not exist.
851
852C<collect_pod> is a optional boolean argument that determines whether POD
853data is collected and stored for reference.  POD data is not collected by
854default.  POD headings are always collected.
855
856If the file begins by an UTF-8, UTF-16BE or UTF-16LE byte-order mark, then
857it is skipped before processing, and the content of the file is also decoded
858appropriately starting from perl 5.8.
859
860=head2 C<< new_from_handle($handle, $filename, collect_pod => 1) >>
861
862This works just like C<new_from_file>, except that a handle can be provided
863as the first argument.
864
865Note that there is no validation to confirm that the handle is a handle or
866something that can act like one.  Passing something that isn't a handle will
867cause a exception when trying to read from it.  The C<filename> argument is
868mandatory or undef will be returned.
869
870You are responsible for setting the decoding layers on C<$handle> if
871required.
872
873=head2 C<< new_from_module($module, collect_pod => 1, inc => \@dirs) >>
874
875Constructs a C<Module::Metadata> object given a module or package name.
876Returns undef if the module cannot be found.
877
878In addition to accepting the C<collect_pod> argument as described above,
879this method accepts a C<inc> argument which is a reference to an array of
880directories to search for the module.  If none are given, the default is
881@INC.
882
883If the file that contains the module begins by an UTF-8, UTF-16BE or
884UTF-16LE byte-order mark, then it is skipped before processing, and the
885content of the file is also decoded appropriately starting from perl 5.8.
886
887=head2 C<< find_module_by_name($module, \@dirs) >>
888
889Returns the path to a module given the module or package name. A list
890of directories can be passed in as an optional parameter, otherwise
891@INC is searched.
892
893Can be called as either an object or a class method.
894
895=head2 C<< find_module_dir_by_name($module, \@dirs) >>
896
897Returns the entry in C<@dirs> (or C<@INC> by default) that contains
898the module C<$module>. A list of directories can be passed in as an
899optional parameter, otherwise @INC is searched.
900
901Can be called as either an object or a class method.
902
903=head2 C<< provides( %options ) >>
904
905This is a convenience wrapper around C<package_versions_from_directory>
906to generate a CPAN META C<provides> data structure.  It takes key/value
907pairs.  Valid option keys include:
908
909=over
910
911=item version B<(required)>
912
913Specifies which version of the L<CPAN::Meta::Spec> should be used as
914the format of the C<provides> output.  Currently only '1.4' and '2'
915are supported (and their format is identical).  This may change in
916the future as the definition of C<provides> changes.
917
918The C<version> option is required.  If it is omitted or if
919an unsupported version is given, then C<provides> will throw an error.
920
921=item dir
922
923Directory to search recursively for F<.pm> files.  May not be specified with
924C<files>.
925
926=item files
927
928Array reference of files to examine.  May not be specified with C<dir>.
929
930=item prefix
931
932String to prepend to the C<file> field of the resulting output. This defaults
933to F<lib>, which is the common case for most CPAN distributions with their
934F<.pm> files in F<lib>.  This option ensures the META information has the
935correct relative path even when the C<dir> or C<files> arguments are
936absolute or have relative paths from a location other than the distribution
937root.
938
939=back
940
941For example, given C<dir> of 'lib' and C<prefix> of 'lib', the return value
942is a hashref of the form:
943
944  {
945    'Package::Name' => {
946      version => '0.123',
947      file => 'lib/Package/Name.pm'
948    },
949    'OtherPackage::Name' => ...
950  }
951
952=head2 C<< package_versions_from_directory($dir, \@files?) >>
953
954Scans C<$dir> for .pm files (unless C<@files> is given, in which case looks
955for those files in C<$dir> - and reads each file for packages and versions,
956returning a hashref of the form:
957
958  {
959    'Package::Name' => {
960      version => '0.123',
961      file => 'Package/Name.pm'
962    },
963    'OtherPackage::Name' => ...
964  }
965
966The C<DB> and C<main> packages are always omitted, as are any "private"
967packages that have leading underscores in the namespace (e.g.
968C<Foo::_private>)
969
970Note that the file path is relative to C<$dir> if that is specified.
971This B<must not> be used directly for CPAN META C<provides>.  See
972the C<provides> method instead.
973
974=head2 C<< log_info (internal) >>
975
976Used internally to perform logging; imported from Log::Contextual if
977Log::Contextual has already been loaded, otherwise simply calls warn.
978
979=head1 OBJECT METHODS
980
981=head2 C<< name() >>
982
983Returns the name of the package represented by this module. If there
984is more than one package, it makes a best guess based on the
985filename. If it's a script (i.e. not a *.pm) the package name is
986'main'.
987
988=head2 C<< version($package) >>
989
990Returns the version as defined by the $VERSION variable for the
991package as returned by the C<name> method if no arguments are
992given. If given the name of a package it will attempt to return the
993version of that package if it is specified in the file.
994
995=head2 C<< filename() >>
996
997Returns the absolute path to the file.
998Note that this file may not actually exist on disk yet, e.g. if the module was read from an in-memory filehandle.
999
1000=head2 C<< packages_inside() >>
1001
1002Returns a list of packages. Note: this is a raw list of packages
1003discovered (or assumed, in the case of C<main>).  It is not
1004filtered for C<DB>, C<main> or private packages the way the
1005C<provides> method does.  Invalid package names are not returned,
1006for example "Foo:Bar".  Strange but valid package names are
1007returned, for example "Foo::Bar::", and are left up to the caller
1008on how to handle.
1009
1010=head2 C<< pod_inside() >>
1011
1012Returns a list of POD sections.
1013
1014=head2 C<< contains_pod() >>
1015
1016Returns true if there is any POD in the file.
1017
1018=head2 C<< pod($section) >>
1019
1020Returns the POD data in the given section.
1021
1022=head2 C<< is_indexable($package) >> or C<< is_indexable() >>
1023
1024Available since version 1.000020.
1025
1026Returns a boolean indicating whether the package (if provided) or any package
1027(otherwise) is eligible for indexing by PAUSE, the Perl Authors Upload Server.
1028Note This only checks for valid C<package> declarations, and does not take any
1029ownership information into account.
1030
1031=head1 SUPPORT
1032
1033Bugs may be submitted through L<the RT bug tracker|https://rt.cpan.org/Public/Dist/Display.html?Name=Module-Metadata>
1034(or L<bug-Module-Metadata@rt.cpan.org|mailto:bug-Module-Metadata@rt.cpan.org>).
1035
1036There is also a mailing list available for users of this distribution, at
1037L<http://lists.perl.org/list/cpan-workers.html>.
1038
1039There is also an irc channel available for users of this distribution, at
1040L<irc://irc.perl.org/#toolchain>.
1041
1042=head1 AUTHOR
1043
1044Original code from Module::Build::ModuleInfo by Ken Williams
1045<kwilliams@cpan.org>, Randy W. Sims <RandyS@ThePierianSpring.org>
1046
1047Released as Module::Metadata by Matt S Trout (mst) <mst@shadowcat.co.uk> with
1048assistance from David Golden (xdg) <dagolden@cpan.org>.
1049
1050=head1 CONTRIBUTORS
1051
1052=for stopwords Karen Etheridge David Golden Vincent Pit Matt S Trout Chris Nehren Graham Knop Olivier Mengué Tomas Doran Tatsuhiko Miyagawa tokuhirom Peter Rabbitson Steve Hay Josh Jore Craig A. Berry Mitchell Steinbrunner Edward Zborowski Gareth Harper James Raspass Jerry D. Hedden 'BinGOs' Williams Kent Fredric
1053
1054=over 4
1055
1056=item *
1057
1058Karen Etheridge <ether@cpan.org>
1059
1060=item *
1061
1062David Golden <dagolden@cpan.org>
1063
1064=item *
1065
1066Vincent Pit <perl@profvince.com>
1067
1068=item *
1069
1070Matt S Trout <mst@shadowcat.co.uk>
1071
1072=item *
1073
1074Chris Nehren <apeiron@cpan.org>
1075
1076=item *
1077
1078Graham Knop <haarg@haarg.org>
1079
1080=item *
1081
1082Olivier Mengué <dolmen@cpan.org>
1083
1084=item *
1085
1086Tomas Doran <bobtfish@bobtfish.net>
1087
1088=item *
1089
1090Tatsuhiko Miyagawa <miyagawa@bulknews.net>
1091
1092=item *
1093
1094tokuhirom <tokuhirom@gmail.com>
1095
1096=item *
1097
1098Peter Rabbitson <ribasushi@cpan.org>
1099
1100=item *
1101
1102Steve Hay <steve.m.hay@googlemail.com>
1103
1104=item *
1105
1106Josh Jore <jjore@cpan.org>
1107
1108=item *
1109
1110Craig A. Berry <cberry@cpan.org>
1111
1112=item *
1113
1114David Mitchell <davem@iabyn.com>
1115
1116=item *
1117
1118David Steinbrunner <dsteinbrunner@pobox.com>
1119
1120=item *
1121
1122Edward Zborowski <ed@rubensteintech.com>
1123
1124=item *
1125
1126Gareth Harper <gareth@broadbean.com>
1127
1128=item *
1129
1130James Raspass <jraspass@gmail.com>
1131
1132=item *
1133
1134Jerry D. Hedden <jdhedden@cpan.org>
1135
1136=item *
1137
1138Chris 'BinGOs' Williams <chris@bingosnet.co.uk>
1139
1140=item *
1141
1142Kent Fredric <kentnl@cpan.org>
1143
1144=back
1145
1146=head1 COPYRIGHT & LICENSE
1147
1148Original code Copyright (c) 2001-2011 Ken Williams.
1149Additional code Copyright (c) 2010-2011 Matt Trout and David Golden.
1150All rights reserved.
1151
1152This library is free software; you can redistribute it and/or
1153modify it under the same terms as Perl itself.
1154
1155=cut
1156