http://qs321.pair.com?node_id=11147264

clscott has asked for the wisdom of the Perl Monks concerning the following question:

I have a string that comes from a config file: My::Filters::filter_it_like_this

If we assume that My::Filters has been loaded, how can I verify that this string is a subroutine?

--
Clayton

Replies are listed 'Best First'.
Re: Test if a string is a sub name
by choroba (Cardinal) on Oct 05, 2022 at 21:56 UTC
    You can use exists and defined to find out:
    #!/usr/bin/perl use warnings; use strict; use feature qw{ say }; sub My::Filters::known {} sub My::Filters::forward; for my $string (qw(My::Filters::known My::Filters::unknown My::Filters::forward) ) { say join "\t", $string, defined &$string, exists &$string; }

    Output:

    My::Filters::known 1 1 My::Filters::unknown My::Filters::forward 1
    map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]
      I do not understand how your expression &$string works. The documentation for exists tells us that the expression must return the name of a subroutine. It appears to me that this would only be true for your expression if $string is a symbolic reference (which is prohibited by use strict). I would expect you need string interpolation (perhaps "&$string") but this syntax throws an error that the argument of exists is not a subroutine.
      Bill
        It seems the documentation uses the term "subroutine name" in quite a confusing way. Check the examples:
        Use of a subroutine call, rather than a subroutine name, as an argument to exists is an error.
        exists ⊂ # OK exists &sub(); # Error

        So, in this context, "subroutine name" includes the ampersand.

        Considering strict, note the exceptions to strict 'refs':

        $bar = \&{'foo'}; &$bar;
        We are not calling the subroutine, we're just checking it exists/is defined.

        map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]
      That's great. Thanks very much
      --
      Clayton
Re: Test if a string is a sub name
by SankoR (Prior) on Oct 06, 2022 at 00:39 UTC
    I would use can for this. That way, whether your filters inherit functions from parents or import them, your query will work correctly.

    sub My::Filters::known { } sub My::Filters::forward; for my $string (qw[known unknown forward]) { warn $string if My::Filters->can($string); }
    As a bonus, you can define the package with a variable with can:

    sub My::Filters::known { } sub My::Filters::forward; sub My::Other::Filters::forward; for my $package (qw[My::Filters My::Other::Filters]) { for my $func (qw[known unknown forward]) { warn $package . '::' . $func if $package->can($func); } }
      Thanks for this answer, I'll try this out as well
      --
      Clayton