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

Is there anyway to refactor this so that it does not need the no strict 'refs', and can work under Modern::Perl without it?

use Modern::Perl;$_=' <use><qd>action</></> <use><qd>action</></> '; $_{'s'} = { jeopardy =>"21"}; $_{'qd'} = { action => 'default' }; sub dbl { say "this should only calc once"; $_{'dbl'}->{$_[0]} = $_[0]*2; } sub use { $_{'use'}->{$_[0]} = &simulate_opening_file; } sub simulate_opening_file { say "this should only slurp once"; "The answer is <dbl><s>jeopardy</></>" }; while (/<([^<]+?)>([^<]*?)<\/>/) { my $l=$+[0]-$-[0]; no strict 'refs'; my $r = $_{$1}->{$2} ||= $1->($2); substr($_,$-[0],$l,$r); } say;

Replies are listed 'Best First'.
Re: No strict refs
by ikegami (Patriarch) on Aug 21, 2011 at 04:13 UTC

    use strict 'refs'; is what's preventing simulate_opening_file from being called if someone did <simulate_opening_file>...</>, so I applaud your desire to use it.

    Two options:

    • Keep using no strict 'refs';, but require that the callbacks are located in a specific patckage that contains nothing but callbacks.

      1 while s/<([^<]+?)>([^<]*?)<\/>/ $_{$1}->{$2} ||= do { #TODO: Make sure $1 doesn't contains "::". my $func = $pkg . "::" . $1; #TODO: Make sure $func exists. no strict 'refs'; $func->($2) } /e;
    • Require that callbacks get registered.

      my %cb = ( use => \&use, dbl => \&dbl, ); 1 while s/<([^<]+?)>([^<]*?)<\/>/ #TODO: Make sure $cb->{$1} exists. $_{$1}->{$2} ||= $cb->{$1}->($2) /e;

    By the way, you'll have problems if the replacement value contains a "<".

Re: No strict refs
by Anonymous Monk on Aug 21, 2011 at 03:22 UTC
    First I would refactor it to use meaningful variable names
Re: No strict refs
by JavaFan (Canon) on Aug 21, 2011 at 23:57 UTC
    Use goto:
    use 5.010; use strict; use warnings; sub foo { say "This is foo <@_>" } sub bar { say "This is bar <@_>" } sub call { my $sub = shift; goto &$sub; } $_ = "foo 123 foo bar bar 456"; while (/(\w+) (\w+)/g) { call $1, $2; } __END__ This is foo <123> This is foo <bar> This is bar <456>
    Of course, that only helps to circumvent the no strict 'refs';. It doesn't solve anything that no strict 'refs'; tries to protect you from.

    Adapting the trick so it works with your templating system is left as an exercise to the reader.