1# -*- mode: cperl; tab-width: 8; indent-tabs-mode: nil; basic-offset: 2 -*- 2# vim:ts=8:sw=2:et:sta:sts=2:tw=78 3package Module::Metadata; # git description: v1.000035-3-gaa51be1 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.000036'; 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->abs2rel( $file, $dir ); 264 my @path = File::Spec->splitdir( $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 @{$self->{packages}} = __uniq(@{$self->{packages}}); 415 416 unless($self->{module} and length($self->{module})) { 417 # CAVEAT (possible TODO): .pmc files not treated the same as .pm 418 if ($self->{filename} =~ /\.pm$/) { 419 my ($v, $d, $f) = File::Spec->splitpath($self->{filename}); 420 $f =~ s/\..+$//; 421 my @candidates = grep /(^|::)$f$/, @{$self->{packages}}; 422 $self->{module} = shift(@candidates); # this may be undef 423 } 424 else { 425 # this seems like an atrocious heuristic, albeit marginally better than 426 # what was here before. It should be rewritten entirely to be more like 427 # "if it's not a .pm file, it's not require()able as a name, therefore 428 # name() should be undef." 429 if ((grep /main/, @{$self->{packages}}) 430 or (grep /main/, keys %{$self->{versions}})) { 431 $self->{module} = 'main'; 432 } 433 else { 434 # TODO: this should maybe default to undef instead 435 $self->{module} = $self->{packages}[0] || ''; 436 } 437 } 438 } 439 440 $self->{version} = $self->{versions}{$self->{module}} 441 if defined( $self->{module} ); 442 443 return $self; 444} 445 446# class method 447sub _do_find_module { 448 my $class = shift; 449 my $module = shift || croak 'find_module_by_name() requires a package name'; 450 my $dirs = shift || \@INC; 451 452 my $file = File::Spec->catfile(split( /::/, $module)); 453 foreach my $dir ( @$dirs ) { 454 my $testfile = File::Spec->catfile($dir, $file); 455 return [ File::Spec->rel2abs( $testfile ), $dir ] 456 if -e $testfile and !-d _; # For stuff like ExtUtils::xsubpp 457 # CAVEAT (possible TODO): .pmc files are not discoverable here 458 $testfile .= '.pm'; 459 return [ File::Spec->rel2abs( $testfile ), $dir ] 460 if -e $testfile; 461 } 462 return; 463} 464 465# class method 466sub find_module_by_name { 467 my $found = shift()->_do_find_module(@_) or return; 468 return $found->[0]; 469} 470 471# class method 472sub find_module_dir_by_name { 473 my $found = shift()->_do_find_module(@_) or return; 474 return $found->[1]; 475} 476 477 478# given a line of perl code, attempt to parse it if it looks like a 479# $VERSION assignment, returning sigil, full name, & package name 480sub _parse_version_expression { 481 my $self = shift; 482 my $line = shift; 483 484 my( $sigil, $variable_name, $package); 485 if ( $line =~ /$VERS_REGEXP/o ) { 486 ( $sigil, $variable_name, $package) = $2 ? ( $1, $2, $3 ) : ( $4, $5, $6 ); 487 if ( $package ) { 488 $package = ($package eq '::') ? 'main' : $package; 489 $package =~ s/::$//; 490 } 491 } 492 493 return ( $sigil, $variable_name, $package ); 494} 495 496# Look for a UTF-8/UTF-16BE/UTF-16LE BOM at the beginning of the stream. 497# If there's one, then skip it and set the :encoding layer appropriately. 498sub _handle_bom { 499 my ($self, $fh, $filename) = @_; 500 501 my $pos = tell $fh; 502 return unless defined $pos; 503 504 my $buf = ' ' x 2; 505 my $count = read $fh, $buf, length $buf; 506 return unless defined $count and $count >= 2; 507 508 my $encoding; 509 if ( $buf eq "\x{FE}\x{FF}" ) { 510 $encoding = 'UTF-16BE'; 511 } 512 elsif ( $buf eq "\x{FF}\x{FE}" ) { 513 $encoding = 'UTF-16LE'; 514 } 515 elsif ( $buf eq "\x{EF}\x{BB}" ) { 516 $buf = ' '; 517 $count = read $fh, $buf, length $buf; 518 if ( defined $count and $count >= 1 and $buf eq "\x{BF}" ) { 519 $encoding = 'UTF-8'; 520 } 521 } 522 523 if ( defined $encoding ) { 524 if ( "$]" >= 5.008 ) { 525 binmode( $fh, ":encoding($encoding)" ); 526 } 527 } 528 else { 529 seek $fh, $pos, SEEK_SET 530 or croak( sprintf "Can't reset position to the top of '$filename'" ); 531 } 532 533 return $encoding; 534} 535 536sub _parse_fh { 537 my ($self, $fh) = @_; 538 539 my( $in_pod, $seen_end, $need_vers ) = ( 0, 0, 0 ); 540 my( @packages, %vers, %pod, @pod ); 541 my $package = 'main'; 542 my $pod_sect = ''; 543 my $pod_data = ''; 544 my $in_end = 0; 545 546 while (defined( my $line = <$fh> )) { 547 my $line_num = $.; 548 549 chomp( $line ); 550 551 # From toke.c : any line that begins by "=X", where X is an alphabetic 552 # character, introduces a POD segment. 553 my $is_cut; 554 if ( $line =~ /^=([a-zA-Z].*)/ ) { 555 my $cmd = $1; 556 # Then it goes back to Perl code for "=cutX" where X is a non-alphabetic 557 # character (which includes the newline, but here we chomped it away). 558 $is_cut = $cmd =~ /^cut(?:[^a-zA-Z]|$)/; 559 $in_pod = !$is_cut; 560 } 561 562 if ( $in_pod ) { 563 564 if ( $line =~ /^=head[1-4]\s+(.+)\s*$/ ) { 565 push( @pod, $1 ); 566 if ( $self->{collect_pod} && length( $pod_data ) ) { 567 $pod{$pod_sect} = $pod_data; 568 $pod_data = ''; 569 } 570 $pod_sect = $1; 571 } 572 elsif ( $self->{collect_pod} ) { 573 $pod_data .= "$line\n"; 574 } 575 next; 576 } 577 elsif ( $is_cut ) { 578 if ( $self->{collect_pod} && length( $pod_data ) ) { 579 $pod{$pod_sect} = $pod_data; 580 $pod_data = ''; 581 } 582 $pod_sect = ''; 583 next; 584 } 585 586 # Skip after __END__ 587 next if $in_end; 588 589 # Skip comments in code 590 next if $line =~ /^\s*#/; 591 592 # Would be nice if we could also check $in_string or something too 593 if ($line eq '__END__') { 594 $in_end++; 595 next; 596 } 597 598 last if $line eq '__DATA__'; 599 600 # parse $line to see if it's a $VERSION declaration 601 my( $version_sigil, $version_fullname, $version_package ) = 602 index($line, 'VERSION') >= 1 603 ? $self->_parse_version_expression( $line ) 604 : (); 605 606 if ( $line =~ /$PKG_REGEXP/o ) { 607 $package = $1; 608 my $version = $2; 609 push( @packages, $package ) unless grep( $package eq $_, @packages ); 610 $need_vers = defined $version ? 0 : 1; 611 612 if ( not exists $vers{$package} and defined $version ){ 613 # Upgrade to a version object. 614 my $dwim_version = eval { _dwim_version($version) }; 615 croak "Version '$version' from $self->{filename} does not appear to be valid:\n$line\n\nThe fatal error was: $@\n" 616 unless defined $dwim_version; # "0" is OK! 617 $vers{$package} = $dwim_version; 618 } 619 } 620 621 # VERSION defined with full package spec, i.e. $Module::VERSION 622 elsif ( $version_fullname && $version_package ) { 623 # we do NOT save this package in found @packages 624 $need_vers = 0 if $version_package eq $package; 625 626 unless ( defined $vers{$version_package} && length $vers{$version_package} ) { 627 $vers{$version_package} = $self->_evaluate_version_line( $version_sigil, $version_fullname, $line ); 628 } 629 } 630 631 # first non-comment line in undeclared package main is VERSION 632 elsif ( $package eq 'main' && $version_fullname && !exists($vers{main}) ) { 633 $need_vers = 0; 634 my $v = $self->_evaluate_version_line( $version_sigil, $version_fullname, $line ); 635 $vers{$package} = $v; 636 push( @packages, 'main' ); 637 } 638 639 # first non-comment line in undeclared package defines package main 640 elsif ( $package eq 'main' && !exists($vers{main}) && $line =~ /\w/ ) { 641 $need_vers = 1; 642 $vers{main} = ''; 643 push( @packages, 'main' ); 644 } 645 646 # only keep if this is the first $VERSION seen 647 elsif ( $version_fullname && $need_vers ) { 648 $need_vers = 0; 649 my $v = $self->_evaluate_version_line( $version_sigil, $version_fullname, $line ); 650 651 unless ( defined $vers{$package} && length $vers{$package} ) { 652 $vers{$package} = $v; 653 } 654 } 655 } # end loop over each line 656 657 if ( $self->{collect_pod} && length($pod_data) ) { 658 $pod{$pod_sect} = $pod_data; 659 } 660 661 $self->{versions} = \%vers; 662 $self->{packages} = \@packages; 663 $self->{pod} = \%pod; 664 $self->{pod_headings} = \@pod; 665} 666 667sub __uniq (@) 668{ 669 my (%seen, $key); 670 grep !$seen{ $key = $_ }++, @_; 671} 672 673{ 674my $pn = 0; 675sub _evaluate_version_line { 676 my $self = shift; 677 my( $sigil, $variable_name, $line ) = @_; 678 679 # We compile into a local sub because 'use version' would cause 680 # compiletime/runtime issues with local() 681 $pn++; # everybody gets their own package 682 my $eval = qq{ my \$dummy = q# Hide from _packages_inside() 683 #; package Module::Metadata::_version::p${pn}; 684 use version; 685 sub { 686 local $sigil$variable_name; 687 $line; 688 return \$$variable_name if defined \$$variable_name; 689 return \$Module::Metadata::_version::p${pn}::$variable_name; 690 }; 691 }; 692 693 $eval = $1 if $eval =~ m{^(.+)}s; 694 695 local $^W; 696 # Try to get the $VERSION 697 my $vsub = __clean_eval($eval); 698 # some modules say $VERSION <equal sign> $Foo::Bar::VERSION, but Foo::Bar isn't 699 # installed, so we need to hunt in ./lib for it 700 if ( $@ =~ /Can't locate/ && -d 'lib' ) { 701 local @INC = ('lib',@INC); 702 $vsub = __clean_eval($eval); 703 } 704 warn "Error evaling version line '$eval' in $self->{filename}: $@\n" 705 if $@; 706 707 (ref($vsub) eq 'CODE') or 708 croak "failed to build version sub for $self->{filename}"; 709 710 my $result = eval { $vsub->() }; 711 # FIXME: $eval is not the right thing to print here 712 croak "Could not get version from $self->{filename} by executing:\n$eval\n\nThe fatal error was: $@\n" 713 if $@; 714 715 # Upgrade it into a version object 716 my $version = eval { _dwim_version($result) }; 717 718 # FIXME: $eval is not the right thing to print here 719 croak "Version '$result' from $self->{filename} does not appear to be valid:\n$eval\n\nThe fatal error was: $@\n" 720 unless defined $version; # "0" is OK! 721 722 return $version; 723} 724} 725 726# Try to DWIM when things fail the lax version test in obvious ways 727{ 728 my @version_prep = ( 729 # Best case, it just works 730 sub { return shift }, 731 732 # If we still don't have a version, try stripping any 733 # trailing junk that is prohibited by lax rules 734 sub { 735 my $v = shift; 736 $v =~ s{([0-9])[a-z-].*$}{$1}i; # 1.23-alpha or 1.23b 737 return $v; 738 }, 739 740 # Activestate apparently creates custom versions like '1.23_45_01', which 741 # cause version.pm to think it's an invalid alpha. So check for that 742 # and strip them 743 sub { 744 my $v = shift; 745 my $num_dots = () = $v =~ m{(\.)}g; 746 my $num_unders = () = $v =~ m{(_)}g; 747 my $leading_v = substr($v,0,1) eq 'v'; 748 if ( ! $leading_v && $num_dots < 2 && $num_unders > 1 ) { 749 $v =~ s{_}{}g; 750 $num_unders = () = $v =~ m{(_)}g; 751 } 752 return $v; 753 }, 754 755 # Worst case, try numifying it like we would have before version objects 756 sub { 757 my $v = shift; 758 no warnings 'numeric'; 759 return 0 + $v; 760 }, 761 762 ); 763 764 sub _dwim_version { 765 my ($result) = shift; 766 767 return $result if ref($result) eq 'version'; 768 769 my ($version, $error); 770 for my $f (@version_prep) { 771 $result = $f->($result); 772 $version = eval { version->new($result) }; 773 $error ||= $@ if $@; # capture first failure 774 last if defined $version; 775 } 776 777 croak $error unless defined $version; 778 779 return $version; 780 } 781} 782 783############################################################ 784 785# accessors 786sub name { $_[0]->{module} } 787 788sub filename { $_[0]->{filename} } 789sub packages_inside { @{$_[0]->{packages}} } 790sub pod_inside { @{$_[0]->{pod_headings}} } 791sub contains_pod { 0+@{$_[0]->{pod_headings}} } 792 793sub version { 794 my $self = shift; 795 my $mod = shift || $self->{module}; 796 my $vers; 797 if ( defined( $mod ) && length( $mod ) && 798 exists( $self->{versions}{$mod} ) ) { 799 return $self->{versions}{$mod}; 800 } 801 else { 802 return undef; 803 } 804} 805 806sub pod { 807 my $self = shift; 808 my $sect = shift; 809 if ( defined( $sect ) && length( $sect ) && 810 exists( $self->{pod}{$sect} ) ) { 811 return $self->{pod}{$sect}; 812 } 813 else { 814 return undef; 815 } 816} 817 818sub is_indexable { 819 my ($self, $package) = @_; 820 821 my @indexable_packages = grep $_ ne 'main', $self->packages_inside; 822 823 # check for specific package, if provided 824 return !! grep $_ eq $package, @indexable_packages if $package; 825 826 # otherwise, check for any indexable packages at all 827 return !! @indexable_packages; 828} 829 8301; 831 832__END__ 833 834=pod 835 836=encoding UTF-8 837 838=head1 NAME 839 840Module::Metadata - Gather package and POD information from perl module files 841 842=head1 VERSION 843 844version 1.000036 845 846=head1 SYNOPSIS 847 848 use Module::Metadata; 849 850 # information about a .pm file 851 my $info = Module::Metadata->new_from_file( $file ); 852 my $version = $info->version; 853 854 # CPAN META 'provides' field for .pm files in a directory 855 my $provides = Module::Metadata->provides( 856 dir => 'lib', version => 2 857 ); 858 859=head1 DESCRIPTION 860 861This module provides a standard way to gather metadata about a .pm file through 862(mostly) static analysis and (some) code execution. When determining the 863version of a module, the C<$VERSION> assignment is C<eval>ed, as is traditional 864in the CPAN toolchain. 865 866=head1 CLASS METHODS 867 868=head2 C<< new_from_file($filename, collect_pod => 1) >> 869 870Constructs a C<Module::Metadata> object given the path to a file. Returns 871undef if the filename does not exist. 872 873C<collect_pod> is a optional boolean argument that determines whether POD 874data is collected and stored for reference. POD data is not collected by 875default. POD headings are always collected. 876 877If the file begins by an UTF-8, UTF-16BE or UTF-16LE byte-order mark, then 878it is skipped before processing, and the content of the file is also decoded 879appropriately starting from perl 5.8. 880 881=head2 C<< new_from_handle($handle, $filename, collect_pod => 1) >> 882 883This works just like C<new_from_file>, except that a handle can be provided 884as the first argument. 885 886Note that there is no validation to confirm that the handle is a handle or 887something that can act like one. Passing something that isn't a handle will 888cause a exception when trying to read from it. The C<filename> argument is 889mandatory or undef will be returned. 890 891You are responsible for setting the decoding layers on C<$handle> if 892required. 893 894=head2 C<< new_from_module($module, collect_pod => 1, inc => \@dirs) >> 895 896Constructs a C<Module::Metadata> object given a module or package name. 897Returns undef if the module cannot be found. 898 899In addition to accepting the C<collect_pod> argument as described above, 900this method accepts a C<inc> argument which is a reference to an array of 901directories to search for the module. If none are given, the default is 902@INC. 903 904If the file that contains the module begins by an UTF-8, UTF-16BE or 905UTF-16LE byte-order mark, then it is skipped before processing, and the 906content of the file is also decoded appropriately starting from perl 5.8. 907 908=head2 C<< find_module_by_name($module, \@dirs) >> 909 910Returns the path to a module given the module or package name. A list 911of directories can be passed in as an optional parameter, otherwise 912@INC is searched. 913 914Can be called as either an object or a class method. 915 916=head2 C<< find_module_dir_by_name($module, \@dirs) >> 917 918Returns the entry in C<@dirs> (or C<@INC> by default) that contains 919the module C<$module>. A list of directories can be passed in as an 920optional parameter, otherwise @INC is searched. 921 922Can be called as either an object or a class method. 923 924=head2 C<< provides( %options ) >> 925 926This is a convenience wrapper around C<package_versions_from_directory> 927to generate a CPAN META C<provides> data structure. It takes key/value 928pairs. Valid option keys include: 929 930=over 931 932=item version B<(required)> 933 934Specifies which version of the L<CPAN::Meta::Spec> should be used as 935the format of the C<provides> output. Currently only '1.4' and '2' 936are supported (and their format is identical). This may change in 937the future as the definition of C<provides> changes. 938 939The C<version> option is required. If it is omitted or if 940an unsupported version is given, then C<provides> will throw an error. 941 942=item dir 943 944Directory to search recursively for F<.pm> files. May not be specified with 945C<files>. 946 947=item files 948 949Array reference of files to examine. May not be specified with C<dir>. 950 951=item prefix 952 953String to prepend to the C<file> field of the resulting output. This defaults 954to F<lib>, which is the common case for most CPAN distributions with their 955F<.pm> files in F<lib>. This option ensures the META information has the 956correct relative path even when the C<dir> or C<files> arguments are 957absolute or have relative paths from a location other than the distribution 958root. 959 960=back 961 962For example, given C<dir> of 'lib' and C<prefix> of 'lib', the return value 963is a hashref of the form: 964 965 { 966 'Package::Name' => { 967 version => '0.123', 968 file => 'lib/Package/Name.pm' 969 }, 970 'OtherPackage::Name' => ... 971 } 972 973=head2 C<< package_versions_from_directory($dir, \@files?) >> 974 975Scans C<$dir> for .pm files (unless C<@files> is given, in which case looks 976for those files in C<$dir> - and reads each file for packages and versions, 977returning a hashref of the form: 978 979 { 980 'Package::Name' => { 981 version => '0.123', 982 file => 'Package/Name.pm' 983 }, 984 'OtherPackage::Name' => ... 985 } 986 987The C<DB> and C<main> packages are always omitted, as are any "private" 988packages that have leading underscores in the namespace (e.g. 989C<Foo::_private>) 990 991Note that the file path is relative to C<$dir> if that is specified. 992This B<must not> be used directly for CPAN META C<provides>. See 993the C<provides> method instead. 994 995=head2 C<< log_info (internal) >> 996 997Used internally to perform logging; imported from Log::Contextual if 998Log::Contextual has already been loaded, otherwise simply calls warn. 999 1000=head1 OBJECT METHODS 1001 1002=head2 C<< name() >> 1003 1004Returns the name of the package represented by this module. If there 1005is more than one package, it makes a best guess based on the 1006filename. If it's a script (i.e. not a *.pm) the package name is 1007'main'. 1008 1009=head2 C<< version($package) >> 1010 1011Returns the version as defined by the $VERSION variable for the 1012package as returned by the C<name> method if no arguments are 1013given. If given the name of a package it will attempt to return the 1014version of that package if it is specified in the file. 1015 1016=head2 C<< filename() >> 1017 1018Returns the absolute path to the file. 1019Note that this file may not actually exist on disk yet, e.g. if the module was read from an in-memory filehandle. 1020 1021=head2 C<< packages_inside() >> 1022 1023Returns a list of packages. Note: this is a raw list of packages 1024discovered (or assumed, in the case of C<main>). It is not 1025filtered for C<DB>, C<main> or private packages the way the 1026C<provides> method does. Invalid package names are not returned, 1027for example "Foo:Bar". Strange but valid package names are 1028returned, for example "Foo::Bar::", and are left up to the caller 1029on how to handle. 1030 1031=head2 C<< pod_inside() >> 1032 1033Returns a list of POD sections. 1034 1035=head2 C<< contains_pod() >> 1036 1037Returns true if there is any POD in the file. 1038 1039=head2 C<< pod($section) >> 1040 1041Returns the POD data in the given section. 1042 1043=head2 C<< is_indexable($package) >> or C<< is_indexable() >> 1044 1045Available since version 1.000020. 1046 1047Returns a boolean indicating whether the package (if provided) or any package 1048(otherwise) is eligible for indexing by PAUSE, the Perl Authors Upload Server. 1049Note This only checks for valid C<package> declarations, and does not take any 1050ownership information into account. 1051 1052=head1 SUPPORT 1053 1054Bugs may be submitted through L<the RT bug tracker|https://rt.cpan.org/Public/Dist/Display.html?Name=Module-Metadata> 1055(or L<bug-Module-Metadata@rt.cpan.org|mailto:bug-Module-Metadata@rt.cpan.org>). 1056 1057There is also a mailing list available for users of this distribution, at 1058L<http://lists.perl.org/list/cpan-workers.html>. 1059 1060There is also an irc channel available for users of this distribution, at 1061L<C<#toolchain> on C<irc.perl.org>|irc://irc.perl.org/#toolchain>. 1062 1063=head1 AUTHOR 1064 1065Original code from Module::Build::ModuleInfo by Ken Williams 1066<kwilliams@cpan.org>, Randy W. Sims <RandyS@ThePierianSpring.org> 1067 1068Released as Module::Metadata by Matt S Trout (mst) <mst@shadowcat.co.uk> with 1069assistance from David Golden (xdg) <dagolden@cpan.org>. 1070 1071=head1 CONTRIBUTORS 1072 1073=for stopwords Karen Etheridge David Golden Vincent Pit Matt S Trout Chris Nehren Graham Knop Olivier Mengué Tomas Doran tokuhirom Christian Walde Tatsuhiko Miyagawa Peter Rabbitson Steve Hay Jerry D. Hedden Craig A. Berry Mitchell Steinbrunner Edward Zborowski Gareth Harper James Raspass 'BinGOs' Williams Josh Jore Kent Fredric 1074 1075=over 4 1076 1077=item * 1078 1079Karen Etheridge <ether@cpan.org> 1080 1081=item * 1082 1083David Golden <dagolden@cpan.org> 1084 1085=item * 1086 1087Vincent Pit <perl@profvince.com> 1088 1089=item * 1090 1091Matt S Trout <mst@shadowcat.co.uk> 1092 1093=item * 1094 1095Chris Nehren <apeiron@cpan.org> 1096 1097=item * 1098 1099Graham Knop <haarg@haarg.org> 1100 1101=item * 1102 1103Olivier Mengué <dolmen@cpan.org> 1104 1105=item * 1106 1107Tomas Doran <bobtfish@bobtfish.net> 1108 1109=item * 1110 1111tokuhirom <tokuhirom@gmail.com> 1112 1113=item * 1114 1115Christian Walde <walde.christian@googlemail.com> 1116 1117=item * 1118 1119Tatsuhiko Miyagawa <miyagawa@bulknews.net> 1120 1121=item * 1122 1123Peter Rabbitson <ribasushi@cpan.org> 1124 1125=item * 1126 1127Steve Hay <steve.m.hay@googlemail.com> 1128 1129=item * 1130 1131Jerry D. Hedden <jdhedden@cpan.org> 1132 1133=item * 1134 1135Craig A. Berry <cberry@cpan.org> 1136 1137=item * 1138 1139Craig A. Berry <craigberry@mac.com> 1140 1141=item * 1142 1143David Mitchell <davem@iabyn.com> 1144 1145=item * 1146 1147David Steinbrunner <dsteinbrunner@pobox.com> 1148 1149=item * 1150 1151Edward Zborowski <ed@rubensteintech.com> 1152 1153=item * 1154 1155Gareth Harper <gareth@broadbean.com> 1156 1157=item * 1158 1159James Raspass <jraspass@gmail.com> 1160 1161=item * 1162 1163Chris 'BinGOs' Williams <chris@bingosnet.co.uk> 1164 1165=item * 1166 1167Josh Jore <jjore@cpan.org> 1168 1169=item * 1170 1171Kent Fredric <kentnl@cpan.org> 1172 1173=back 1174 1175=head1 COPYRIGHT & LICENSE 1176 1177Original code Copyright (c) 2001-2011 Ken Williams. 1178Additional code Copyright (c) 2010-2011 Matt Trout and David Golden. 1179All rights reserved. 1180 1181This library is free software; you can redistribute it and/or 1182modify it under the same terms as Perl itself. 1183 1184=cut 1185