| PPIx-EditorTools documentation | Contained in the PPIx-EditorTools distribution. |
my $munged = PPIx::EditorTools::IntroduceTemporaryVariable->new->introduce(
code => "use strict; BEGIN {
$^W = 1;
}\n\tmy $x = ( 1 + 10 / 12 ) * 2;\n\tmy $y = ( 3 + 10 / 12 ) * 2;\n",
start_location => [ 2, 19 ],
end_location => [ 2, 25 ],
varname => '$foo',
);
my $modified_code_as_string = $munged->code;
my $location_of_new_var_declaration = $munged->element->location;
Given a region of code within a statement, replaces all occurrences of that code with a temporary variable. Declares and initializes the temporary variable right above the statement that included the selected expression.
Constructor. Generally shouldn't be called with any arguments.
Accepts either a PPI::Document to process or a string containing
the code (which will be converted into a PPI::Document) to process.
Given the region of code specified by start_location and end_location,
replaces that code with a temporary variable with the name given
in varname (defaults to tmp). Declares and initializes
the temporary variable right above the statement that included the
selected expression.
Returns a PPIx::EditorTools::ReturnObject with the modified code
as a string available via the code accessor (or as a PPI::Document
via the ppi accessor), and the PPI::Token where the new variable
is declared available via the element accessor.
Croaks with a "no token" exception if no token is found at the location. Croaks with a "no statement" exception if unable to find the statement.
This class inherits from PPIx::EditorTools.
Also see App::EditorTools, Padre, and PPI.
| PPIx-EditorTools documentation | Contained in the PPIx-EditorTools distribution. |
package PPIx::EditorTools::IntroduceTemporaryVariable; # ABSTRACT: Introduces a temporary variable using PPI use 5.008; use strict; use warnings; use Carp; use base 'PPIx::EditorTools'; use Class::XSAccessor accessors => { 'start_location' => 'start_location', 'end_location' => 'end_location', 'expression' => 'expression', 'location' => 'location', }; our $VERSION = '0.15';
sub introduce { my ( $self, %args ) = @_; $self->process_doc(%args); my $start_loc = $args{start_location} or croak "start_location required"; my $end_loc = $args{end_location} or croak "end_location required"; my $varname = $args{varname}; $varname = 'tmp' if not defined $varname; $varname = '$' . $varname if $varname !~ /^[\$\@\%]/; my $ppi = $self->ppi; $ppi->flush_locations; my $token = PPIx::EditorTools::find_token_at_location( $ppi, $start_loc ); $ppi->flush_locations; die "no token" unless $token; my $statement = $token->statement(); die "no statement" unless $statement; # walk up the PPI tree until we reach a sort of structure that's not a statement. # FIXME: This may or may not be robust. A PPI::Statement claims to be what's # defined as "statements" in perlsyn, but it's not! perlsyn says all statements # end in a semicolon unless at the end of a block. # For PPI, Statements can be part of others and thus don't necessarily have # a semicolon. while (1) { my $parent = $statement->statement(); last if not defined $parent; if ( $parent eq $statement ) { # exactly the same object, ie. is a statement already $parent = $statement->parent(); # force the parent last if not $parent # stop if we're at a block or at the document level or $parent->isa('PPI::Structure::Block') or $parent->isa('PPI::Structure::Document'); $parent = $parent->statement(); # force it to be a statement } last if not $parent # stop if the parent isn't a statement or not $parent->isa('PPI::Statement'); $statement = $parent; } my $location_for_insert = $statement->location; $self->location($location_for_insert); # TODO: split on a look behind \n so we keep the \n my @code = map {"$_\n"} split( /\n/, $ppi->serialize ); my $expr; for my $line_num ( $start_loc->[0] .. $end_loc->[0] ) { my $line = $code[ $line_num - 1 ]; # 0 based index to 1 base line numbers substr( $line, $end_loc->[1] ) = '' if $line_num == $end_loc->[0]; substr( $line, 0, $start_loc->[1] - 1 ) = '' if $line_num == $start_loc->[0]; $expr .= $line; } $self->expression($expr); my $indent = ''; $indent = $1 if $code[ $location_for_insert->[0] - 1 ] =~ /^(\s+)/; my $place_holder = 'XXXXX_PPIx_EDITOR_PLACE_HOLDER_XXXXX'; substr( $code[ $location_for_insert->[0] - 1 ], $location_for_insert->[1] - 1, 0 ) = sprintf( "my %s = %s;\n%s", $varname, $place_holder, $indent ); # TODO: need to watch for word boundries etc... my $code = join( '', @code ); $code =~ s/\Q$expr\E/$varname/gm; $code =~ s/\Q$place_holder\E/$expr/gm; return PPIx::EditorTools::ReturnObject->new( code => $code, element => sub { PPIx::EditorTools::find_token_at_location( shift->ppi, $location_for_insert ); } ); } 1; __END__
# Copyright 2008-2009 The Padre development team as listed in Padre.pm. # LICENSE # This program is free software; you can redistribute it and/or # modify it under the same terms as Perl 5 itself.