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