diotalevi has asked for the wisdom of the Perl Monks concerning the following question:

I recently found it convenient to generate a pile of templated functions. I'd like to also generate the pod for this. I don't know of any obvious way to get this. I included two samples that describe what I'd like to have "just work." Neither do. The first fails because the pod is just ignored by the eval and perldoc never sees it either. The latter fails because perldoc ignores .pmc files.

Any ideas on how to get this to work?

Non-working idea #1:

BEGIN { for my $nm (qw( io fm cv hv pvlv gv av bm pvmg pvnv pviv rv nv iv +pv sv )) { eval <<"B_SUGAR"; =item \L$nm\E( OBJ ) Returns a boolean indicating whether OBJ is an instance of type B::\U$ +nm\E. This respects any overridden ->isa methods. =cut sub \L$nm\E { my \$op = shift \@_; return blessed(\$op) and \$op->isa('B::\U$nm\E'); } B_SUGAR if ( my $e = $@ ) { die $e; } push @EXPORT_OK, $nm; } }

Non-working idea #2

use tt ( subs => [qw( io fm cv hv pvlv gv av bm pvmg pvnv pviv rv nv i +v pv sv )] ); [% FOREACH sub IN subs %] =item [% sub %]( OBJ ) Returns a boolean indicating whether OBJ is an instance of type B::[% +sub %]. This respects any overridden ->isa methods. =cut sub [% sub %] { my $op = shift @_; return blessed($op) and $op->isa('B::[% sub %]'); } [% END %] no tt;

( The above was originally just one example with some questionable indentation. It was changed to the current form within a few minutes.)

Replies are listed 'Best First'.
Re: Templating pod generation?
by Zaxo (Archbishop) on Jul 19, 2006 at 06:30 UTC

    From CB conversation, it seems like you want this file to modify itself, generating the pod and methods. That is an evil desire.

    Ok, here's an evil thought to go with it.

    use Tie::File; tie my @file, 'Tie::File', $0 or die $!; splice @file, $begin_lineno, $begin_length, split $/, eval <<B_SUGAR; # etc.
    I wouldn't do it ;-)

    Every time I look at this, I see something more that needs doing to make it work. That's a bad sign. Take this a purely conceptual notion.

    After Compline,
    Zaxo

      I don't really want to have the file modify itself. That'd suck because people wouldn't expect it. I'd just like it to expand itself when looked at like a BEGIN block can do for perl code or macros do for lisp code. From other responses in this thread it looks like I'll have to stick with a separate template that just generates the pod and perl. It's not as nice but not difficult either. I just wanted the nicest possible world.

      ⠤⠤ ⠙⠊⠕⠞⠁⠇⠑⠧⠊

        That notion makes source filters look good, doesn't it? Quite an accomplishment, in a wicked kind of way ;-)

        After Compline,
        Zaxo

Re: Templating pod generation?
by Aristotle (Chancellor) on Jul 19, 2006 at 06:14 UTC

    No, that won’t work. Generally, you have to generate your POD statically, else it won’t be understood by POD processors. So why not document them all once, instead of repetitively documenting each with the same boilerplate?

    =head2 io( OBJ ) =head2 fm( OBJ ) =head2 cv( OBJ ) =head2 hv( OBJ ) =head2 pvlv( OBJ ) =head2 gv( OBJ ) =head2 av( OBJ ) =head2 bm( OBJ ) =head2 pvmg( OBJ ) =head2 pvnv( OBJ ) =head2 pviv( OBJ ) =head2 rv( OBJ ) =head2 nv( OBJ ) =head2 iv( OBJ ) =head2 pv( OBJ ) =head2 sv( OBJ ) Returns a boolean indicating whether OBJ is an instance of the B:: cla +ss indicated by the method name, and respects any overridden C<-E<gt> +isa> methods.

    Granted, that’s not entirely DRY. For that, you could try turning your question on its head by parsing your own POD at load time in order to get the list of functions to generate. (I also enjoy Pod::Constants, but it doesn’t fit your use case.)

    PS.: your use of eval is unnecessary:

    for my $nm ( qw( io fm cv hv pvlv gv av bm pvmg pvnv pviv rv nv iv pv +sv ) ) { my $nm_pkg = "B::$nm"; *{ $nm } = sub { my $op = shift @_; return blessed( $op ) and $op->isa( $nm_pkg ); } }

    Makeshifts last the longest.

      The eval means my functions have real names, not ANON in the __ANON__ package. I hadn't considered parsing my own pod to get the list of methods to generate but uh... that's possible I guess.

      ⠤⠤ ⠙⠊⠕⠞⠁⠇⠑⠧⠊

        Ah, right.

        for my $nm ( qw( io fm cv hv pvlv gv av bm pvmg pvnv pviv rv nv iv pv +sv ) ) { my $nm_pkg = "B::$nm"; *{ $nm } = sub { local *__ANON__ = $nm; my $op = shift @_; return blessed( $op ) and $op->isa( $nm_pkg ); } }

        As for the POD, think about it: the POD processor is just reading the file. How would it know where to look for what gets seen by the perl compiler at one stage or other when the file is compiled? (Short of solving the halting problem, anyway…) It would have to invoke the compiler on the file and then somehow hook into eval, which isn’t trivial, since CORE::eval has a variable prototype, and it certainly wouldn’t be very safe. So to cover such cases there would have to be some form of templating built into POD itself. And while it might be worthwhile to think about that, that won’t solve your problem.

        Makeshifts last the longest.

Re: Templating pod generation?
by xdg (Monsignor) on Jul 19, 2006 at 08:41 UTC

    The thing to remember is that Pod parsers don't execute code. Pod and Perl are just two languages that can live in the same file and each parser just ignores the other language. So you can't use Perl constructs or source filters to affect how Pod parsers see the file.

    However, you might be able to take advantage of the fact that perldoc will prefer a .pod file to a .pm file. For an example of how that could work, consider Pod::WikiDoc.

    Pod::WikiDoc parses a .pm file containing "wikidoc" Pod format blocks when the distribution tarball is created and creates a matching .pod file with the wikidoc blocks converted to Pod. On installation, the .pod are what perldoc finds and end-users never need to know or care that I used Pod::WikiDoc to write my Pod.

    You could do something similar where some template Pod format block gets expanded into a separate .pod file. You just need to customize a Pod parser to pre-process the .pm file, process your templates, and stick the results into a .pod file.

    -xdg

    Code written by xdg and posted on PerlMonks is public domain. It is provided as is with no warranties, express or implied, of any kind. Posted code may not have been tested. Use of posted code is at your own risk.

      I thought pod parsers executed some code. I remember getting warnings when running perldoc as root that it was allowed to execute code.

      ⠤⠤ ⠙⠊⠕⠞⠁⠇⠑⠧⠊

        I thought pod parsers executed some code.

        Well, perldoc, the program, allows you to specify an arbitrary Pod parser to use for formatting. Pod parsers can do anything they want, including running malicious code. So I suspect that was the restriction on running as root.

        But I don't think that perlpodspec says anything about code execution -- that was my point about Pod and code being two separate languages.

        -xdg

        Code written by xdg and posted on PerlMonks is public domain. It is provided as is with no warranties, express or implied, of any kind. Posted code may not have been tested. Use of posted code is at your own risk.