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