| Filename | /usr/share/perl/5.36/Module/Metadata.pm |
| Statements | Executed 38 statements in 3.22ms |
| Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
|---|---|---|---|---|---|
| 1 | 1 | 1 | 2.79ms | 2.88ms | Module::Metadata::BEGIN@39 |
| 3 | 3 | 1 | 296µs | 296µs | Module::Metadata::CORE:regcomp (opcode) |
| 1 | 1 | 1 | 8µs | 8µs | Module::Metadata::BEGIN@20 |
| 1 | 1 | 1 | 7µs | 9µs | Module::Metadata::BEGIN@14 |
| 1 | 1 | 1 | 7µs | 25µs | Module::Metadata::BEGIN@27 |
| 1 | 1 | 1 | 6µs | 24µs | Module::Metadata::BEGIN@767 |
| 1 | 1 | 1 | 5µs | 17µs | Module::Metadata::BEGIN@19 |
| 1 | 1 | 1 | 4µs | 15µs | Module::Metadata::BEGIN@21 |
| 7 | 7 | 1 | 4µs | 4µs | Module::Metadata::CORE:qr (opcode) |
| 1 | 1 | 1 | 3µs | 16µs | Module::Metadata::BEGIN@15 |
| 1 | 1 | 1 | 3µs | 3µs | Module::Metadata::BEGIN@28 |
| 1 | 1 | 1 | 300ns | 300ns | Module::Metadata::__ANON__ (xsub) |
| 0 | 0 | 0 | 0s | 0s | Module::Metadata::__ANON__[:143] |
| 0 | 0 | 0 | 0s | 0s | Module::Metadata::__ANON__[:146] |
| 0 | 0 | 0 | 0s | 0s | Module::Metadata::__ANON__[:164] |
| 0 | 0 | 0 | 0s | 0s | Module::Metadata::__ANON__[:202] |
| 0 | 0 | 0 | 0s | 0s | Module::Metadata::__ANON__[:254] |
| 0 | 0 | 0 | 0s | 0s | Module::Metadata::__ANON__[:25] |
| 0 | 0 | 0 | 0s | 0s | Module::Metadata::__ANON__[:312] |
| 0 | 0 | 0 | 0s | 0s | Module::Metadata::__ANON__[:332] |
| 0 | 0 | 0 | 0s | 0s | Module::Metadata::__ANON__[:356] |
| 0 | 0 | 0 | 0s | 0s | Module::Metadata::__ANON__[:36] |
| 0 | 0 | 0 | 0s | 0s | Module::Metadata::__ANON__[:739] |
| 0 | 0 | 0 | 0s | 0s | Module::Metadata::__ANON__[:747] |
| 0 | 0 | 0 | 0s | 0s | Module::Metadata::__ANON__[:762] |
| 0 | 0 | 0 | 0s | 0s | Module::Metadata::__ANON__[:769] |
| 0 | 0 | 0 | 0s | 0s | Module::Metadata::__clean_eval |
| 0 | 0 | 0 | 0s | 0s | Module::Metadata::__uniq |
| 0 | 0 | 0 | 0s | 0s | Module::Metadata::_do_find_module |
| 0 | 0 | 0 | 0s | 0s | Module::Metadata::_dwim_version |
| 0 | 0 | 0 | 0s | 0s | Module::Metadata::_evaluate_version_line |
| 0 | 0 | 0 | 0s | 0s | Module::Metadata::_handle_bom |
| 0 | 0 | 0 | 0s | 0s | Module::Metadata::_init |
| 0 | 0 | 0 | 0s | 0s | Module::Metadata::_parse_fh |
| 0 | 0 | 0 | 0s | 0s | Module::Metadata::_parse_version_expression |
| 0 | 0 | 0 | 0s | 0s | Module::Metadata::contains_pod |
| 0 | 0 | 0 | 0s | 0s | Module::Metadata::filename |
| 0 | 0 | 0 | 0s | 0s | Module::Metadata::find_module_by_name |
| 0 | 0 | 0 | 0s | 0s | Module::Metadata::find_module_dir_by_name |
| 0 | 0 | 0 | 0s | 0s | Module::Metadata::is_indexable |
| 0 | 0 | 0 | 0s | 0s | Module::Metadata::name |
| 0 | 0 | 0 | 0s | 0s | Module::Metadata::new_from_file |
| 0 | 0 | 0 | 0s | 0s | Module::Metadata::new_from_handle |
| 0 | 0 | 0 | 0s | 0s | Module::Metadata::new_from_module |
| 0 | 0 | 0 | 0s | 0s | Module::Metadata::package_versions_from_directory |
| 0 | 0 | 0 | 0s | 0s | Module::Metadata::packages_inside |
| 0 | 0 | 0 | 0s | 0s | Module::Metadata::pod |
| 0 | 0 | 0 | 0s | 0s | Module::Metadata::pod_inside |
| 0 | 0 | 0 | 0s | 0s | Module::Metadata::provides |
| 0 | 0 | 0 | 0s | 0s | Module::Metadata::version |
| Line | State ments |
Time on line |
Calls | Time in subs |
Code |
|---|---|---|---|---|---|
| 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 | ||||
| 3 | package 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 | |||||
| 13 | sub __clean_eval { eval $_[0] } | ||||
| 14 | 2 | 16µs | 2 | 10µs | # spent 9µs (7+1) within Module::Metadata::BEGIN@14 which was called:
# once (7µs+1µs) by Module::Load::Conditional::BEGIN@14 at line 14 # spent 9µs making 1 call to Module::Metadata::BEGIN@14
# spent 1µs making 1 call to strict::import |
| 15 | 2 | 21µs | 2 | 30µs | # spent 16µs (3+13) within Module::Metadata::BEGIN@15 which was called:
# once (3µs+13µs) by Module::Load::Conditional::BEGIN@14 at line 15 # spent 16µs making 1 call to Module::Metadata::BEGIN@15
# spent 13µs making 1 call to warnings::import |
| 16 | |||||
| 17 | 1 | 300ns | our $VERSION = '1.000037'; | ||
| 18 | |||||
| 19 | 2 | 14µs | 2 | 28µs | # spent 17µs (5+12) within Module::Metadata::BEGIN@19 which was called:
# once (5µs+12µs) by Module::Load::Conditional::BEGIN@14 at line 19 # spent 17µs making 1 call to Module::Metadata::BEGIN@19
# spent 12µs making 1 call to Exporter::import |
| 20 | 2 | 41µs | 2 | 8µs | # spent 8µs (8+300ns) within Module::Metadata::BEGIN@20 which was called:
# once (8µs+300ns) by Module::Load::Conditional::BEGIN@14 at line 20 # spent 8µs making 1 call to Module::Metadata::BEGIN@20
# spent 300ns making 1 call to Module::Metadata::__ANON__ |
| 21 | # spent 15µs (4+11) within Module::Metadata::BEGIN@21 which was called:
# once (4µs+11µs) by Module::Load::Conditional::BEGIN@14 at line 26 | ||||
| 22 | # Try really hard to not depend ony any DynaLoaded module, such as IO::File or Fcntl | ||||
| 23 | eval { | ||||
| 24 | 3 | 2µs | 1 | 11µs | require Fcntl; Fcntl->import('SEEK_SET'); 1; # spent 11µs making 1 call to Exporter::import |
| 25 | } or *SEEK_SET = sub { 0 } | ||||
| 26 | 1 | 17µs | 1 | 15µs | } # spent 15µs making 1 call to Module::Metadata::BEGIN@21 |
| 27 | 3 | 63µs | 3 | 43µs | # spent 25µs (7+18) within Module::Metadata::BEGIN@27 which was called:
# once (7µs+18µs) by Module::Load::Conditional::BEGIN@14 at line 27 # spent 25µs making 1 call to Module::Metadata::BEGIN@27
# spent 13µs making 1 call to version::import
# spent 5µs making 1 call to version::_VERSION |
| 28 | # spent 3µs within Module::Metadata::BEGIN@28 which was called:
# once (3µs+0s) by Module::Load::Conditional::BEGIN@14 at line 38 | ||||
| 29 | 1 | 2µs | 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 | 1 | 1µs | *log_info = sub (&) { warn $_[0]->() }; | ||
| 37 | } | ||||
| 38 | 1 | 12µs | 1 | 3µs | } # spent 3µs making 1 call to Module::Metadata::BEGIN@28 |
| 39 | 2 | 2.43ms | 2 | 2.90ms | # spent 2.88ms (2.79+84µs) within Module::Metadata::BEGIN@39 which was called:
# once (2.79ms+84µs) by Module::Load::Conditional::BEGIN@14 at line 39 # spent 2.88ms making 1 call to Module::Metadata::BEGIN@39
# spent 21µs making 1 call to Exporter::import |
| 40 | |||||
| 41 | 1 | 6µs | 1 | 2µs | my $V_NUM_REGEXP = qr{v?[0-9._]+}; # crudely, a v-string or decimal # spent 2µs making 1 call to Module::Metadata::CORE:qr |
| 42 | |||||
| 43 | 1 | 3µs | 1 | 300ns | my $PKG_FIRST_WORD_REGEXP = qr{ # the FIRST word in a package name # spent 300ns making 1 call to Module::Metadata::CORE:qr |
| 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 | |||||
| 51 | 1 | 1µs | 1 | 300ns | my $PKG_ADDL_WORD_REGEXP = qr{ # the 2nd+ word in a package name # spent 300ns making 1 call to Module::Metadata::CORE:qr |
| 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 | |||||
| 59 | 1 | 125µs | 2 | 121µs | my $PKG_NAME_REGEXP = qr{ # match a package name # spent 121µs making 1 call to Module::Metadata::CORE:regcomp
# spent 400ns making 1 call to Module::Metadata::CORE:qr |
| 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 | |||||
| 71 | 1 | 124µs | 2 | 121µs | my $PKG_REGEXP = qr{ # match a package declaration # spent 120µs making 1 call to Module::Metadata::CORE:regcomp
# spent 400ns making 1 call to Module::Metadata::CORE:qr |
| 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 | |||||
| 82 | 1 | 1µs | 1 | 300ns | my $VARNAME_REGEXP = qr{ # match fully-qualified VERSION name # spent 300ns making 1 call to Module::Metadata::CORE:qr |
| 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 | |||||
| 93 | 1 | 58µs | 2 | 55µs | my $VERS_REGEXP = qr{ # match a VERSION definition # spent 55µs making 1 call to Module::Metadata::CORE:regcomp
# spent 300ns making 1 call to Module::Metadata::CORE:qr |
| 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 | |||||
| 103 | sub 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 | |||||
| 111 | sub 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 | |||||
| 123 | sub 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 | 1 | 2µs | }; | ||
| 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 | 1 | 600ns | }; | ||
| 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 | 1 | 1µs | }; | ||
| 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 | |||||
| 378 | 1 | 300ns | sub _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 | ||||
| 447 | sub _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 | ||||
| 466 | sub find_module_by_name { | ||||
| 467 | my $found = shift()->_do_find_module(@_) or return; | ||||
| 468 | return $found->[0]; | ||||
| 469 | } | ||||
| 470 | |||||
| 471 | # class method | ||||
| 472 | sub 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 | ||||
| 480 | sub _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. | ||||
| 498 | sub _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 | |||||
| 536 | sub _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 | |||||
| 676 | sub __uniq (@) | ||||
| 677 | { | ||||
| 678 | my (%seen, $key); | ||||
| 679 | grep !$seen{ $key = $_ }++, @_; | ||||
| 680 | } | ||||
| 681 | |||||
| 682 | { | ||||
| 683 | 1 | 200ns | my $pn = 0; | ||
| 684 | sub _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 | 1 | 100ns | 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 | 2 | 262µs | 2 | 41µs | # spent 24µs (6+18) within Module::Metadata::BEGIN@767 which was called:
# once (6µs+18µs) by Module::Load::Conditional::BEGIN@14 at line 767 # spent 24µs making 1 call to Module::Metadata::BEGIN@767
# spent 18µs making 1 call to warnings::unimport |
| 768 | return 0 + $v; | ||||
| 769 | }, | ||||
| 770 | |||||
| 771 | 1 | 2µs | ); | ||
| 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 | ||||
| 795 | 1 | 200ns | sub name { $_[0]->{module} } | ||
| 796 | |||||
| 797 | sub filename { $_[0]->{filename} } | ||||
| 798 | sub packages_inside { @{$_[0]->{packages}} } | ||||
| 799 | sub pod_inside { @{$_[0]->{pod_headings}} } | ||||
| 800 | sub contains_pod { 0+@{$_[0]->{pod_headings}} } | ||||
| 801 | |||||
| 802 | sub 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 | |||||
| 815 | sub 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 | |||||
| 827 | sub 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 | |||||
| 839 | 1 | 12µs | 1; | ||
| 840 | |||||
| 841 | __END__ | ||||
# spent 4µs within Module::Metadata::CORE:qr which was called 7 times, avg 500ns/call:
# once (2µs+0s) by Module::Load::Conditional::BEGIN@14 at line 41
# once (400ns+0s) by Module::Load::Conditional::BEGIN@14 at line 71
# once (400ns+0s) by Module::Load::Conditional::BEGIN@14 at line 59
# once (300ns+0s) by Module::Load::Conditional::BEGIN@14 at line 93
# once (300ns+0s) by Module::Load::Conditional::BEGIN@14 at line 43
# once (300ns+0s) by Module::Load::Conditional::BEGIN@14 at line 51
# once (300ns+0s) by Module::Load::Conditional::BEGIN@14 at line 82 | |||||
sub Module::Metadata::CORE:regcomp; # opcode | |||||
# spent 300ns within Module::Metadata::__ANON__ which was called:
# once (300ns+0s) by Module::Metadata::BEGIN@20 at line 20 |