#!perl -w
my
(
$tap
,
$test
,
%Missing
);
BEGIN {
@ARGV
=
grep
{ not(
$_
eq
'--tap'
and
$tap
= 1) }
@ARGV
;
if
(
$tap
) {
Test::More->
import
;
}
}
my
(
%Kinds
,
%Flavor
,
@Types
);
my
%Omit
;
my
$p
= Pod::Simple::SimpleTree->new;
$p
->accept_targets(
'Pod::Functions'
);
my
$tree
=
$p
->parse_file(
shift
)->root;
foreach
my
$TL_node
(
@$tree
[2 ..
$#$tree
]) {
next
unless
$TL_node
->[0] eq
'over-text'
;
my
$i
= 2;
while
(
$i
<=
$#$TL_node
) {
if
(
$TL_node
->[
$i
][0] ne
'item-text'
) {
++
$i
;
next
;
}
my
$item_text
=
$TL_node
->[
$i
][2];
die
"Confused by $item_text at line $TL_node->[$i][1]{start_line}"
if
ref
$item_text
;
$item_text
=~ s/\s+\z//s;
if
(
$TL_node
->[
$i
+1][0] ne
'for'
||
$TL_node
->[
$i
+1][1]{target} ne
'Pod::Functions'
) {
++
$i
;
++
$Missing
{
$item_text
}
unless
$Omit
{
$item_text
};
next
;
}
my
$data
=
$TL_node
->[
$i
+1][2];
die
"Confused by $data at line $TL_node->[$i+1][1]{start_line}"
unless
ref
$data
eq
'ARRAY'
;
my
$text
=
$data
->[2];
die
"Confused by $text at line $TL_node->[$i+1][1]{start_line}"
if
ref
$text
;
$i
+= 2;
if
(
$text
=~ s/^=//) {
die
"Expected a paragraph after =item at $TL_node->[$i-2][1]{start_line}"
unless
$TL_node
->[
$i
][0] eq
'Para'
;
my
$para
=
$TL_node
->[
$i
];
foreach
my
$func
(
@$para
[2 ..
$#$para
]) {
next
unless
ref
$func
eq
'ARRAY'
;
my
$c_node
=
$func
->[0] eq
'C'
&& !
ref
$func
->[2] ?
$func
:
$func
->[0] eq
'L'
&&
ref
$func
->[2]
&&
$func
->[2][0] eq
'C'
&& !
ref
$func
->[2][2] ?
$func
->[2] :
die
"Expected only C<> blocks in paragraph after item at $TL_node->[$i-2][1]{start_line}"
;
my
$funcname
=
join
''
,
map
{
ref
$_
?
$_
->[2] :
$_
}
@$c_node
[2..
$#$c_node
];
$funcname
=~ s!(
q.?)//!$1/STRING/!;
push @{$Kinds{$text}}, $funcname;
}
if ($text =~ /^!/) {
++$Omit{$_} foreach @{$Kinds{$text}};
} else {
push @Types, [$text, $item_text];
}
} else {
$item_text =~ s/ .
*//;
$text
=~ s/^\+\S+ //;
$Flavor
{
$item_text
} =
$text
;
++
$Omit
{
$item_text
}
if
$text
=~ /^!/;
}
}
}
my
%Type
;
while
(
my
(
$type
,
$funcs
) =
each
%Kinds
) {
push
@{
$Type
{
$_
}},
$type
foreach
@$funcs
;
}
sub
sort_funcs {
map
{
$_
->[0] }
sort
{
uc
$a
->[1] cmp
uc
$b
->[1]
||
$b
->[1] cmp
$a
->[1]
||
$a
->[0] =~ /^_/
||
$a
->[0] cmp
$b
->[0]
}
map
{
my
$f
=
tr
/_//dr; [
$_
,
$f
] }
@_
;
}
if
(
$tap
) {
foreach
my
$func
(sort_funcs(
keys
%Flavor
)) {
ok (
$Type
{
$func
},
"$func is mentioned in at least one category group"
);
}
foreach
(
sort
keys
%Missing
) {
s!(?: [A-Z].*| \(\)|\( LIST \)| /PATTERN/.*)!!;
next
if
$Flavor
{
$_
};
if
(/^[_a-z]/) {
fail(
"function '$_' has no summary for Pod::Functions"
);
}
else
{
fail(
"for Pod::Functions"
);
}
}
foreach
my
$kind
(
sort
keys
%Kinds
) {
my
$funcs
=
$Kinds
{
$kind
};
++
$test
;
my
$want
=
join
' '
, sort_funcs(
@$funcs
);
is (
"@$funcs"
,
$want
,
"category $kind is correctly sorted"
);
}
done_testing();
exit
;
}
my
$real
=
'Functions.pm'
;
my
$temp
=
"Functions.$$"
;
END {
return
if
!
defined
$temp
|| !-e
$temp
;
unlink
$temp
or
warn
"Can't unlink '$temp': $!"
;
}
foreach
(
$real
,
$temp
) {
next
if
!-e
$_
;
unlink
$_
or
die
"Can't unlink '$_': $!"
;
}
open
my
$fh
,
'>'
,
$temp
or
die
"Can't open '$temp' for writing: $!"
;
print
$fh
<<'EOT';
package Pod::Functions;
use strict;
=head1 NAME
Pod::Functions - Group Perl's functions a la perlfunc.pod
=head1 SYNOPSIS
use Pod::Functions;
my @misc_ops = @{ $Kinds{ 'Misc' } };
my $misc_dsc = $Type_Description{ 'Misc' };
or
perl /path/to/lib/Pod/Functions.pm
This will print a grouped list of Perl's functions, like the
L<perlfunc/"Perl Functions by Category"> section.
=head1 DESCRIPTION
It exports the following variables:
=over 4
=item %Kinds
This holds a hash-of-lists. Each list contains the functions in the category
the key denotes.
=item %Type
In this hash each key represents a function and the value is the category.
The category can be a comma separated list.
=item %Flavor
In this hash each key represents a function and the value is a short
description of that function.
=item %Type_Description
In this hash each key represents a category of functions and the value is
a short description of that category.
=item @Type_Order
This list of categories is used to produce the same order as the
L<perlfunc/"Perl Functions by Category"> section.
=back
=cut
our $VERSION = '1.14';
use Exporter 'import';
our @EXPORT = qw(%Kinds %Type %Flavor %Type_Description @Type_Order);
our(%Kinds, %Type, %Flavor, %Type_Description, @Type_Order);
foreach (
EOT
foreach
(
@Types
) {
my
(
$type
,
$desc
) =
@$_
;
$type
=
"'$type'"
if
$type
=~ /[^A-Za-z]/;
$desc
=~ s!([\\'])!\\$1!g;
printf
$fh
" [%-9s => '%s'],\n"
,
$type
,
$desc
;
}
print
$fh
<<'EOT';
) {
push @Type_Order, $_->[0];
$Type_Description{$_->[0]} = $_->[1];
};
while (<DATA>) {
chomp;
s/^#.*//;
next unless $_;
my($name, @data) = split "\t", $_;
$Flavor{$name} = pop @data;
$Type{$name} = join ',', @data;
for my $t (@data) {
push @{$Kinds{$t}}, $name;
}
}
close DATA;
my( $typedesc, $list );
unless (caller) {
foreach my $type ( @Type_Order ) {
$list = join(", ", sort @{$Kinds{$type}});
$typedesc = $Type_Description{$type} . ":";
write;
}
}
format =
^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
$typedesc
~~ ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
$typedesc
~~ ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
$list
.
1;
__DATA__
EOT
foreach
my
$func
(sort_funcs(
keys
%Flavor
)) {
my
$desc
=
$Flavor
{
$func
};
die
"No types listed for $func"
unless
$Type
{
$func
};
next
if
$Omit
{
$func
};
print
$fh
join
(
"\t"
,
$func
, (
sort
@{
$Type
{
$func
}}),
$desc
),
"\n"
;
}
close
$fh
or
die
"Can't close '$temp': $!"
;
rename
$temp
,
$real
or
die
"Can't rename '$temp' to '$real': $!"
;