Skip Menu |

This queue is for tickets about the Perl-Tidy CPAN distribution.

Report information
The Basics
Id: 123749
Status: resolved
Priority: 0/
Queue: Perl-Tidy

People
Owner: Nobody in particular
Requestors: sri [...] cpan.org
Cc:
AdminCc:

Bug Information
Severity: (no value)
Broken in: (no value)
Fixed in: (no value)



Subject: Problem with promises
The Mojolicious project has recently adopted promises and many of our users will soon be using them. Sadly it appears that perltidy can't handle the most commonly used ->then constructs without making a bit of a mess. get('http://mojolicious.org')->then(sub { my $mojo = shift; say $mojo->res->code; return get('http://metacpan.org'); })->then(sub { my $cpan = shift; say $cpan->res->code; })->catch(sub { my $err = shift; warn "Something went wrong: $err"; })->wait; becomes get('http://mojolicious.org')->then( sub { my $mojo = shift; say $mojo->res->code; return get('http://metacpan.org'); } )->then( sub { my $cpan = shift; say $cpan->res->code; } )->catch( sub { my $err = shift; warn "Something went wrong: $err"; } )->wait; The project .perltidyrc is fairly unspectacular. We've tried finding options that make the result a little better, but failed so far. https://github.com/kraih/mojo/blob/master/.perltidyrc This is the result i would have expected. get('http://mojolicious.org')->then( sub { my $mojo = shift; say $mojo->res->code; return get('http://metacpan.org'); } )->then( sub { my $cpan = shift; say $cpan->res->code; } )->catch( sub { my $err = shift; warn "Something went wrong: $err"; } )->wait; Many in the community would prefer a result like the first example, which i realize might be close to impossible. Any improvements to formatting constructs like this would be greatly appreciated.
+1 on this. Would really like support for "->then(sub {", but any improvement from the current situation would be awesome!
Would really like to see support for this compact handling of callbacks in general.
Subject: Re: [rt.cpan.org #123749] Problem with promises
Date: Mon, 27 Nov 2017 08:01:38 -0800
To: "bug-Perl-Tidy [...] rt.cpan.org" <bug-Perl-Tidy [...] rt.cpan.org>
From: Steven Hancock <s7078hancock [...] gmail.com>
I think I can fix this. There are two issues. The first issue has to do with manipulating the "continuation indentation" of lines, and the second has to do with compacting the code. FIRST ISSUE: In perltidy there are two types of indentation, structural indentation specified by "i=n1" and continuation indentation specified by "ci=n2", where n1 and n2 are the number of spaces. Structural indentation is controlled by the nesting depth of braces and parens, and continuation indentation is used to add spaces to the latter parts of a line when a line broken because it exceeds the specified maximum line length. N1 and n2 may be any values, but it is recommended that n2 be about half of n1 to avoid problems in complex code. The default parameters are n1=4 and and n2=2 and give: get('http://mojolicious.org')->then( sub { my $mojo = shift; say $mojo->res->code; return get('http://metacpan.org'); } )->then( sub { my $cpan = shift; say $cpan->res->code; } )->catch( sub { my $err = shift; warn "Something went wrong: $err"; } )->wait; [I don't know if my leading spaces will be correct in the email, but you can reproduce this by turning off your default parameters with perltidy -npro]. It looks like the snippet which was sent used n1=n2=2, and the equality of these values causes the closing braces and parens to line up. A programming fix for this is to remove continuation indentation for lines of the form ")->then(". I looked at the perltidy source code and saw that it is actually supposed to be doing this but it is not because of a minor bug. This bug will be corrected in the next release, currently scheduled for early January. With the corrected code the snippet will look okay for any choice of n2. For n1=2 it will be: get('http://mojolicious.org')->then( sub { my $mojo = shift; say $mojo->res->code; return get('http://metacpan.org'); } )->then( sub { my $cpan = shift; say $cpan->res->code; } )->catch( sub { my $err = shift; warn "Something went wrong: $err"; } )->wait; SECOND ISSUE: The second point is that some programmers prefer vertically compact code and some don't. There are some vertical tightness flags in perltidy which give some flexibility, but they do not work for this type of code. Programming this type of formatting is surprisingly tricky, but I believe I can make a patch to handle this particular type of code. If so, it will be controlled by the existing vertical tightness flags. I will try to get this in the next release and will post a note here if I do. It would help if someone could give me a link to a representative source of this type of coding to use for testing. Steve On Sun, Nov 26, 2017 at 5:25 AM, Sebastian Riedel via RT < bug-Perl-Tidy@rt.cpan.org> wrote: Show quoted text
> Sun Nov 26 08:25:09 2017: Request 123749 was acted upon. > Transaction: Ticket created by SRI > Queue: Perl-Tidy > Subject: Problem with promises > Broken in: (no value) > Severity: (no value) > Owner: Nobody > Requestors: sri@cpan.org > Status: new > Ticket <URL: https://rt.cpan.org/Ticket/Display.html?id=123749 > > > > The Mojolicious project has recently adopted promises and many of our > users will soon be using them. Sadly it appears that perltidy can't handle > the most commonly used ->then constructs without making a bit of a mess. > > get('http://mojolicious.org')->then(sub { > my $mojo = shift; > say $mojo->res->code; > return get('http://metacpan.org'); > })->then(sub { > my $cpan = shift; > say $cpan->res->code; > })->catch(sub { > my $err = shift; > warn "Something went wrong: $err"; > })->wait; > > becomes > > get('http://mojolicious.org')->then( > sub { > my $mojo = shift; > say $mojo->res->code; > return get('http://metacpan.org'); > } > )->then( > sub { > my $cpan = shift; > say $cpan->res->code; > } > )->catch( > sub { > my $err = shift; > warn "Something went wrong: $err"; > } > )->wait; > > The project .perltidyrc is fairly unspectacular. We've tried finding > options that make the result a little better, but failed so far. > > https://github.com/kraih/mojo/blob/master/.perltidyrc > > This is the result i would have expected. > > get('http://mojolicious.org')->then( > sub { > my $mojo = shift; > say $mojo->res->code; > return get('http://metacpan.org'); > } > )->then( > sub { > my $cpan = shift; > say $cpan->res->code; > } > )->catch( > sub { > my $err = shift; > warn "Something went wrong: $err"; > } > )->wait; > > Many in the community would prefer a result like the first example, which > i realize might be close to impossible. Any improvements to formatting > constructs like this would be greatly appreciated. >
Show quoted text
> I think I can fix this. There are two issues. The first issue has to do > with manipulating the "continuation indentation" of lines, and the second > has to do with compacting the code.
Thank you, can't wait for the next release! Show quoted text
> It would help if someone could give me a link to a representative source of > this type of coding to use for testing.
This is a little tricky right now. Since all Mojolicious code is required to run through perltidy we use workarounds without method chains in actual code, like this: my $promise = Mojo::Promise->new; my $promise2 = $promise->then( sub { ... } ); $promise2->catch( sub { ... } ); Aside from the case that started all of this, and which has some more variations in the Mojo::Promise documentation (http://mojolicious.org/perldoc/Mojo/Promise#SYNOPSIS), there are four more cases i can think of right now: # First: two closures $promise->then(sub { my @value = @_; say "The result is $value[0]"; return @value; }, sub { my @reason = @_; warn "Something went wrong: $reason[0]"; return @reason; }); # Second: mixed arguments $promise->then( undef, sub { my @reason = @_; warn "Something went wrong: $reason[0]"; return @reason; } ); # Third: mixed arguments with fat comma $e->on(test => sub { my ($e, $foo) = @_; say $foo; }); # Fourth: mixed arguments with multiple fat commas $e->on( test => sub { my ($e, $foo) = @_; say $foo; }, test2 => sub { my ($e, $bar) = @_; say $bar; } );
Show quoted text
> # First: two closures > $promise->then(sub { > my @value = @_; > say "The result is $value[0]"; > return @value; > }, > sub { > my @reason = @_; > warn "Something went wrong: $reason[0]"; > return @reason; > });
Honestly, i'm not even sure if this is the right way to present this kind of code. $promise->then( sub { my @value = @_; say "The result is $value[0]"; return @value; }, sub { my @reason = @_; warn "Something went wrong: $reason[0]"; return @reason; } ); While i do like vertical tightness a lot, it does feel more correct formatted this way.
Show quoted text
> I looked at the perltidy source code and saw that it > is actually supposed to be doing this but it is not because of a minor bug. > This bug will be corrected in the next release, currently scheduled for > early January.
Is the code publicly available somewhere? GitHub? I'd really like to test it.
Subject: Re: [rt.cpan.org #123749] Problem with promises
Date: Sat, 2 Dec 2017 14:34:25 -0800
To: "bug-Perl-Tidy [...] rt.cpan.org" <bug-Perl-Tidy [...] rt.cpan.org>
From: Steven Hancock <s7078hancock [...] gmail.com>
I'm afraid not. But I can move the release date up to Dec 14 to get it out sooner. I think I'm done coding and just have to run a lot more tests. I'm using the Promises code for testing, and Perl/TK code is also good for testing. There is a new flag to control the "tightness" of chained method calls which I am tentatively calling 'method-chain-tightness' for lack of a better word. mct=0 default (least tight; )->then( on single line mct=2 tight: )->then( joins with previous } and following anonymous sub mct=1 follows example of input file The default setting of least tight looks pretty good on all code I've tested so far. The tighter calls with mct=2 look good in simple cases such as Example 1 below but run into trouble with complex code, such as when a method takes more than one anonymous sub as argument as in Example 2 below. It's hard to fix that. So the tight version is probably only useful when working with a certain limited type of chained method calls. The flag value mct=1 follows the input line breaks and might be useful for someone who wants more control. Also, the separate closing and opening "tightnesses" can be individually controlled if desired. EXAMPLE 1 with default, mct=0 get( 'http://mojolicious.org' )->then( sub { my $mojo = shift; say $mojo->res->code; return get('http://metacpan.org'); } )->then( sub { my $cpan = shift; say $cpan->res->code; } )->catch( sub { my $err = shift; warn "Something went wrong: $err"; } )->wait; EXAMPLE 1 with perltidy -mct=2 get('http://mojolicious.org')->then( sub { my $mojo = shift; say $mojo->res->code; return get('http://metacpan.org'); } )->then( sub { my $cpan = shift; say $cpan->res->code; } )->catch( sub { my $err = shift; warn "Something went wrong: $err"; } )->wait; Example 2 with default parameters: fetch_it( 'http://en.wikipedia.org/w/api.php?action=opensearch&format=json&search= ' . url_encode( $ARGV[0] ) )->then( sub { my $data = shift; collect( map { fetch_it( 'http://en.wikipedia.org/w/api.php?action=query&format=json&titles=' . url_encode($_) . '&prop=info&inprop=url' ) } @{ $data->[1] } ); }, sub { $cv->croak('ERROR') } )->then( sub { $cv->send( map { ( values %{ $_->[0]->{'query'}->{'pages'} } )[0]->{'fullurl'} } @_ ); }, sub { $cv->croak('ERROR') } ); Example2 with perltidy -mct=2 fetch_it( 'http://en.wikipedia.org/w/api.php?action=opensearch&format=json&search= ' . url_encode( $ARGV[0] ) )->then( sub { my $data = shift; collect( map { fetch_it( 'http://en.wikipedia.org/w/api.php?action=query&format=json&titles=' . url_encode($_) . '&prop=info&inprop=url' ) } @{ $data->[1] } ); }, sub { $cv->croak('ERROR') } )->then( sub { $cv->send( map { ( values %{ $_->[0]->{'query'}->{'pages'} } )[0]->{'fullurl'} } @_ ); }, sub { $cv->croak('ERROR') } ); Steve On Sat, Dec 2, 2017 at 10:08 AM, Sebastian Riedel via RT < bug-Perl-Tidy@rt.cpan.org> wrote: Show quoted text
> Queue: Perl-Tidy > Ticket <URL: https://rt.cpan.org/Ticket/Display.html?id=123749 > >
> > I looked at the perltidy source code and saw that it > > is actually supposed to be doing this but it is not because of a minor
> bug.
> > This bug will be corrected in the next release, currently scheduled for > > early January.
> > Is the code publicly available somewhere? GitHub? I'd really like to test > it. >
Subject: Re: [rt.cpan.org #123749] Problem with promises
Date: Sat, 2 Dec 2017 14:53:16 -0800
To: "bug-Perl-Tidy [...] rt.cpan.org" <bug-Perl-Tidy [...] rt.cpan.org>
From: Steven Hancock <s7078hancock [...] gmail.com>
Some extra line breaks found their way into the last snippet of my email. It isn't quite that bad. Steve On Sat, Dec 2, 2017 at 2:34 PM, Steven Hancock via RT < bug-Perl-Tidy@rt.cpan.org> wrote: Show quoted text
> Queue: Perl-Tidy > Ticket <URL: https://rt.cpan.org/Ticket/Display.html?id=123749 > > > I'm afraid not. But I can move the release date up to Dec 14 to get it out > sooner. I think I'm done coding and just have to run a lot more tests. I'm > using the Promises > code for testing, and Perl/TK code is also good for testing. There is a new > flag to control the "tightness" of chained method calls which I am > tentatively calling > 'method-chain-tightness' for lack of a better word. > > mct=0 default (least tight; )->then( on single line > > mct=2 tight: )->then( joins with previous } and following anonymous sub > > mct=1 follows example of input file > > The default setting of least tight looks pretty good on all code I've > tested so far. The tighter calls with mct=2 > look good in simple cases such as Example 1 below but run into trouble with > complex code, such as when a method takes more than one anonymous sub as > argument as in Example 2 below. It's hard to fix that. > So the tight version is probably only useful when working with a certain > limited type of chained method calls. > > The flag value mct=1 follows the input line breaks and might be useful for > someone who wants more control. > > Also, the separate closing and opening "tightnesses" can be individually > controlled if desired. > > > EXAMPLE 1 with default, mct=0 > > get( 'http://mojolicious.org' )->then( > sub { > my $mojo = shift; > say $mojo->res->code; > return get('http://metacpan.org'); > } > )->then( > sub { > my $cpan = shift; > say $cpan->res->code; > } > )->catch( > sub { > my $err = shift; > warn "Something went wrong: $err"; > } > )->wait; > > EXAMPLE 1 with perltidy -mct=2 > > get('http://mojolicious.org')->then( sub { > my $mojo = shift; > say $mojo->res->code; > return get('http://metacpan.org'); > } )->then( sub { > my $cpan = shift; > say $cpan->res->code; > } )->catch( sub { > my $err = shift; > warn "Something went wrong: $err"; > } )->wait; > > Example 2 with default parameters: > > fetch_it( > 'http://en.wikipedia.org/w/api.php?action=opensearch& > format=json&search= > ' > . url_encode( $ARGV[0] ) )->then( > sub { > my $data = shift; > collect( > map { > fetch_it( > 'http://en.wikipedia.org/w/api.php?action=query&format=json&titles=' > . url_encode($_) > . '&prop=info&inprop=url' ) > } @{ $data->[1] } > ); > }, > sub { $cv->croak('ERROR') } > )->then( > sub { > $cv->send( > map { > ( values %{ $_->[0]->{'query'}->{'pages'} } > )[0]->{'fullurl'} > } @_ > ); > }, > sub { $cv->croak('ERROR') } > ); > > > Example2 with perltidy -mct=2 > > fetch_it( > 'http://en.wikipedia.org/w/api.php?action=opensearch& > format=json&search= > ' > . url_encode( $ARGV[0] ) )->then( sub { > my $data = shift; > collect( > map { > fetch_it( > 'http://en.wikipedia.org/w/api.php?action=query&format=json&titles=' > . url_encode($_) > . '&prop=info&inprop=url' ) > } @{ $data->[1] } > ); > }, > sub { $cv->croak('ERROR') } )->then( sub { > $cv->send( > map { > ( values %{ $_->[0]->{'query'}->{'pages'} } > )[0]->{'fullurl'} > } @_ > ); > }, > sub { $cv->croak('ERROR') } ); > > Steve > > On Sat, Dec 2, 2017 at 10:08 AM, Sebastian Riedel via RT < > bug-Perl-Tidy@rt.cpan.org> wrote: >
> > Queue: Perl-Tidy > > Ticket <URL: https://rt.cpan.org/Ticket/Display.html?id=123749 > > >
> > > I looked at the perltidy source code and saw that it > > > is actually supposed to be doing this but it is not because of a minor
> > bug.
> > > This bug will be corrected in the next release, currently scheduled for > > > early January.
> > > > Is the code publicly available somewhere? GitHub? I'd really like to test > > it. > >
> >
Version 20171214 has a fix to remove continuation indentation at lines such as ')->then('. This will help make the structure clearer in most cases. For example: # perltidy -i=2 -ci=2 get('http://mojolicious.org')->then( sub { my $mojo = shift; say $mojo->res->code; return get('http://metacpan.org'); } )->then( sub { my $cpan = shift; say $cpan->res->code; } )->catch( sub { my $err = shift; warn "Something went wrong: $err"; } )->wait; A new flag to make compact coding turns out to be straightforward but must to be postponed to the next release because it requires some reorganization of perltidy to allow another pass through the source code to do it correctly in all cases. I hope to release it in about two months.
Show quoted text
> Version 20171214 has a fix to remove continuation indentation at lines > such as ')->then('. This will help make the structure clearer in most > cases. > For example: > > # perltidy -i=2 -ci=2 > get('http://mojolicious.org')->then( > sub { > my $mojo = shift; > say $mojo->res->code; > return get('http://metacpan.org'); > } > )->then( > sub { > my $cpan = shift; > say $cpan->res->code; > } > )->catch( > sub { > my $err = shift; > warn "Something went wrong: $err"; > } > )->wait;
Thank you, very much appreciated!
Use the flag -wn (--weld-nested_containers) in version 20180101. For example: # perltidy -wn get('http://mojolicious.org')->then( sub { my $mojo = shift; say $mojo->res->code; return get('http://metacpan.org'); } )->then( sub { my $cpan = shift; say $cpan->res->code; } )->catch( sub { my $err = shift; warn "Something went wrong: $err"; } )->wait; This flag should handle all variations in a reasonable way. The man page has more information. Steve
Am So 31. Dez 2017, 10:54:49, SHANCOCK schrieb: Show quoted text
> Use the flag -wn (--weld-nested_containers) in version 20180101. For > example: > > # perltidy -wn > get('http://mojolicious.org')->then( sub { > my $mojo = shift; > say $mojo->res->code; > return get('http://metacpan.org'); > } )->then( sub { > my $cpan = shift; > say $cpan->res->code; > } )->catch( sub { > my $err = shift; > warn "Something went wrong: $err"; > } )->wait; > > This flag should handle all variations in a reasonable way. The man > page has more information. > Steve
I ran perltidy with the new -wn flag against all of Mojolicious, and it appears we've stumbled over a bug. https://github.com/kraih/mojo/commit/b815d5666f2b255e2914363d05fc6c80f2ccd9aa#diff-8a580e4a5afea12ec1e70217519b306aL208 It now completely removes the indentation from such continuation lines.
Subject: Re: [rt.cpan.org #123749] Problem with promises
Date: Wed, 3 Jan 2018 06:14:20 -0800
To: bug-Perl-Tidy [...] rt.cpan.org
From: Steven Hancock <s7078hancock [...] gmail.com>
Sebastian, I'm not quite following you, can you clarify this? Steve On Wed, Jan 3, 2018 at 5:14 AM, Sebastian Riedel via RT < bug-Perl-Tidy@rt.cpan.org> wrote: Show quoted text
> Queue: Perl-Tidy > Ticket <URL: https://rt.cpan.org/Ticket/Display.html?id=123749 > > > Am So 31. Dez 2017, 10:54:49, SHANCOCK schrieb:
> > Use the flag -wn (--weld-nested_containers) in version 20180101. For > > example: > > > > # perltidy -wn > > get('http://mojolicious.org')->then( sub { > > my $mojo = shift; > > say $mojo->res->code; > > return get('http://metacpan.org'); > > } )->then( sub { > > my $cpan = shift; > > say $cpan->res->code; > > } )->catch( sub { > > my $err = shift; > > warn "Something went wrong: $err"; > > } )->wait; > > > > This flag should handle all variations in a reasonable way. The man > > page has more information. > > Steve
> > I ran perltidy with the new -wn flag against all of Mojolicious, and it > appears we've stumbled over a bug. > > https://github.com/kraih/mojo/commit/b815d5666f2b255e2914363d05fc6c > 80f2ccd9aa#diff-8a580e4a5afea12ec1e70217519b306aL208 > > It now completely removes the indentation from such continuation lines. > >
Show quoted text
> Sebastian, I'm not quite following you, can you clarify this?
I can't imagine it's supposed to generate these two lines without any indentation. $headers->from_hash( {'X-Test' => [23, 24], 'X-Test2' => 'foo', Connection => ['a', 'b']});
Subject: Re: [rt.cpan.org #123749] Problem with promises
Date: Wed, 3 Jan 2018 18:32:20 -0800
To: bug-Perl-Tidy [...] rt.cpan.org
From: Steven Hancock <s7078hancock [...] gmail.com>
OK, I see. This is a glitch in which the -wn logic is in conflict with logic which tries to keep long one-line blocks, such as {'X-Test' => [23, 24], 'X-Test2' => 'foo', Connection => ['a', 'b']}. I also noticed it in testing too and will work out a fix. It generally only happens with two lines of code. If you do not use -iob (--ignore-old-breakpoints) and the inner block is broken in the input to perltidy in any way, such as $headers->from_hash( {'X-Test' => [23, 24], 'X-Test2' => 'foo', Connection => ['a', 'b']}) They the block will stay broken with -wn and you will get: perltidy -wn $headers->from_hash( { 'X-Test' => [ 23, 24 ], 'X-Test2' => 'foo', Connection => [ 'a', 'b' ] } ) And this result is stable. However, if you don't let perltidy see old breakpoints it will try to form the one line block and give the first result. The fix will be to ignore the one-line block rule when the block is part of a weld. Steve On Wed, Jan 3, 2018 at 5:43 PM, Sebastian Riedel via RT < bug-Perl-Tidy@rt.cpan.org> wrote: Show quoted text
> Queue: Perl-Tidy > Ticket <URL: https://rt.cpan.org/Ticket/Display.html?id=123749 > >
> > Sebastian, I'm not quite following you, can you clarify this?
> > I can't imagine it's supposed to generate these two lines without any > indentation. > > $headers->from_hash( > {'X-Test' => [23, 24], 'X-Test2' => 'foo', Connection => ['a', 'b']}); > > >
Subject: Re: [rt.cpan.org #123749] Problem with promises
Date: Wed, 3 Jan 2018 18:44:33 -0800
To: bug-Perl-Tidy [...] rt.cpan.org
From: Steven Hancock <s7078hancock [...] gmail.com>
The fix for this was trivial and it will be in the next release. Steve On Wed, Jan 3, 2018 at 6:32 PM, Steven Hancock via RT < bug-Perl-Tidy@rt.cpan.org> wrote: Show quoted text
> Queue: Perl-Tidy > Ticket <URL: https://rt.cpan.org/Ticket/Display.html?id=123749 > > > OK, I see. This is a glitch in which the -wn logic is in conflict with > logic which tries to keep long one-line blocks, such as > {'X-Test' => [23, 24], 'X-Test2' => 'foo', Connection => ['a', 'b']}. I > also noticed it in testing too and will work out > a fix. It generally only happens with two lines of code. > > If you do not use -iob (--ignore-old-breakpoints) and the inner block is > broken in the input to perltidy in any way, such as > > $headers->from_hash( > {'X-Test' => [23, 24], 'X-Test2' => 'foo', > Connection => ['a', 'b']}) > > They the block will stay broken with -wn and you will get: > > perltidy -wn > $headers->from_hash( { > 'X-Test' => [ 23, 24 ], > 'X-Test2' => 'foo', > Connection => [ 'a', 'b' ] > } ) > > And this result is stable. However, if you don't let perltidy see old > breakpoints it will try to form the one line block > and give the first result. > > The fix will be to ignore the one-line block rule when the block is part of > a weld. > Steve > > > On Wed, Jan 3, 2018 at 5:43 PM, Sebastian Riedel via RT < > bug-Perl-Tidy@rt.cpan.org> wrote: >
> > Queue: Perl-Tidy > > Ticket <URL: https://rt.cpan.org/Ticket/Display.html?id=123749 > > >
> > > Sebastian, I'm not quite following you, can you clarify this?
> > > > I can't imagine it's supposed to generate these two lines without any > > indentation. > > > > $headers->from_hash( > > {'X-Test' => [23, 24], 'X-Test2' => 'foo', Connection => ['a',
> 'b']});
> > > > > >
> >
The -wn option has been improved in version 20180219