Search code examples
perlstring-interpolation

How to run code inside a string (equivalent to Ruby's #{})


I know we can put any code to #{} in Ruby, the code in #{} will be computed and then inserted into a string.

Is there any equivalent thing in Perl?


Solution

  • From Using references in perlref

    Anywhere you'd put an identifier (or chain of identifiers) as part of a variable or subroutine name, you can replace the identifier with a simple scalar variable containing a reference of the correct type
    ...
    Anywhere you'd put an identifier (or chain of identifiers) as part of a variable or subroutine name, you can replace the identifier with a BLOCK returning a reference of the correct type.

    So

    perl -Mstrict -wE'my $x = 2.6; say "Integer part: ${ \( int $x ) }"'
    

    where you can run code returning a scalar inside \(...) that takes its reference, then ${...} dereferences it. Similarly you can generate an arrayref and use @{...} around it

    perl -Mstrict -wE'$_ = q(silly,it,is); say "Got: @{ [ /(\w+)/g ] }"'
    

    and similary for a hash. But then this goes with an expression returning a scalar as well

    perl -wE'say "$_ squared: @{[ $_**2 ]}" for 1..10'
    

    which is nicer and is more "commonly" used. Thanks to ysth for a comment.

    Keep in mind that [ ] imposes the list context, where the return often differs from the one in scalar context (and \(LIST) is wrong on other accounts). A good example is localtime. The scalar return can be enforced by [scalar localtime]. Thanks to ikegami for a comment.

    Watch that you don't get dragged into using symbolic references though. Also see that in perlfaq7.

    This assumes that you are thinking of code in {...} being a part of a string. If you want to have a string and execute what it contains as code, that's what eval EXPR does. But please note that there are always better ways to do what you need.

    A few examples

    my $str = sprintf "Squared: %6.3f", $x**2;
    my $str = "He said: " . join ' ', split /,/, 'yes,it,is';  #/
    say "Variable is: ", ( $x // 'undef');
    

    or use a do { ... }; to evaluate any code in a well restricted scope and return the result, which can then be joined or concatenated with other strings.

    The topic is discussed in perlfaq4 and at the end of the perlref section linked on top of this post.


    In \(LIST) the reference is taken to every element of the list, perl -wE'say for \(1,2)'. Then the comma operator in the scalar context does its thing, discarding left-hand-side operands one after another and ${ \(LIST) } ends up serving the last element of the list.