List 如何在测试用例的多行列表初始值设定项中获取当前行号?

List 如何在测试用例的多行列表初始值设定项中获取当前行号?,list,perl,debugging,eval,stack-trace,List,Perl,Debugging,Eval,Stack Trace,有没有一种方法可以在Perl测试期间可靠地获取当前行号 不显式使用的多行列表分配?我是 将测试用例存储在一个列表中,并希望用它的行标记每个测试用例 数字。*这样我可以做(大致) @tests的ok($\u->[1],'line.$\u->[0])。 当然,我也希望能节省打字时间 将\uuuu行\uuuu放在每个测试用例的开头:)。我有 没能找到这样做的方法,我遇到了一些问题 调用者报告的行中的混乱行为 *可能是XY,但我找不到一个模块 更新我发现了一个黑客,并将其发布为。感谢@zdim帮助我以不

有没有一种方法可以在Perl测试期间可靠地获取当前行号 不显式使用
的多行列表分配?我是
将测试用例存储在一个列表中,并希望用它的行标记每个测试用例
数字。*这样我可以做(大致)
@tests的
ok($\u->[1],'line.$\u->[0])。
当然,我也希望能节省打字时间
将
\uuuu行\uuuu
放在每个测试用例的开头:)。我有 没能找到这样做的方法,我遇到了一些问题
调用者报告的行中的混乱行为

*可能是XY,但我找不到一个模块

更新我发现了一个黑客,并将其发布为。感谢@zdim帮助我以不同的方式思考这个问题

MCVE

很长的一个,因为我已经尝试了几种不同的选择<代码>我的评估
L()
L2{}
是到目前为止我尝试过的一些方法-
L()
就是其中之一 我最初希望它能起作用。跳转到
my@testcases
查看如何 我正在用这些。测试时,务必复制shebang线

如果你感兴趣的话,这是我的

输出

加上我的评论

 0 LINE       line 32 expected 32
 1 LINE       line 33 expected 33
使用
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
缩写

 2 L()        line 45 expected 34 *
 3 L()        line 45 expected 35 *
L()
使用
调用者
获取行号,然后报告一行 在文件中(!)

当我将
L()
调用包装在
do{}
中时,
调用方
返回正确的 行号-但仅一次(!)

eval
,有趣的是,它工作得很好。然而,它并不短 而不是
\uuuuuuuuuuuuuuuuuuu

 8 eval L     line  1 expected 40 *
 9 eval L     line  1 expected 41 *
字符串
eval
给出
eval
中的行号(毫不奇怪)

my_eval()
是一个基于
呼叫方
。它还提供了文件后面的行号(!)

L2
L
相同,但它需要一个返回列表的块, 而不是 清单本身。它还使用
调用者
作为行号。而且 一次是正确的,但不是两次(!)。(可能只是因为这是最后一次 项目-
my_eval
也报告了第45行。)

那么,这里发生了什么?我听说过德帕斯,不知道这是不是 优化相关,但我对引擎的了解还不够 从哪里开始调查。我还认为这可以通过源代码来实现 过滤或过滤,但这远远超出我的理解 经验水平

拿2块 @zdim的回答让我开始思考流畅的界面,例如:


然而,即使这些在这里也不起作用-对于每个
->L()
调用,我都会得到第26行。因此,
caller
似乎看到所有链接调用都来自
$testcases2->…
行。哦,好吧。如果有人能启发我的话,我仍然想知道为什么

调用方
只能获取编译时确定的语句行号

当我将代码更改为

my @testcases;
push @testcases, ([__LINE__,0,32,'LINE']);
push @testcases, ([__LINE__,1,33,'LINE']);
push @testcases, (L(2,34,'L()'));
push @testcases, (L(3,35,'L()'));
...
保持行号,它可以工作(字符串求值除外)

因此,在实践方面,使用
调用者
可以为调用提供单独的语句

Perl内部 行号在编译时被烘焙到op树中,然后(我的重点)

在运行时,只有语句的行号可用[…]

我们可以通过运行
perl-MO=简明脚本.pl
看到这一点

2 nextstate(main 25 line_nos.pl:45) v:*,&,{,x*,x&,x$,$,67108864 ->3
即使连续的调用在不同的行上,它们也是同一语句的一部分,因此都附加到相同的
nextstate

编辑此答案现在被包装在一个()中


让我想到了流畅的界面。下面是两个适用于我的特定用例的hack,但这并不能帮助我理解问题中报告的行为。如果你能帮忙,请发布另一个答案

Hack 2(更新版)(现在在CPAN上的版本) 我认为这是非常接近最低限度。在perl中,您可以通过使用
$ref->()
的引用调用子例程,并且可以在箭头链中省略第二个和后续的
->
。这意味着,例如,您可以:

my $foo; $foo=sub { say shift; return $foo; };
$foo->(1)
      (2)
      (3);
看起来不错,对吧?以下是MCVE:

#!perl
use strict; use warnings; use 5.010;

package FluentAutoIncList2 {
    sub new {   # call as $class->new(__LINE__); each element is one line
        my $class = shift;
        my $self = bless {lnum => shift // 0, arr => []}, $class;

        # Make a loader that adds an item and returns itself --- not $self
        $self->{loader} = sub { $self->L(@_); return $self->{loader} };

        return $self;
    }
    sub size { return scalar @{ shift->{arr} }; }
    sub last { return shift->size-1; }      # $#

    sub load { goto &{ shift->{loader} } }  # kick off loading

    sub L {     # Push a new record with the next line number on the front
        my $self = shift;
        push @{ $self->{arr} }, [++$self->{lnum}, @_];
        return $self;
    } #L

    sub add {   # just add it
        my $self = shift;
        ++$self->{lnum};    # keep it consistent
        push @{ $self->{arr} }, [@_];
        return $self;
    } #add

} #FluentAutoIncList2

# List of [line number, item index, expected line number, type]
my $testcases = FluentAutoIncList2->new(__LINE__)    # line 28
    ->add(__LINE__,0,36,'LINE')
    ->add(__LINE__,1,37,'LINE');
    $testcases->load(2,38,'load')->     # <== Only need two arrows.
    (3,39,'chain load')                 # <== After that, () are enough.
    (4,40,'chain load')
    (5,41,'chain load')
    (6,42,'chain load')
    (7,43,'chain load')
;

foreach my $idx (0..$testcases->last) {
    printf "%2d %-10s line %2d expected %2d %s\n",
            $idx, $testcases->{arr}->[$idx]->[3],
            $testcases->{arr}->[$idx]->[0],
            $testcases->{arr}->[$idx]->[2],
            ($testcases->{arr}->[$idx]->[0] !=
                $testcases->{arr}->[$idx]->[2]) && '*';
}
与原始的
[x,y]
方法相比,所有
链加载
行都加载了零个额外字符。一些开销,但不多

黑客1 代码:

通过从
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。使用
领带
可能会更干净

#!perl
use strict; use warnings; use 5.010;

package FluentAutoIncList {
    sub new {   # call as $class->new(__LINE__); each element is one line
        my $class = shift;
        return bless {lnum => shift // 0, arr => []}, $class;
    }
    sub size { return scalar @{ shift->{arr} }; }
    sub last { return shift->size-1; }      # $#

    sub L {     # Push a new record with the next line number on the front
        my $self = shift;
        push @{ $self->{arr} }, [++$self->{lnum}, @_];
        return $self;
    } #L

    sub add {   # just add it
        my $self = shift;
        ++$self->{lnum};    # keep it consistent
        push @{ $self->{arr} }, [@_];
        return $self;
    } #add

} #FluentAutoIncList

# List of [line number, item index, expected line number, type]
my $testcases = FluentAutoIncList->new(__LINE__)    # line 28
    ->add(__LINE__,0,29,'LINE')
    ->add(__LINE__,1,30,'LINE')
    ->L(2,31,'L()')
    ->L(3,32,'L()')
    ->L(4,33,'L()')
;

foreach my $idx (0..$testcases->last) {
    printf "%2d %-10s line %2d expected %2d %s\n",
            $idx, $testcases->{arr}->[$idx]->[3],
            $testcases->{arr}->[$idx]->[0],
            $testcases->{arr}->[$idx]->[2],
            ($testcases->{arr}->[$idx]->[0] !=
                $testcases->{arr}->[$idx]->[2]) && '*';
}
输出:

 0 LINE       line 36 expected 36
 1 LINE       line 37 expected 37
 2 load       line 38 expected 38
 3 chain load line 39 expected 39
 4 chain load line 40 expected 40
 5 chain load line 41 expected 41
 6 chain load line 42 expected 42
 7 chain load line 43 expected 43
 0 LINE       line 29 expected 29
 1 LINE       line 30 expected 30
 2 L()        line 31 expected 31
 3 L()        line 32 expected 32
 4 L()        line 33 expected 33

zdim,说得好!我仍然对内部处理感到好奇。而且,
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。就像它经常做的那样——但由于这些是子调用,我希望
caller
能够在它们自己的线路上看到它们。我也会这样做。我找到了一个暂时有效的方法,但是如果你发现为什么子呼叫在
呼叫者
记录中没有自己的行号,请告诉我。谢谢你让我思考解决这个问题的其他方法!您已经有了我的upvote:)。@cxw已更新--行号信息是为列表所在的语句编译的(至于更多关于为什么要创建列表以及其他内容的一般信息……我暂时不讨论)。我喜欢你解决这个问题的方法:)@cxw感谢你添加了答案(很抱歉,我没有立即回复,我希望能再次看到这个问题……)非常有趣(+1-ed),但从我看到你的“第二次破解”也很有效——问题结束了 2 nextstate(main 25 line_nos.pl:45) v:*,&,{,x*,x&,x$,$,67108864 ->3
$ perl -MO=Concise -e '$x
    ->foo()
    ->bar()
    ->bat()'
d  <@> leave[1 ref] vKP/REFC ->(end)
1     <0> enter ->2
2     <;> nextstate(main 1 -e:1) v:{ ->3    <=== the only nextstate
c     <1> entersub[t4] vKRS/TARG ->d
3        <0> pushmark s ->4
a        <1> entersub[t3] sKRMS/LVINTRO,TARG,INARGS ->b
4           <0> pushmark s ->5
8           <1> entersub[t2] sKRMS/LVINTRO,TARG,INARGS ->9
5              <0> pushmark s ->6
-              <1> ex-rv2sv sKM/1 ->7
6                 <#> gvsv[*x] s ->7
7              <.> method_named[PV "foo"] s ->8
9           <.> method_named[PV "bar"] s ->a
b        <.> method_named[PV "bat"] ->c
-e syntax OK
my $foo; $foo=sub { say shift; return $foo; };
$foo->(1)
      (2)
      (3);
#!perl
use strict; use warnings; use 5.010;

package FluentAutoIncList2 {
    sub new {   # call as $class->new(__LINE__); each element is one line
        my $class = shift;
        my $self = bless {lnum => shift // 0, arr => []}, $class;

        # Make a loader that adds an item and returns itself --- not $self
        $self->{loader} = sub { $self->L(@_); return $self->{loader} };

        return $self;
    }
    sub size { return scalar @{ shift->{arr} }; }
    sub last { return shift->size-1; }      # $#

    sub load { goto &{ shift->{loader} } }  # kick off loading

    sub L {     # Push a new record with the next line number on the front
        my $self = shift;
        push @{ $self->{arr} }, [++$self->{lnum}, @_];
        return $self;
    } #L

    sub add {   # just add it
        my $self = shift;
        ++$self->{lnum};    # keep it consistent
        push @{ $self->{arr} }, [@_];
        return $self;
    } #add

} #FluentAutoIncList2

# List of [line number, item index, expected line number, type]
my $testcases = FluentAutoIncList2->new(__LINE__)    # line 28
    ->add(__LINE__,0,36,'LINE')
    ->add(__LINE__,1,37,'LINE');
    $testcases->load(2,38,'load')->     # <== Only need two arrows.
    (3,39,'chain load')                 # <== After that, () are enough.
    (4,40,'chain load')
    (5,41,'chain load')
    (6,42,'chain load')
    (7,43,'chain load')
;

foreach my $idx (0..$testcases->last) {
    printf "%2d %-10s line %2d expected %2d %s\n",
            $idx, $testcases->{arr}->[$idx]->[3],
            $testcases->{arr}->[$idx]->[0],
            $testcases->{arr}->[$idx]->[2],
            ($testcases->{arr}->[$idx]->[0] !=
                $testcases->{arr}->[$idx]->[2]) && '*';
}
 0 LINE       line 36 expected 36
 1 LINE       line 37 expected 37
 2 load       line 38 expected 38
 3 chain load line 39 expected 39
 4 chain load line 40 expected 40
 5 chain load line 41 expected 41
 6 chain load line 42 expected 42
 7 chain load line 43 expected 43
#!perl
use strict; use warnings; use 5.010;

package FluentAutoIncList {
    sub new {   # call as $class->new(__LINE__); each element is one line
        my $class = shift;
        return bless {lnum => shift // 0, arr => []}, $class;
    }
    sub size { return scalar @{ shift->{arr} }; }
    sub last { return shift->size-1; }      # $#

    sub L {     # Push a new record with the next line number on the front
        my $self = shift;
        push @{ $self->{arr} }, [++$self->{lnum}, @_];
        return $self;
    } #L

    sub add {   # just add it
        my $self = shift;
        ++$self->{lnum};    # keep it consistent
        push @{ $self->{arr} }, [@_];
        return $self;
    } #add

} #FluentAutoIncList

# List of [line number, item index, expected line number, type]
my $testcases = FluentAutoIncList->new(__LINE__)    # line 28
    ->add(__LINE__,0,29,'LINE')
    ->add(__LINE__,1,30,'LINE')
    ->L(2,31,'L()')
    ->L(3,32,'L()')
    ->L(4,33,'L()')
;

foreach my $idx (0..$testcases->last) {
    printf "%2d %-10s line %2d expected %2d %s\n",
            $idx, $testcases->{arr}->[$idx]->[3],
            $testcases->{arr}->[$idx]->[0],
            $testcases->{arr}->[$idx]->[2],
            ($testcases->{arr}->[$idx]->[0] !=
                $testcases->{arr}->[$idx]->[2]) && '*';
}
 0 LINE       line 29 expected 29
 1 LINE       line 30 expected 30
 2 L()        line 31 expected 31
 3 L()        line 32 expected 32
 4 L()        line 33 expected 33