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