Sometimes when I'm writing POD, I find that I want something like this:
use Test::More 'no_plan'; ok 1, '"1" is true'; is "foo", "foo", '"foo" equals itself'; __END__ ok 1 - "1" is true ok 2 - "foo" equals itself 1..2
In other words, I want a snippet of code with the output displayed after the __END__ block. However, that means copying the code to a file, pasting the code, fixing the inevitable errors, rerunning, copying the output, putting vim in paste mode, typing the __END__ token, pasting in the output and putting vim back in nopaste mode.
That's a pain. Now I can just type ,rs (run snippet) on a section of code which I've selected via cntl-v. The vim mapping is:
vnoremap,rs :!perl ~/bin/eval
And ~/bin/eval script is:
#!/usr/bin/env perl use strict; use warnings; use File::Temp 'tempfile'; # create a temporary perl script file my ( $fh, $snippet ) = tempfile( 'eval_XXXX', SUFFIX => '.pl', DIR => '/var/tmp' ); my $code = do { local $/;}; print $fh $code or die "Could not print code to ($snippet): $!"; close $fh or die "Could not close ($snippet): $!"; my $perl = $^X; print $code, " __END__\n"; my $output = ' ' . qx{ $perl $snippet 2>&1 }; $output =~ s/\n/\n /g; print $output;
That will run the snippet and automatically put the results after an __END__ token. This is a very dangerous (and fragile) technique, so use it with care.
Hey, that's nifty.
But having ~/bin/eval may get confusing, the name clashing with the buit-in shell command eval
. perleval
would be less confusing (and a longer name doesn't really matter, since your mapping does the typing for you).
Re:Nice, but Name Clash
Ovid on 2009-11-09T13:45:04
Ah, good point. I'll make a change locally. Thanks!
Nice idea. I used it in my
(defvar perl-run-snippet-command
"perl"
"Command for running perl for `perl-run-snippet'")
(defun perl-run-snippet (start end)
"Execute `perl-run-snippet-command' on the current region. Insert the results as comments."
(interactive "r")
(let ((buffer (current-buffer))
(snippet-result (generate-new-buffer "*perl-snippet*")))
(save-excursion
;; Run the snippet
(shell-command-on-region
start end
perl-run-snippet-command
snippet-result nil snippet-result)
;; Comment it out
(set-buffer snippet-result)
(goto-char (point-min))
(while (re-search-forward "^" nil t)
(replace-match "# "))
(set-buffer buffer)
;; Insert the snippet
(goto-char (max start end))
(insert-buffer snippet-result)
;; Clean up
(kill-buffer snippet-result))))
I find it a little more likely I'd rather just turn a snippet into example data for immediate use inline than something far removed at an __END__ tag. FWIW, to do something like that, you'd use commands like the below instead:
;; Either:
;; * goto the line after __END__
;; * goto the end and add an __END__ marker
;;
(if (re-search-forward "^__END__\n" nil t)
nil
(goto-char (point-max))
(if (not (bolp)) (insert "\n"))
(insert "__END__\n"))