Acme::Pythonic - Python whitespace conventions for Perl
use Acme::Pythonic; # this semicolon yet needed sub delete_edges: my $G = shift while my ($u, $v) = splice(@_, 0, 2): if defined $v: $G->delete_edge($u, $v) else: my @e = $G->edges($u) while ($u, $v) = splice(@e, 0, 2): $G->delete_edge($u, $v)
Acme::Pythonic is a source filter that brings Python whitespace conventions to Perl.
This module is thought for those who embrace contradictions. A humble aid for walkers of the Whitespace Matters Way in their pursuit of highest realization, only attained with SuperPython.
This is the Acme::Pythonic version of the example in perlsyn:
OUTER: for my $wid in @ary1: INNER: for my $jet in @ary2: next OUTER if $wid > $jet $wid += $jet
Labeled blocks work as well:
my $k = 7 FOO: --$k last FOO if $k < 0 redo FOO
Note that if we put a label in the line before in a control structure indentation matters. This would be a non-equivalent reformat of the example above:
OUTER: for my $wid in @ary1: # NOT WHAT WE WANT INNER: for my $jet in @ary2: # GOOD, ALIGNED next OUTER if $wid > $jet $wid += $jet
Since the first for is indented with respect to OUTER: we get a labeled block containing a for loop, instead of a labeled for.
for
OUTER:
Labels can be composed just of upper-case letters. That was decided so that list operators can be chained:
my @st = map: $_->[0] sort: $a->[1] <=> $b->[1] map: [$_, $foo{$_}] keys %foo
do/while
Acme::Pythonic tries to detect loop modifiers after a do BLOCK. Thus
do: do_something() do_something_else() while $condition
is seen as a do/while, whereas
do: do_something() do_something_else() while $condition: handle_some_stuff()
is not.
To be able to have an empty block we provide pass:
pass
sub abstract_method: pass
This works:
foreach my $foo @array: do_something_with $foo
However in is supported in case you find the following more readable
in
foreach my $foo in @array: do_something_with $foo
This keyword can be used if there's no variable to its left too, which means we are dealing with $_ as usual:
$_
foreach in @array: s/foo/bar/
but can't be used when the loop acts as a modifier:
print foreach in @array # ERROR
&-prototyped subroutines can be used like this:
&
sub mygrep (&@): my $code = shift my @result foreach @_: push @result, $_ if &$code return @result @array = mygrep: my $aux = $_ $aux *= 3 $aux += 1 $aux % 2 reverse 0..5
If the prototype is exactly &, however, Acme::Pythonic needs to know it because it might need to add a semicolon after the closing bracket in the generated code.
Thus, if any module defines such a subroutine use() it before Acme::Pythonic:
use()
use Thread 'async'; use Acme::Pythonic; # now Acme::Pythonic knows async() has prototype "&" async: do_this() do_that()
If such a subroutine is defined in the very code being filtered declare it before Acme::Pythonic is use()d:
sub twice (&); # declaration use Acme::Pythonic; # now it knows twice() has prototype "&" sub twice (&): # the definition itself can be Pythonic my $code = shift $code->() for 1..2 twice: do_this_twice()
Nevertheless, the module is not smart enough to handle optional arguments as in a subroutine with prototype &;$.
&;$
As in Python, you can break a logical line in several physical lines using a backslash at the end:
my $total = total_products() + \ total_delivery() + \ total_taxes()
and in that case the indentation of those additional lines is irrelevant.
Unlike Python, backslashes in a line with a comment are allowed
my $foo = 1 + \ # comment, no problem 2
In Python that's a syntax error, but I think that's more in the line of Perl forgiveness.
If a line ends in a comma or arrow (=>) it is conceptually joined with the following as well:
=>
my %authors = (Perl => "Larry Wall", Python => "Guido van Rossum")
As in Python, comments can be intermixed there:
my %hello = (Catalan => 'Hola', # my mother tongue English => 'Hello',)
Keywords followed by code in the same line are not supported. This would be valid in Python:
not
if $n % 2: $n = 3*$n + 1 else: $n /= 2
but it does not work in Acme::Pythonic. The reason for this is that it would be hard to identify the colon that closes the expression without parsing Perl, consider for instance:
if keys %foo::bar ? keys %main:: : keys %foo::: print "foo\n"
You can pass a debug flag to Acme::Pythonic like this:
debug
use Acme::Pythonic debug => 1;
In debug mode the module prints to standard output the code it has generated and substitutes everything with a dummy 1;, so nothing gets executed. This way the resulting source can be inspected.
1;
The module tries to generate human readable code following perlstyle. Blank lines and comments are preserved.
This happens before Filter::Simple undoes the blanking out of PODs, strings, and regexps. Those parts are marked with the label BLANKED_OUT for easy identification.
BLANKED_OUT
This module uses a regexp approach and the superb help of Filter::Simple. The regexp part of this means it is broken from the start, though I've tried hard to make it as robust as I could. Bug reports will be very welcome, just drop me a line!
Damian Conway gave his full blessing if I wanted to write a module like this based on his unpublished Language::Pythonesque. The code that handles indentation is inspired by his.
Also, Dr. Conway is the author of Filter::Simple, which aids a lot blanking out PODs, strings, etc. so you can munge the source with certain confidence. Without Filter::Simple this module would be infinitely more broken.
perlfilter, Filter::Simple, SuperPython.
Xavier Noria (FXN), <fxn@cpan.org>
Copyright (C) 2004 by Xavier Noria
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.8.2 or, at your option, any later version of Perl 5 you may have available.
To install Acme::Pythonic, copy and paste the appropriate command in to your terminal.
cpanm
cpanm Acme::Pythonic
CPAN shell
perl -MCPAN -e shell install Acme::Pythonic
For more information on module installation, please visit the detailed CPAN module installation guide.