6

Is there a way to measure POD coverage for scripts (e.g. *.pl)?

I can measure documentation coverage for packages using Pod::Coverage and Test::Pod::Coverage, but I cannot measure it for scripts, because Pod::Coverage and the underlying Devel::Symdump use require to inspect the content of the package, which fails due to the lack of a .pm file.

Is there a way to work around this?

(I have to have POD documentation in the .pl files, so moving everything into a module and documenting it there is not a good solution for me. Wherever I could do that, it's already done that way.)

Jonas
  • 121,568
  • 97
  • 310
  • 388
battery
  • 511
  • 2
  • 8

2 Answers2

4

Pod::Coverage loads (executes) the module to let it create subs and such. You would have to prevent your .pl from running normally somehow.

#!/usr/bin/perl
...
main(@ARGV) if !$ENV{NO_RUN};
1; # For do()

But once you've done that, it's easy because you tell Pod::Coverage which package to examine (package) and which file to examine (pod_from).

#!/usr/bin/perl

use strict;
use warnings;

use Test::More tests => 1;

use Pod::Coverage qw( );

{
    package the_script;
    local $ENV{NO_RUN} = 1;
    do "script.pl" or die $@;
}

my $pc = Pod::Coverage->new(
   package  => 'the_script',
   pod_from => 'script.pl',
);

# P::C expects "require the_script;" to succeed.
$INC{"the_script.pm"} = 1;

my $coverage = $pc->coverage();
die $pc->why_unrated()
   if !defined($coverage);

ok($coverage)
   or diag("Not covered: ".join(', ', $pc->naked()));

1;

Tested.

ikegami
  • 367,544
  • 15
  • 269
  • 518
  • I like the idea, I'll try it out, and report back.I'd upvote, but I'm too much of a newcomer at the moment... :) – battery Sep 25 '12 at 16:04
  • The coverage is `undef`, and the reason reported by `$pc->why_unrated()` is `no public symbols defined`. I encountered this error also with modules: there I had to change `package Bar` to `package Foo::Bar`, and that solved the problem. But I'm not quite sure how to change `package the_script` in this case. I'll give it another go tomorrow... – battery Sep 25 '12 at 17:07
  • genius! Works like a charm! Augmenting all the scripts with the `$ENV{NO_RUN}` check is a one-time pain I'm willing to accept. Thanks for your quick help! And I actually learned some new stuff about `do` today, so another +1 for that! :) – battery Sep 25 '12 at 17:24
  • 1
    Make it main(@ARGV) unless caller – jira Sep 25 '12 at 22:14
  • @jira, There are instances where that gives a false positive. Aside from the obvious impossibility of launching your script via `do`, I mean. I can't remember what exactly, though. Maybe it's when the script is run in the debugger? I'll keep the current code; it works just as well and has no downsides. – ikegami Sep 25 '12 at 22:17
  • @jira, @ikegami, @brian-d-foy: I checked `perl -d script.pl`, and indeed, `caller()` returns `DB/usr/share/perl/5.14/perl5db.pl640` inside the debugger. However, it seems to be working well with `do`. – battery Sep 26 '12 at 08:59
4

Make your program a modulino. That's what ikegami is doing, but he makes you set an environment variable.

run(@ARGV) unless caller;

Once your program is really a module with some default behavior, you can use module tools on it.

Community
  • 1
  • 1
brian d foy
  • 129,424
  • 31
  • 207
  • 592
  • Unfortunately I cannot use the whole modulino concept in the short run, as I have to keep the executable `.pl` files for historical reasons. But I will use it for new scripts for sure and start to rework older scripts as I happen to touch them. – battery Sep 25 '12 at 22:36
  • Sure you can use it. The file is still a program and you can name it whatever you like, but you can also load it like a module. – brian d foy Sep 28 '12 at 00:41
  • I read through http://www.drdobbs.com/scripts-as-modules/184416165 again, and indeed it will be simpler to take it into use than I first realized. Thanks for nudging me, and not giving up! :) – battery Sep 28 '12 at 06:01
  • 1
    however, I'm still leaning towards @ikegami's environment variable based solution due to `caller()` returning `true` under a debugger (at least `perl -d`). Do you have a trick for that up in your sleeves too? :) – battery Sep 28 '12 at 06:04