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