Подтвердить что ты не робот

Определение имени подпрограммы для ссылки на Perl-код

Как определить имя подпрограммы для ссылки на Perl-код? Я также хотел бы различать именованные и анонимные подпрограммы.

Благодаря этому вопросу Я знаю, как распечатать код, но я до сих пор не знаю, как получить имя.

Например, я хотел бы получить 'inigo_montoya' из следующего:

#!/usr/bin/env perl

use strict;
use warnings;

use Data::Dumper;
$Data::Dumper::Deparse = 1;

my $sub_ref = \&inigo_montoya;

print Dumper $sub_ref;



# === subroutines ===

sub inigo_montoya {
  print <<end_quote;
I will go up to the six-fingered man and say, "Hello. My name is Inigo
Montoya. You killed my father. Prepare to die."';
end_quote
}
4b9b3361

Ответ 1

Почему бы не спросить, что видит компилятор? (Он будет возвращать __ANON__ на анонимных подписях).

#!/usr/bin/perl

use strict;
use warnings;

my $sub_ref = \&inigo_montoya;


use B qw(svref_2object);
my $cv = svref_2object ( $sub_ref );
my $gv = $cv->GV;
print "name: " . $gv->NAME . "\n";


sub inigo_montoya {
    print "...\n";
}

Ответ 2

Sub::Identify делает именно это, скрывая от вас все эти неприятные вещи B::svref_2object(), поэтому вам не нужно об этом думать.

#!/usr/bin/env perl

use strict;
use warnings;
use feature 'say';

use Sub::Identify ':all';

my $sub_ref = \&inigo_montoya;

say "Sub Name: ",   sub_name($sub_ref);
say "Stash Name: ", stash_name($sub_ref);
say "Full Name: ",  sub_fullname($sub_ref);

# === subroutines ===

sub inigo_montoya {
    print <<'    end_quote';
I will go up to the six-fingered man and say, "Hello. My name is Inigo
Montoya. You killed my father. Prepare to die."';
    end_quote
}

Какие выходы:

$ ./sub_identify.pl 
Sub Name: inigo_montoya
Stash Name: main
Full Name: main::inigo_montoya

Ответ 3

Расширяясь по идее Яна Хартунга (и отказываясь от моего собственного), вы можете получить полное имя и информацию о трассировке независимо от того, что это такое или откуда оно взялось:

use B qw(svref_2object);

sub sub_name {
    return unless ref( my $r = shift );
    return unless my $cv = svref_2object( $r );
    return unless $cv->isa( 'B::CV' )
              and my $gv = $cv->GV
              ;
    my $name = '';
    if ( my $st = $gv->STASH ) { 
        $name = $st->NAME . '::';
    }
    my $n = $gv->NAME;
    if ( $n ) { 
        $name .= $n;
        if ( $n eq '__ANON__' ) { 
            $name .= ' defined at ' . $gv->FILE . ':' . $gv->LINE;
        }
    }
    return $name;
}

Ответ 4

Я не уверен в вызове имени функции извне, но вы можете получить ее из подпрограммы через caller:

sub Foo {print "foo!\n";return (caller(0))[3];}
$function_name=Foo();
print "Called $function_name\n";

Это имеет следующий результат:

foo!
Called main::Foo

Конечно, вы можете вернуть имя функции как один из элементов, возвращаемых подпрограммой. Таким образом, вы можете захватить его и иметь возможность отображать его (или использовать его в другой логике и т.д.).