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