NAME
Pod::Elemental::Transformer::ExampleRunner - include/run examples scripts in your documentation without copy/paste
VERSION
version 0.002
SYNOPSIS
Tell ExampleRunner
what to run. Insert =example
into your pod.
[-Transformer]
in your weaver.ini
:
[-Transformer]
transformer = ExampleRunner
command =example
along with [PodWeaver]
in your dist.ini
if you're Dist::Zilla inclined.
or use
it in a script
my $xform = Pod::Elemental::Transformer::ExampleRunner->new({qw[ command example script_path script/ ]});
$xform->transform_node($pod_elemental_document);
see example/examplerunner-doc
=example
commands in your pod
You can include script source or output in your pod, with a pod command like:
=example source showoff
for this dist, that would become something like:
#see ./example/showoff
#! /usr/bin/perl -w
#FOR: showing off the features of ExampleRunner
#...use libraries
use MyApp::Example;
my $app = MyApp::Example->new();
use SomeLib qw[ frobulate ];
#... read config files and do other stuff
print frobulate();
# an example of your module being used along with SomeLib
for (@SomeLib::Plugins) {
print "Setting up plugin: $_\n";
my $plugin_obj = SomeLib->factory( $_ );
#...feed $plugin_obj
$app->accept_frobulation( $_ => $plugin_obj->frobulate() );
}
$app->run(); # is now able to serve pre-frobulated results
#...
#end of listing
and if you wanted to run the script, and capture it's output, you'd use
=example run showoff
which would look something like this:
#running ./example/showoff
behold the awesome power of SomeLib's frobulate implementation
Setting up plugin: funky
Oh my! MyApp::Example::accept_frobulation is happening!
Setting up plugin: fresh
Oh my! MyApp::Example::accept_frobulation is happening!
Oh my! MyApp::Example::run is happening!
#.
KEEPING IT PUNCHY...
Often your example scripts will contain lots of boring setup code, by yada
ing this code out your examples stay runnable, and your docs stay focused on the features you're trying to explain...
If you want to just hide a couple of lines, use an inline-yada (consecutive lines lines matching yada_pattern
)... For more lengthy chunks of boring stuff use a multi-line yadas (delimited with yada_{start,end}
)
... with inline-yada
s
If a library wants you to pass in lots of options, and you need those options to make your example work, then keep them in your example script, but tell ExampleRunner
that they're boring and it'll yada
them out.
my $foo = ComplexLibrary->new({
plugins => {
often => { # boring
scratchdir => '/tmp/', # boring
with => [ qw[ --extra --support-large ]] # boring
}, # boring
sneaky => { # boring
mask_user => 1, # boring
show_full_name => 0, # boring
}, # boring
options => { # boring
no_laoder => 0 # boring
} # boring
}
});
# now we move on to code that's actually from my distribution... damn you ComplexLibrary!
and you'll get this in the pod:
my $foo = ComplexLibrary->new({
plugins => {
#...
}
});
# aah, that's a lot less cruft in my pod!
... with a multi-line yada
s
Now, that's a lot of # boring
in your script too, so you might want a multi-line yada
instead, like this:
my $foo = ComplexLibrary->new({
plugins => {
# {{{ ExampleRunnerHide ComplexLibrary requires lots of arguments!
often => {
scratchdir => '/tmp/',
with => [ qw[ --extra --support-large ]]
},
sneaky => {
mask_user => 1,
show_full_name => 0,
},
options => {
no_laoder => 0
}
# ExampleRunnerShow }}}
}
});
# now we move on to code that's actually from my distribution... damn you ComplexLibrary!
you'll still get:
my $foo = ComplexLibrary->new({
plugins => {
# ... ComplexLibrary requires lots of arguments!
}
});
# now more of this example is to do with my code than with ComplexLibrary's setup
If your yada_start
or yada_pattern
captures something, it'll be tacked on after the yada
marker.
Multiple consecutive lines matching yada_pattern
will be collapsed down to one yada
using the last <stuff>
captured
... SYNOPSIS
example without yada
s
Here is example/showoff
without the yada
blocks collapsed...
#running ./example/cat example/showoff
#! /usr/bin/perl -w
#FOR: showing off the features of ExampleRunner
use strict; # boring
use warnings; # boring
use lib 'somelib/lib'; # boring use libraries
use MyApp::Example;
my $app = MyApp::Example->new();
use SomeLib qw[ frobulate ];
# {{{ ExampleRunnerHide read config files and do other stuff
# the stuff in this block ( from yada_start to yada_end )
# will be stripped out of the source listed in your POD
# this way you can hide stuff that's not really that interesting
# things like setting up stubs that let your example run without real libs
# (for example, SomeLib doesn't really export frobulate)
sub frobulate {
"behold the awesome power of SomeLib's frobulate implementation\n"
}
=pod
you can do things in your examples that would require lots of tedious
configuration (say of a mysql server) that you really don't want to
force on your readers.
They get to see the a couple of runs of your scripts without having to
install everything, configure mysql and then find out your modules' not
as cool as they thought.
And, you don't have to re-run the scripts and copy/paste their output
every time you change them
=cut
# ExampleRunnerShow }}}
print frobulate();
# an example of your module being used along with SomeLib
for (@SomeLib::Plugins) {
print "Setting up plugin: $_\n";
my $plugin_obj = SomeLib->factory( $_ );
$plugin_obj->configure( SomeLib->configuration_for_plugin( $_ ) ); # boring
$plugin_obj->init; # boring feed $plugin_obj
$app->accept_frobulation( $_ => $plugin_obj->frobulate() );
}
$app->run(); # is now able to serve pre-frobulated results
# {{{ ExampleRunnerHide
#
# This script is exclusive and non-transferrable property of yada yada
# yada yada yada yada yada yada yada
#
# ExampleRunnerShow }}}
#.
man, tl;dr
!
MORE EXAMPLES
you might want to check out the awesome scripts in the example/
directory for this dist:
#running ./example/list-examples
list-examples lists the files in example/ (this script!)
cat runs cat on files - meow!
something-bad-happened to demonstrate what happens when ExampleRunner runs something that dies and spews stuff to STDERR
not-runnable demonstrate what happens when a script can't be run
examplerunner-doc format the pod in ExampleRunner with ExampleRunner
somelib-examples demonstrate ExampleRunner being used as more than one command on the same document
showoff showing off the features of ExampleRunner
#.
which obviously came from this script:
#see ./example/list-examples
:
#FOR: lists the files in example/ (this script!)
grep '#FOR:' $( find example/ -type f ) | perl -ne 'next if /Binary file/;s{example/}{}; printf qq[%-25s %s], split /:#FOR:/'
#end of listing
/somelib
in this dist is a fake distribution with docs ...
CONFIGURATION
These are the options you can set, and their defaults... you'd use these in your weaver.ini
:
[-Transformer]
transformer = ExampleRunner
script_path = example/ ; where I'll look for scripts to run/include
command = example ; which pod command I'll expand
indent = ' ' ; the indent I'll add to source/output
; multi-line yada blocks
yada_start = # {{{ ExampleRunnerHide(?: ([^\n]+))? ; start token, captures comment to be kept in pod
yada_end = # ExampleRunnerShow }}} ; end token
; single-line yada blocks
yada_pattern = # boring(?: ([^\n]+))? ; many lines matching these are considered a single yada
; all yadas are replaced with this, followed by the captures from above
yada_replace = #...
DIAGNOSTICS
If you find an empty block in place of your script's output, it could be one of...
permission denied
If you forget to make your scripts executable you'll get the message in the POD
# Couldn't run ./example/not-runnable: Permission denied
things going pear shaped in your script
If your perl script dies you'll likely just get an empty section where the script was (since STDERR is ignored), you see something similar happening in this script:
#see ./example/something-bad-happened
:
#FOR: to demonstrate what happens when ExampleRunner runs something that dies and spews stuff to STDERR
echo "oh noes!" >&2;
exit 1
#end of listing
#running ./example/something-bad-happened
## something-bad-happened exited with 1
EXTENDING
If you find this library even remotely useful, you're likely to want it to do a little more than just running/inlining scripts... or maybe you'll want to disable something...
All the behaviours are in separate subs...
=example foo
is dispatched to $self->_foo
, and the rest of the command is passed on so you can add new sub-commands by just adding a method to your subclass. the thing _foo
returns is spliced back into the document.
You can re-use the yada support by calling $self->remove_yadas_from($string)
, or remove it by replacing it with sub { return $_[1] }
.
FOLKS WHO HELPED OUT
Some of this is stolen from Pod::Elemental::Transformer::List
, but that doesn't mean rjbs
has anything to do with the horrible ideas behind this module.
both Apocalypse
and kentln
were helpful with the running ExampleRunner on ExampleRunner's docs during distribution confusion I had ...
BUGS
Please report any bugs or feature requests to bug-pod-elemental-transformer-examplerunner@rt.cpan.org or through the web interface at: http://rt.cpan.org/Public/Dist/Display.html?Name=Pod-Elemental-Transformer-ExampleRunner
AUTHOR
FOOLISH <FOOLISH@cpan.org>
COPYRIGHT AND LICENSE
This software is copyright (c) 2010 by FOOLISH.
This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.