4

我目前正在重构一些应用程序代码,我希望能够从子例程中删除一些参数。例如,假设我有以下 [1]:

sub do_something {
    my ( $param1, $param2, $param3, $param4 ) = ( @_ );
    ....
}

但是,作为重构的一部分,我使参数 2 和 3 变得多余。更新这个方法签名是很容易的部分,但是有没有一种直接的方法来更新对它的所有调用?

我一直在做一些定制的 grep/sed/perl 来做这件事,但是对 sub 的一些调用是多行的,这使得它很痛苦,每次我在一个项目上这样做都是定制的。是否有适合进行这种特定重构的工具?

[1] - 不是实际参数或子程序名称,我向你保证!

4

2 回答 2

3

Padre有一些重构的功能,但不知道能不能完成你想要的。

更改您的界面以接受散列而不是位置列表,这将使未来的更改比现在更少工作。

sub do_something {
    my (%param) = (@_);
    ...
}

do_something(foo => 23, bar => 42);
于 2013-07-26T08:56:09.680 回答
0

如果您有一个代码覆盖率接近 100% 的测试套件,您可以使用它来查找所有调用站点。

给定调用堆栈中位置的参数,caller内置函数返回

  1. 调用者的包名
  2. 文件名
  3. 电话号码
  4. 完全限定的子名称
  5. ……还有更多

我们现在可以添加一些记录调用位置的代码。我们可以将结果放入某种数据结构中进行自动处理,也可以将报告写入日志文件。例如

sub this_logs {
  {
    # seperate scope to not pollute your sub
    state $log_fh //= do {
      open my $fh, ">", "record_callsites.log"; # assuming autodie;
      $fh;
    };
    state $seen = {};
    my (undef,    undef, undef, $sub) = caller(1);
    my ($package, $file, $line,     ) = caller(0);
    my $site = $sub ? "$sub()" : "pkg $package";
    unless ($seen->{$file}{$line}++) {
      say {$log_fh} "CALL from $site at $file line $line";
    }
  }
  my ($param1, $param2) = @_;
  # etc
}

假设你所有的代码都是

this_logs(1, 2, 3);         # direct call
foo();                      # call from same package
my $sub = "this_" . "logs"; 
baz($sub);                  # call by name
Foo::bar();                 # call from different package
foo();                      # duplicate call

sub foo {
  return this_logs(5, 6, 7);
}
sub baz {
  shift()->(1, 2, 3);  # no strict refs for this, please
};

package Foo;
sub bar {
  main::this_logs();
}

这将产生日志文件

CALL from pkg main at - line 20
CALL from main::foo() at - line 28
CALL from main::baz() at - line 31
CALL from Foo::bar() at - line 3

(文件名-表示标准输入)

因此,给定一个合适的测试套件,它能够找到无法被 grep 的调用站点。

如果您有一个非白痴编辑器,您还可以发出一个脚本,依次打开每个文件并将光标定位在正确的行上:

say "kate -l $line $file";
say "vim +$line $file";
于 2013-07-26T14:21:25.143 回答