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