Why not adopt me?
NAME
Acme::Pythonic - Python whitespace conventions for Perl
SYNOPSIS
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)
DESCRIPTION
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.
DETAILS
Labels
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
.
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
In addition, "BEGIN", "CHECK", "INIT", "END", cannot be labels because
BEGIN:
$foo = 3
is treated as a BEGIN block, for example.
do/while
-like constructs
Acme::Pythonic tries to detect statement 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.
New Keywords
pass
To be able to have an empty block we provide pass
:
sub abstract_method:
pass
in
This works:
foreach my $foo @array:
do_something_with $foo
However in
is supported in case you find the following more readable
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
&
-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 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 &;$
.
Line joining
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',)
LIMITATIONS
Keywords followed by code in the same line are not
supported. This would be valid in Python:
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"
DEBUG
You can pass a debug
flag to Acme::Pythonic like this:
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.
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.
BUGS
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!
THANKS
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.
SEE ALSO
perlfilter, Filter::Simple, SuperPython.
AUTHOR
Xavier Noria (FXN), <fxn@cpan.org>
COPYRIGHT AND LICENSE
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.