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

Hi Monks
What I am trying to do here is to print the results of the sub "add_row". It just creates a table, but the problem is, I need to call the sub routine as you see and perl executes the sub right there and ignores the $table_rows inside the while. How can I have the results of sub add_row used inside of the while so the template file can read it?

###################################################################### +###### sub print_form ###################################################################### +###### { my $output_file = "template.sthml"; open(OUTPUT, "$output_file") || print "There is no file here, I'll run + away now!"; $table_rows = &add_row; while(<OUTPUT>) { $_=~s/<!-- (TBROWS) \/\/-->/$table_rows/g; print $_; } close OUTPUT; }####################################################### EDN PRINT FO +RM SUB

Thank you!

Replies are listed 'Best First'.
Re: Sub Return Value Help
by gellyfish (Monsignor) on Aug 01, 2005 at 15:35 UTC

    Change your substitution to:

    $_=~s%<!-- (TBROWS) //-->%add_row()%eg;
    I have changed the regex delimiters to make it easier to read

    /J\

      It worked, can you just explain your reg. exp. for me, thanks a lot!!!!

        The only difference (apart from changing the delimiters from '/' to '%' to reduce backslashing and improve readability) is that the /e modifier has been added to the substitution (meaning that perl code will be evaluated in the RHS of the substitution) and I have replace your variable with a call to the add_row() subroutine - for more on regular expressions please see the perlre manpage.

        /J\

Re: Sub Return Value Help
by JediWizard (Deacon) on Aug 01, 2005 at 15:35 UTC

    I cannot tell you why this doesn't work... but I'd like to offer a few suggestions:

    • Do not use bare word filehandles.
    • use the three argument form of open: open(my $fh, '<', $file)
    • printing "I'll run away now" is not a good error handling technique
    • Do you really mean to be capturing TBROWS and not using the back reference? Perhaps you should see prelre
    • If you are doing an exact match... perhaps you want to use substr instead of a regex. (Would be much faster).
    • You appear to be attempting to use HTML templates.... perhaps you should look at HTML::Template.

    They say that time changes things, but you actually have to change them yourself.

    —Andy Warhol

      Do not use bare word filehandles.
      Bare word filehandles have worked fine since perl1.000, where the way 99% of the code used filehandles until 5.6.0, and are still used in the majority of the code.

      Just stating "don't use bare word filehandles" without any motivation at all doesn't serve anybody.

      use the three argument form of open: open(my $fh, '<', $file)
      Again, no motivation why to not use a construct which has worked fine for almost 20 years. Just because there's a different way of doing things isn't reason enough to critize the old use.

      If you are doing an exact match... perhaps you want to use substr instead of a regex. (Would be much faster).
      Really? How about this benchmark:
      use Benchmark 'cmpthese'; our $orig = "a" x 20; $orig .= "<!-- TBROWS //-->"; $orig .= "a" x 20; $orig .= "<!-- TBROWS //-->"; $orig .= "a" x 20; cmpthese(-1, { 's///' => 'my $c = $orig; $c =~ {<!-- TBROWS //-->}{XXXX}g;', substr => 'my $c = $orig; while ((my $i = index($c, "<!-- TBROWS //-->")) > -1 +) { substr($c, $i, 17) = "XXXX"; }' }); __END__ Rate substr s/// substr 240498/s -- -37% s/// 381869/s 59% --

        Secondly: Your posted code does not even compile.

        Benchmark: running s///, substr, each for at least 1 CPU seconds... runloop unable to compile 'my $c = $orig; $c =~ {<!-- TBROWS //-->}{XX +XX}g;': syntax error at (eval 2) line 1, near "}{XXXX" syntax error at (eval 2) line 1, near "} }" code: sub { for (1 .. 1) { local $_; package main; my $c = $orig; $c = +~ {<!-- TBROWS //-->}{XXXX}g;;} } at test_bench.pl line 9

        If you are going to critize, atleast do so in an effective manner.


        They say that time changes things, but you actually have to change them yourself.

        —Andy Warhol

        Bare work file handles are not as safe as lexically scoped scalars. Just because they were used a decade ago doesn't mean we should continue to use them when a more robust alternative is available. Walking everywhere one needed to go worked fine for centuries. Does that mean we shouldn't use cars? What used to be the standard should not always continue. Change can be good. Before perl 5, we used typeglobs to pass around data structures: If you recomend that... you are insane.


        They say that time changes things, but you actually have to change them yourself.

        —Andy Warhol

Re: Sub Return Value Help
by blazar (Canon) on Aug 01, 2005 at 15:38 UTC
    What I am trying to do here is to print the results of the sub "add_row". It just creates a table, but the problem is, I need to call the sub routine as you see and perl executes the sub right there and ignores the $table_rows inside the while. How can I have the results of sub add_row used inside of the while so the template file can read it?
    I apologize since it must be me being too dumb, but I really can hardly make any sense of your question; however... on to the code:
    ###################################################################### +###### sub print_form ###################################################################### +###### {
    If you nicely indent your code there should never be any need for such heavy comments...
    my $output_file = "template.sthml"; open(OUTPUT, "$output_file") || print "There is no file here, I'll run + away now!";
    Huh?!? the "open or die" idiom is one of Perl's most charachteristic ones. But what does make you think that a simple print will make "run away now"?

    Also, and just as importantly, if that is to be an $output_file, isn't it that by any chance you could want to open it in write mode?!?

    Slightly less importantly:

    • no need to quote all your variables,
    • better include $! in your open error message when, provided that you take care of emitting a real error message.
    $table_rows = &add_row;
    The &-form of sub call is obsolete and should never be used nowadays unless when one really know what he's doing.
    while(<OUTPUT>) { $_=~s/<!-- (TBROWS) \/\/-->/$table_rows/g; print $_; }
    Are you sure it is an output file?!?

    One nice, fundamental, point about $_ is that it is the topicalizer and as such, the default argument of many functions and operators. Thus either

    1. use named variables, or
    2. just write
      s/<!-- (TBROWS) \/\/-->/$table_rows/g; print;
    All in all I suspect you may be after inline editing. In which case you should look up $^I in perldoc perlvar.

    Update: re-reading the code I realize that obviously the OP's problem may just be that he calls his sub out of the while loop, then he uses the return value of that sub, saved into a variable, every time it is needed inside the loop. OTOH there are IMHO bigger problems with his code, as signalled above.

    A reply falls below the community's threshold of quality. You may see it by logging in.