xref: /openbsd-src/gnu/usr.bin/perl/cpan/Module-Metadata/lib/Module/Metadata.pm (revision 505ee9ea3b177e2387d907a91ca7da069f3f14d8)
1# -*- mode: cperl; tab-width: 8; indent-tabs-mode: nil; basic-offset: 2 -*-
2# vim:ts=8:sw=2:et:sta:sts=2:tw=78
3package Module::Metadata; # git description: v1.000035-3-gaa51be1
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.000036';
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->abs2rel( $file, $dir );
264      my @path = File::Spec->splitdir( $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  @{$self->{packages}} = __uniq(@{$self->{packages}});
415
416  unless($self->{module} and length($self->{module})) {
417    # CAVEAT (possible TODO): .pmc files not treated the same as .pm
418    if ($self->{filename} =~ /\.pm$/) {
419      my ($v, $d, $f) = File::Spec->splitpath($self->{filename});
420      $f =~ s/\..+$//;
421      my @candidates = grep /(^|::)$f$/, @{$self->{packages}};
422      $self->{module} = shift(@candidates); # this may be undef
423    }
424    else {
425      # this seems like an atrocious heuristic, albeit marginally better than
426      # what was here before. It should be rewritten entirely to be more like
427      # "if it's not a .pm file, it's not require()able as a name, therefore
428      # name() should be undef."
429      if ((grep /main/, @{$self->{packages}})
430          or (grep /main/, keys %{$self->{versions}})) {
431        $self->{module} = 'main';
432      }
433      else {
434        # TODO: this should maybe default to undef instead
435        $self->{module} = $self->{packages}[0] || '';
436      }
437    }
438  }
439
440  $self->{version} = $self->{versions}{$self->{module}}
441    if defined( $self->{module} );
442
443  return $self;
444}
445
446# class method
447sub _do_find_module {
448  my $class   = shift;
449  my $module  = shift || croak 'find_module_by_name() requires a package name';
450  my $dirs    = shift || \@INC;
451
452  my $file = File::Spec->catfile(split( /::/, $module));
453  foreach my $dir ( @$dirs ) {
454    my $testfile = File::Spec->catfile($dir, $file);
455    return [ File::Spec->rel2abs( $testfile ), $dir ]
456      if -e $testfile and !-d _;  # For stuff like ExtUtils::xsubpp
457    # CAVEAT (possible TODO): .pmc files are not discoverable here
458    $testfile .= '.pm';
459    return [ File::Spec->rel2abs( $testfile ), $dir ]
460      if -e $testfile;
461  }
462  return;
463}
464
465# class method
466sub find_module_by_name {
467  my $found = shift()->_do_find_module(@_) or return;
468  return $found->[0];
469}
470
471# class method
472sub find_module_dir_by_name {
473  my $found = shift()->_do_find_module(@_) or return;
474  return $found->[1];
475}
476
477
478# given a line of perl code, attempt to parse it if it looks like a
479# $VERSION assignment, returning sigil, full name, & package name
480sub _parse_version_expression {
481  my $self = shift;
482  my $line = shift;
483
484  my( $sigil, $variable_name, $package);
485  if ( $line =~ /$VERS_REGEXP/o ) {
486    ( $sigil, $variable_name, $package) = $2 ? ( $1, $2, $3 ) : ( $4, $5, $6 );
487    if ( $package ) {
488      $package = ($package eq '::') ? 'main' : $package;
489      $package =~ s/::$//;
490    }
491  }
492
493  return ( $sigil, $variable_name, $package );
494}
495
496# Look for a UTF-8/UTF-16BE/UTF-16LE BOM at the beginning of the stream.
497# If there's one, then skip it and set the :encoding layer appropriately.
498sub _handle_bom {
499  my ($self, $fh, $filename) = @_;
500
501  my $pos = tell $fh;
502  return unless defined $pos;
503
504  my $buf = ' ' x 2;
505  my $count = read $fh, $buf, length $buf;
506  return unless defined $count and $count >= 2;
507
508  my $encoding;
509  if ( $buf eq "\x{FE}\x{FF}" ) {
510    $encoding = 'UTF-16BE';
511  }
512  elsif ( $buf eq "\x{FF}\x{FE}" ) {
513    $encoding = 'UTF-16LE';
514  }
515  elsif ( $buf eq "\x{EF}\x{BB}" ) {
516    $buf = ' ';
517    $count = read $fh, $buf, length $buf;
518    if ( defined $count and $count >= 1 and $buf eq "\x{BF}" ) {
519      $encoding = 'UTF-8';
520    }
521  }
522
523  if ( defined $encoding ) {
524    if ( "$]" >= 5.008 ) {
525      binmode( $fh, ":encoding($encoding)" );
526    }
527  }
528  else {
529    seek $fh, $pos, SEEK_SET
530      or croak( sprintf "Can't reset position to the top of '$filename'" );
531  }
532
533  return $encoding;
534}
535
536sub _parse_fh {
537  my ($self, $fh) = @_;
538
539  my( $in_pod, $seen_end, $need_vers ) = ( 0, 0, 0 );
540  my( @packages, %vers, %pod, @pod );
541  my $package = 'main';
542  my $pod_sect = '';
543  my $pod_data = '';
544  my $in_end = 0;
545
546  while (defined( my $line = <$fh> )) {
547    my $line_num = $.;
548
549    chomp( $line );
550
551    # From toke.c : any line that begins by "=X", where X is an alphabetic
552    # character, introduces a POD segment.
553    my $is_cut;
554    if ( $line =~ /^=([a-zA-Z].*)/ ) {
555      my $cmd = $1;
556      # Then it goes back to Perl code for "=cutX" where X is a non-alphabetic
557      # character (which includes the newline, but here we chomped it away).
558      $is_cut = $cmd =~ /^cut(?:[^a-zA-Z]|$)/;
559      $in_pod = !$is_cut;
560    }
561
562    if ( $in_pod ) {
563
564      if ( $line =~ /^=head[1-4]\s+(.+)\s*$/ ) {
565        push( @pod, $1 );
566        if ( $self->{collect_pod} && length( $pod_data ) ) {
567          $pod{$pod_sect} = $pod_data;
568          $pod_data = '';
569        }
570        $pod_sect = $1;
571      }
572      elsif ( $self->{collect_pod} ) {
573        $pod_data .= "$line\n";
574      }
575      next;
576    }
577    elsif ( $is_cut ) {
578      if ( $self->{collect_pod} && length( $pod_data ) ) {
579        $pod{$pod_sect} = $pod_data;
580        $pod_data = '';
581      }
582      $pod_sect = '';
583      next;
584    }
585
586    # Skip after __END__
587    next if $in_end;
588
589    # Skip comments in code
590    next if $line =~ /^\s*#/;
591
592    # Would be nice if we could also check $in_string or something too
593    if ($line eq '__END__') {
594      $in_end++;
595      next;
596    }
597
598    last if $line eq '__DATA__';
599
600    # parse $line to see if it's a $VERSION declaration
601    my( $version_sigil, $version_fullname, $version_package ) =
602      index($line, 'VERSION') >= 1
603        ? $self->_parse_version_expression( $line )
604        : ();
605
606    if ( $line =~ /$PKG_REGEXP/o ) {
607      $package = $1;
608      my $version = $2;
609      push( @packages, $package ) unless grep( $package eq $_, @packages );
610      $need_vers = defined $version ? 0 : 1;
611
612      if ( not exists $vers{$package} and defined $version ){
613        # Upgrade to a version object.
614        my $dwim_version = eval { _dwim_version($version) };
615        croak "Version '$version' from $self->{filename} does not appear to be valid:\n$line\n\nThe fatal error was: $@\n"
616          unless defined $dwim_version;  # "0" is OK!
617        $vers{$package} = $dwim_version;
618      }
619    }
620
621    # VERSION defined with full package spec, i.e. $Module::VERSION
622    elsif ( $version_fullname && $version_package ) {
623      # we do NOT save this package in found @packages
624      $need_vers = 0 if $version_package eq $package;
625
626      unless ( defined $vers{$version_package} && length $vers{$version_package} ) {
627        $vers{$version_package} = $self->_evaluate_version_line( $version_sigil, $version_fullname, $line );
628      }
629    }
630
631    # first non-comment line in undeclared package main is VERSION
632    elsif ( $package eq 'main' && $version_fullname && !exists($vers{main}) ) {
633      $need_vers = 0;
634      my $v = $self->_evaluate_version_line( $version_sigil, $version_fullname, $line );
635      $vers{$package} = $v;
636      push( @packages, 'main' );
637    }
638
639    # first non-comment line in undeclared package defines package main
640    elsif ( $package eq 'main' && !exists($vers{main}) && $line =~ /\w/ ) {
641      $need_vers = 1;
642      $vers{main} = '';
643      push( @packages, 'main' );
644    }
645
646    # only keep if this is the first $VERSION seen
647    elsif ( $version_fullname && $need_vers ) {
648      $need_vers = 0;
649      my $v = $self->_evaluate_version_line( $version_sigil, $version_fullname, $line );
650
651      unless ( defined $vers{$package} && length $vers{$package} ) {
652        $vers{$package} = $v;
653      }
654    }
655  } # end loop over each line
656
657  if ( $self->{collect_pod} && length($pod_data) ) {
658    $pod{$pod_sect} = $pod_data;
659  }
660
661  $self->{versions} = \%vers;
662  $self->{packages} = \@packages;
663  $self->{pod} = \%pod;
664  $self->{pod_headings} = \@pod;
665}
666
667sub __uniq (@)
668{
669    my (%seen, $key);
670    grep !$seen{ $key = $_ }++, @_;
671}
672
673{
674my $pn = 0;
675sub _evaluate_version_line {
676  my $self = shift;
677  my( $sigil, $variable_name, $line ) = @_;
678
679  # We compile into a local sub because 'use version' would cause
680  # compiletime/runtime issues with local()
681  $pn++; # everybody gets their own package
682  my $eval = qq{ my \$dummy = q#  Hide from _packages_inside()
683    #; package Module::Metadata::_version::p${pn};
684    use version;
685    sub {
686      local $sigil$variable_name;
687      $line;
688      return \$$variable_name if defined \$$variable_name;
689      return \$Module::Metadata::_version::p${pn}::$variable_name;
690    };
691  };
692
693  $eval = $1 if $eval =~ m{^(.+)}s;
694
695  local $^W;
696  # Try to get the $VERSION
697  my $vsub = __clean_eval($eval);
698  # some modules say $VERSION <equal sign> $Foo::Bar::VERSION, but Foo::Bar isn't
699  # installed, so we need to hunt in ./lib for it
700  if ( $@ =~ /Can't locate/ && -d 'lib' ) {
701    local @INC = ('lib',@INC);
702    $vsub = __clean_eval($eval);
703  }
704  warn "Error evaling version line '$eval' in $self->{filename}: $@\n"
705    if $@;
706
707  (ref($vsub) eq 'CODE') or
708    croak "failed to build version sub for $self->{filename}";
709
710  my $result = eval { $vsub->() };
711  # FIXME: $eval is not the right thing to print here
712  croak "Could not get version from $self->{filename} by executing:\n$eval\n\nThe fatal error was: $@\n"
713    if $@;
714
715  # Upgrade it into a version object
716  my $version = eval { _dwim_version($result) };
717
718  # FIXME: $eval is not the right thing to print here
719  croak "Version '$result' from $self->{filename} does not appear to be valid:\n$eval\n\nThe fatal error was: $@\n"
720    unless defined $version; # "0" is OK!
721
722  return $version;
723}
724}
725
726# Try to DWIM when things fail the lax version test in obvious ways
727{
728  my @version_prep = (
729    # Best case, it just works
730    sub { return shift },
731
732    # If we still don't have a version, try stripping any
733    # trailing junk that is prohibited by lax rules
734    sub {
735      my $v = shift;
736      $v =~ s{([0-9])[a-z-].*$}{$1}i; # 1.23-alpha or 1.23b
737      return $v;
738    },
739
740    # Activestate apparently creates custom versions like '1.23_45_01', which
741    # cause version.pm to think it's an invalid alpha.  So check for that
742    # and strip them
743    sub {
744      my $v = shift;
745      my $num_dots = () = $v =~ m{(\.)}g;
746      my $num_unders = () = $v =~ m{(_)}g;
747      my $leading_v = substr($v,0,1) eq 'v';
748      if ( ! $leading_v && $num_dots < 2 && $num_unders > 1 ) {
749        $v =~ s{_}{}g;
750        $num_unders = () = $v =~ m{(_)}g;
751      }
752      return $v;
753    },
754
755    # Worst case, try numifying it like we would have before version objects
756    sub {
757      my $v = shift;
758      no warnings 'numeric';
759      return 0 + $v;
760    },
761
762  );
763
764  sub _dwim_version {
765    my ($result) = shift;
766
767    return $result if ref($result) eq 'version';
768
769    my ($version, $error);
770    for my $f (@version_prep) {
771      $result = $f->($result);
772      $version = eval { version->new($result) };
773      $error ||= $@ if $@; # capture first failure
774      last if defined $version;
775    }
776
777    croak $error unless defined $version;
778
779    return $version;
780  }
781}
782
783############################################################
784
785# accessors
786sub name            { $_[0]->{module}            }
787
788sub filename        { $_[0]->{filename}          }
789sub packages_inside { @{$_[0]->{packages}}       }
790sub pod_inside      { @{$_[0]->{pod_headings}}   }
791sub contains_pod    { 0+@{$_[0]->{pod_headings}} }
792
793sub version {
794    my $self = shift;
795    my $mod  = shift || $self->{module};
796    my $vers;
797    if ( defined( $mod ) && length( $mod ) &&
798         exists( $self->{versions}{$mod} ) ) {
799        return $self->{versions}{$mod};
800    }
801    else {
802        return undef;
803    }
804}
805
806sub pod {
807    my $self = shift;
808    my $sect = shift;
809    if ( defined( $sect ) && length( $sect ) &&
810         exists( $self->{pod}{$sect} ) ) {
811        return $self->{pod}{$sect};
812    }
813    else {
814        return undef;
815    }
816}
817
818sub is_indexable {
819  my ($self, $package) = @_;
820
821  my @indexable_packages = grep $_ ne 'main', $self->packages_inside;
822
823  # check for specific package, if provided
824  return !! grep $_ eq $package, @indexable_packages if $package;
825
826  # otherwise, check for any indexable packages at all
827  return !! @indexable_packages;
828}
829
8301;
831
832__END__
833
834=pod
835
836=encoding UTF-8
837
838=head1 NAME
839
840Module::Metadata - Gather package and POD information from perl module files
841
842=head1 VERSION
843
844version 1.000036
845
846=head1 SYNOPSIS
847
848  use Module::Metadata;
849
850  # information about a .pm file
851  my $info = Module::Metadata->new_from_file( $file );
852  my $version = $info->version;
853
854  # CPAN META 'provides' field for .pm files in a directory
855  my $provides = Module::Metadata->provides(
856    dir => 'lib', version => 2
857  );
858
859=head1 DESCRIPTION
860
861This module provides a standard way to gather metadata about a .pm file through
862(mostly) static analysis and (some) code execution.  When determining the
863version of a module, the C<$VERSION> assignment is C<eval>ed, as is traditional
864in the CPAN toolchain.
865
866=head1 CLASS METHODS
867
868=head2 C<< new_from_file($filename, collect_pod => 1) >>
869
870Constructs a C<Module::Metadata> object given the path to a file.  Returns
871undef if the filename does not exist.
872
873C<collect_pod> is a optional boolean argument that determines whether POD
874data is collected and stored for reference.  POD data is not collected by
875default.  POD headings are always collected.
876
877If the file begins by an UTF-8, UTF-16BE or UTF-16LE byte-order mark, then
878it is skipped before processing, and the content of the file is also decoded
879appropriately starting from perl 5.8.
880
881=head2 C<< new_from_handle($handle, $filename, collect_pod => 1) >>
882
883This works just like C<new_from_file>, except that a handle can be provided
884as the first argument.
885
886Note that there is no validation to confirm that the handle is a handle or
887something that can act like one.  Passing something that isn't a handle will
888cause a exception when trying to read from it.  The C<filename> argument is
889mandatory or undef will be returned.
890
891You are responsible for setting the decoding layers on C<$handle> if
892required.
893
894=head2 C<< new_from_module($module, collect_pod => 1, inc => \@dirs) >>
895
896Constructs a C<Module::Metadata> object given a module or package name.
897Returns undef if the module cannot be found.
898
899In addition to accepting the C<collect_pod> argument as described above,
900this method accepts a C<inc> argument which is a reference to an array of
901directories to search for the module.  If none are given, the default is
902@INC.
903
904If the file that contains the module begins by an UTF-8, UTF-16BE or
905UTF-16LE byte-order mark, then it is skipped before processing, and the
906content of the file is also decoded appropriately starting from perl 5.8.
907
908=head2 C<< find_module_by_name($module, \@dirs) >>
909
910Returns the path to a module given the module or package name. A list
911of directories can be passed in as an optional parameter, otherwise
912@INC is searched.
913
914Can be called as either an object or a class method.
915
916=head2 C<< find_module_dir_by_name($module, \@dirs) >>
917
918Returns the entry in C<@dirs> (or C<@INC> by default) that contains
919the module C<$module>. A list of directories can be passed in as an
920optional parameter, otherwise @INC is searched.
921
922Can be called as either an object or a class method.
923
924=head2 C<< provides( %options ) >>
925
926This is a convenience wrapper around C<package_versions_from_directory>
927to generate a CPAN META C<provides> data structure.  It takes key/value
928pairs.  Valid option keys include:
929
930=over
931
932=item version B<(required)>
933
934Specifies which version of the L<CPAN::Meta::Spec> should be used as
935the format of the C<provides> output.  Currently only '1.4' and '2'
936are supported (and their format is identical).  This may change in
937the future as the definition of C<provides> changes.
938
939The C<version> option is required.  If it is omitted or if
940an unsupported version is given, then C<provides> will throw an error.
941
942=item dir
943
944Directory to search recursively for F<.pm> files.  May not be specified with
945C<files>.
946
947=item files
948
949Array reference of files to examine.  May not be specified with C<dir>.
950
951=item prefix
952
953String to prepend to the C<file> field of the resulting output. This defaults
954to F<lib>, which is the common case for most CPAN distributions with their
955F<.pm> files in F<lib>.  This option ensures the META information has the
956correct relative path even when the C<dir> or C<files> arguments are
957absolute or have relative paths from a location other than the distribution
958root.
959
960=back
961
962For example, given C<dir> of 'lib' and C<prefix> of 'lib', the return value
963is a hashref of the form:
964
965  {
966    'Package::Name' => {
967      version => '0.123',
968      file => 'lib/Package/Name.pm'
969    },
970    'OtherPackage::Name' => ...
971  }
972
973=head2 C<< package_versions_from_directory($dir, \@files?) >>
974
975Scans C<$dir> for .pm files (unless C<@files> is given, in which case looks
976for those files in C<$dir> - and reads each file for packages and versions,
977returning a hashref of the form:
978
979  {
980    'Package::Name' => {
981      version => '0.123',
982      file => 'Package/Name.pm'
983    },
984    'OtherPackage::Name' => ...
985  }
986
987The C<DB> and C<main> packages are always omitted, as are any "private"
988packages that have leading underscores in the namespace (e.g.
989C<Foo::_private>)
990
991Note that the file path is relative to C<$dir> if that is specified.
992This B<must not> be used directly for CPAN META C<provides>.  See
993the C<provides> method instead.
994
995=head2 C<< log_info (internal) >>
996
997Used internally to perform logging; imported from Log::Contextual if
998Log::Contextual has already been loaded, otherwise simply calls warn.
999
1000=head1 OBJECT METHODS
1001
1002=head2 C<< name() >>
1003
1004Returns the name of the package represented by this module. If there
1005is more than one package, it makes a best guess based on the
1006filename. If it's a script (i.e. not a *.pm) the package name is
1007'main'.
1008
1009=head2 C<< version($package) >>
1010
1011Returns the version as defined by the $VERSION variable for the
1012package as returned by the C<name> method if no arguments are
1013given. If given the name of a package it will attempt to return the
1014version of that package if it is specified in the file.
1015
1016=head2 C<< filename() >>
1017
1018Returns the absolute path to the file.
1019Note that this file may not actually exist on disk yet, e.g. if the module was read from an in-memory filehandle.
1020
1021=head2 C<< packages_inside() >>
1022
1023Returns a list of packages. Note: this is a raw list of packages
1024discovered (or assumed, in the case of C<main>).  It is not
1025filtered for C<DB>, C<main> or private packages the way the
1026C<provides> method does.  Invalid package names are not returned,
1027for example "Foo:Bar".  Strange but valid package names are
1028returned, for example "Foo::Bar::", and are left up to the caller
1029on how to handle.
1030
1031=head2 C<< pod_inside() >>
1032
1033Returns a list of POD sections.
1034
1035=head2 C<< contains_pod() >>
1036
1037Returns true if there is any POD in the file.
1038
1039=head2 C<< pod($section) >>
1040
1041Returns the POD data in the given section.
1042
1043=head2 C<< is_indexable($package) >> or C<< is_indexable() >>
1044
1045Available since version 1.000020.
1046
1047Returns a boolean indicating whether the package (if provided) or any package
1048(otherwise) is eligible for indexing by PAUSE, the Perl Authors Upload Server.
1049Note This only checks for valid C<package> declarations, and does not take any
1050ownership information into account.
1051
1052=head1 SUPPORT
1053
1054Bugs may be submitted through L<the RT bug tracker|https://rt.cpan.org/Public/Dist/Display.html?Name=Module-Metadata>
1055(or L<bug-Module-Metadata@rt.cpan.org|mailto:bug-Module-Metadata@rt.cpan.org>).
1056
1057There is also a mailing list available for users of this distribution, at
1058L<http://lists.perl.org/list/cpan-workers.html>.
1059
1060There is also an irc channel available for users of this distribution, at
1061L<C<#toolchain> on C<irc.perl.org>|irc://irc.perl.org/#toolchain>.
1062
1063=head1 AUTHOR
1064
1065Original code from Module::Build::ModuleInfo by Ken Williams
1066<kwilliams@cpan.org>, Randy W. Sims <RandyS@ThePierianSpring.org>
1067
1068Released as Module::Metadata by Matt S Trout (mst) <mst@shadowcat.co.uk> with
1069assistance from David Golden (xdg) <dagolden@cpan.org>.
1070
1071=head1 CONTRIBUTORS
1072
1073=for stopwords Karen Etheridge David Golden Vincent Pit Matt S Trout Chris Nehren Graham Knop Olivier Mengué Tomas Doran tokuhirom Christian Walde Tatsuhiko Miyagawa Peter Rabbitson Steve Hay Jerry D. Hedden Craig A. Berry Mitchell Steinbrunner Edward Zborowski Gareth Harper James Raspass 'BinGOs' Williams Josh Jore Kent Fredric
1074
1075=over 4
1076
1077=item *
1078
1079Karen Etheridge <ether@cpan.org>
1080
1081=item *
1082
1083David Golden <dagolden@cpan.org>
1084
1085=item *
1086
1087Vincent Pit <perl@profvince.com>
1088
1089=item *
1090
1091Matt S Trout <mst@shadowcat.co.uk>
1092
1093=item *
1094
1095Chris Nehren <apeiron@cpan.org>
1096
1097=item *
1098
1099Graham Knop <haarg@haarg.org>
1100
1101=item *
1102
1103Olivier Mengué <dolmen@cpan.org>
1104
1105=item *
1106
1107Tomas Doran <bobtfish@bobtfish.net>
1108
1109=item *
1110
1111tokuhirom <tokuhirom@gmail.com>
1112
1113=item *
1114
1115Christian Walde <walde.christian@googlemail.com>
1116
1117=item *
1118
1119Tatsuhiko Miyagawa <miyagawa@bulknews.net>
1120
1121=item *
1122
1123Peter Rabbitson <ribasushi@cpan.org>
1124
1125=item *
1126
1127Steve Hay <steve.m.hay@googlemail.com>
1128
1129=item *
1130
1131Jerry D. Hedden <jdhedden@cpan.org>
1132
1133=item *
1134
1135Craig A. Berry <cberry@cpan.org>
1136
1137=item *
1138
1139Craig A. Berry <craigberry@mac.com>
1140
1141=item *
1142
1143David Mitchell <davem@iabyn.com>
1144
1145=item *
1146
1147David Steinbrunner <dsteinbrunner@pobox.com>
1148
1149=item *
1150
1151Edward Zborowski <ed@rubensteintech.com>
1152
1153=item *
1154
1155Gareth Harper <gareth@broadbean.com>
1156
1157=item *
1158
1159James Raspass <jraspass@gmail.com>
1160
1161=item *
1162
1163Chris 'BinGOs' Williams <chris@bingosnet.co.uk>
1164
1165=item *
1166
1167Josh Jore <jjore@cpan.org>
1168
1169=item *
1170
1171Kent Fredric <kentnl@cpan.org>
1172
1173=back
1174
1175=head1 COPYRIGHT & LICENSE
1176
1177Original code Copyright (c) 2001-2011 Ken Williams.
1178Additional code Copyright (c) 2010-2011 Matt Trout and David Golden.
1179All rights reserved.
1180
1181This library is free software; you can redistribute it and/or
1182modify it under the same terms as Perl itself.
1183
1184=cut
1185