3 use Pod::Simple::SimpleTree;
5 my ($tap, $test, %Missing);
8 @ARGV = grep { not($_ eq '--tap' and $tap = 1) } @ARGV;
15 my (%Kinds, %Flavor, @Types);
18 my $p = Pod::Simple::SimpleTree->new;
19 $p->accept_targets('Pod::Functions');
20 my $tree = $p->parse_file(shift)->root;
22 foreach my $TL_node (@$tree[2 .. $#$tree]) {
23 next unless $TL_node->[0] eq 'over-text';
25 while ($i <= $#$TL_node) {
26 if ($TL_node->[$i][0] ne 'item-text') {
31 my $item_text = $TL_node->[$i][2];
32 die "Confused by $item_text at line $TL_node->[$i][1]{start_line}"
34 $item_text =~ s/\s+\z//s;
36 if ($TL_node->[$i+1][0] ne 'for'
37 || $TL_node->[$i+1][1]{target} ne 'Pod::Functions') {
39 ++$Missing{$item_text} unless $Omit{$item_text};
42 my $data = $TL_node->[$i+1][2];
43 die "Confused by $data at line $TL_node->[$i+1][1]{start_line}"
44 unless ref $data eq 'ARRAY';
45 my $text = $data->[2];
46 die "Confused by $text at line $TL_node->[$i+1][1]{start_line}"
51 if ($text =~ s/^=//) {
52 # We are in "Perl Functions by Category"
53 die "Expected a paragraph after =item at $TL_node->[$i-2][1]{start_line}"
54 unless $TL_node->[$i][0] eq 'Para';
55 my $para = $TL_node->[$i];
56 # $text is the "type" of the built-in
57 # Anything starting ! is not for inclusion in Pod::Functions
59 foreach my $func (@$para[2 .. $#$para]) {
60 next unless ref $func eq 'ARRAY';
61 die "Expected only C<> blocks in paragraph after item at $TL_node->[$i-2][1]{start_line}"
62 unless $func->[0] eq 'C' && !ref $func->[2];
63 # Everything is plain text (ie $func->[2] is everything)
64 # except for C<-I<X>>. So untangle up to one level of nested <>
65 my $funcname = join '', map {
68 $funcname =~ s!(q.?)//!$1/STRING/!;
69 push @{$Kinds{$text}}, $funcname;
72 ++$Omit{$_} foreach @{$Kinds{$text}};
74 push @Types, [$text, $item_text];
77 $item_text =~ s/ .*//;
78 # For now, just remove any metadata about when it was added:
80 $Flavor{$item_text} = $text;
81 ++$Omit{$item_text} if $text =~ /^!/;
86 # Take the lists of functions for each type group, and invert them to get the
87 # type group (or groups) for each function:
89 while (my ($type, $funcs) = each %Kinds) {
90 push @{$Type{$_}}, $type foreach @$funcs;
93 # We sort __SUB__ after sub, but before substr, but __PACKAGE__ after package,
94 # and __END__ after END.
97 sort { uc $a->[1] cmp uc $b->[1] || $b->[1] cmp $a->[1] || $a->[0] cmp $b->[0] }
98 map { my $f = tr/_//dr; [ $_, $f ] }
103 foreach my $func (sort_funcs(keys %Flavor)) {
104 ok ( $Type{$func}, "$func is mentioned in at least one category group");
106 foreach (sort keys %Missing) {
107 # Ignore anything that looks like an alternative for a function we've
109 s!(?: [A-Z].*| \(\)|\( LIST \)| /PATTERN/.*)!!;
112 fail( "function '$_' has no summary for Pod::Functions" );
114 fail( "for Pod::Functions" );
117 foreach my $kind (sort keys %Kinds) {
118 my $funcs = $Kinds{$kind};
120 my $want = join ' ', sort_funcs(@$funcs);
121 is ("@$funcs", $want, "category $kind is correctly sorted" );
127 # blead will run this with miniperl, hence we can't use autodie
128 my $real = 'Functions.pm';
129 my $temp = "Functions.$$";
132 return if !defined $temp || !-e $temp;
133 unlink $temp or warn "Can't unlink '$temp': $!";
136 foreach ($real, $temp) {
138 unlink $_ or die "Can't unlink '$_': $!";
141 open my $fh, '>', $temp or die "Can't open '$temp' for writing: $!";
143 package Pod::Functions;
148 Pod::Functions - Group Perl's functions a la perlfunc.pod
154 my @misc_ops = @{ $Kinds{ 'Misc' } };
155 my $misc_dsc = $Type_Description{ 'Misc' };
159 perl /path/to/lib/Pod/Functions.pm
161 This will print a grouped list of Perl's functions, like the
162 L<perlfunc/"Perl Functions by Category"> section.
166 It exports the following variables:
172 This holds a hash-of-lists. Each list contains the functions in the category
177 In this hash each key represents a function and the value is the category.
178 The category can be a comma separated list.
182 In this hash each key represents a function and the value is a short
183 description of that function.
185 =item %Type_Description
187 In this hash each key represents a category of functions and the value is
188 a short description of that category.
192 This list of categories is used to produce the same order as the
193 L<perlfunc/"Perl Functions by Category"> section.
199 our $VERSION = '1.08';
203 our @ISA = qw(Exporter);
204 our @EXPORT = qw(%Kinds %Type %Flavor %Type_Description @Type_Order);
206 our(%Kinds, %Type, %Flavor, %Type_Description, @Type_Order);
212 my ($type, $desc) = @$_;
213 $type = "'$type'" if $type =~ /[^A-Za-z]/;
214 $desc =~ s!([\\'])!\\$1!g;
215 printf $fh " [%-9s => '%s'],\n", $type, $desc;
220 push @Type_Order, $_->[0];
221 $Type_Description{$_->[0]} = $_->[1];
228 my($name, @data) = split "\t", $_;
229 $Flavor{$name} = pop @data;
230 $Type{$name} = join ',', @data;
232 push @{$Kinds{$t}}, $name;
238 my( $typedesc, $list );
240 foreach my $type ( @Type_Order ) {
241 $list = join(", ", sort @{$Kinds{$type}});
242 $typedesc = $Type_Description{$type} . ":";
249 ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
251 ~~ ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
253 ~~ ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
262 foreach my $func (sort_funcs(keys %Flavor)) {
263 my $desc = $Flavor{$func};
264 die "No types listed for $func" unless $Type{$func};
265 next if $Omit{$func};
266 print $fh join("\t", $func, (sort @{$Type{$func}}), $desc), "\n";
269 close $fh or die "Can't close '$temp': $!";
270 rename $temp, $real or die "Can't rename '$temp' to '$real': $!";