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

Why this aint working?!?!
@files = <../data/texts/*.txt>; $file = $files[int(rand(@files))]; open(IN, "<$file") or die $!; @data = <IN>; close(IN); $data = join("", @data); $data =~ s/\n/\\n/g; print table( {-width=>"90%", -align=>"center", -style=>"border: ridge +lightgreen; color: yellow; font-size: 18", -background=>"../data/imag +es/blue.jpg"}, foreach(@files) { Tr( td( {-align=>'center'}, font( {-size=>5, -color=>'white'}, b +( $file ))))); Tr( {-align=>'center'}, td( submit( $file ))))); }
I just need a way to put the names of every single file as a button.

Replies are listed 'Best First'.
Re: foreach inside print
by Abigail-II (Bishop) on May 18, 2004 at 11:54 UTC
    That's because foreach is a statement, not an expression. Function arguments are expressions, but not statements. Use map in this case:
    print table ({...}), map {Tr (td (...)), Tr ({...})} @files;

    Abigail

Re: foreach inside print
by ysth (Canon) on May 18, 2004 at 11:58 UTC
    Perl distinguishes between "statements" and "expressions". foreach can only be used as a statement unto itself. Though you can nest a statement in a larger expression using do { ... }, foreach doesn't return a value, so that won't help you.

    Perl does have have a map() builtin that does what you want, though, taking an input list and running code for each item in the list and returning a list of the results of the code block:

    print table( {-width=>"90%", -align=>"center", -style=>"border: ridge +lightgreen; color: yellow; font-size: 18", -background=>"../data/imag +es/blue.jpg"}, map { Tr( td( {-align=>'center'}, font( {-size=>5, -color=>'white'}, b +( $_ ))))); Tr( {-align=>'center'}, td( submit( $_ ))))); } @files;
    I suspect you meant $_ where you said $file in your example. One of the limitations of map() is that it only will use $_; you don't have a way of saying the equivalent of foreach my $file (@files) {...}.
      One of the limitations of map() is that it only will use $_; you don't have a way of saying the equivalent of foreach my $file (@files) {...}.
      Oh, sure there is:
      map {local *file = *_; ...} @files;

      Abigail

        local ne my. Might as well stick to $_ IMO
Re: foreach inside print
by inman (Curate) on May 18, 2004 at 11:45 UTC
    You can always make use of multiple print statements.
    #! /usr/bin/perl use CGI; #presumably ... print table( {-width=>"90%", -align=>"center", -style=>"border: ridge lightgreen; color: yellow; font-size: 18", -background=>"../data/image +s/blue.jpg"}; foreach(@files) { print Tr( td( {-align=>'center'}, font( {-size=>5, -color=>'whit +e'}, b( $file ))))); print Tr( {-align=>'center'}, td( submit( $file ))))); }
Re: foreach inside print
by pbeckingham (Parson) on May 18, 2004 at 11:59 UTC

    It looks like you need $_ instead of $file in your example, but try this:

    print table( {-width=>"90%", -align=>"center", -style=>"border: ridge +lightgreen +; color: yellow; font-size: 18", -background=>"../data/images/blue.jp +g"}, map { Tr( td( {-align=>'center'}, font( {-size=>5, -color=>'white'}, b +( $_ )) +))); Tr( {-align=>'center'}, td( submit( $_ ))))); } @files;

      Thank you very much!
      I though i was using $_ already but i mistaken used $file,
      Another problem is that i want to get rid of all the paths in front of the filenames. so the user can see only the filename it self. All files are stored inside the array @files like this: Can a substitute operator be applied to an array it slef or it can only be used in single variebles.
      @files = <../data/texts/*.txt>; $file = $files[int(rand(@files))];
      now the filenames is like this:
      ../data/texts/filename1.txt
      ../data/texts/filename2.txt
      ../data/texts/filename3.txt
      ../data/texts/filename4.txt
      ../data/texts/filename5.txt
      and so on
      can i use a s/// operator to get rid of the paths?

        You can do it with a substitution, but that's not really a good idea, and difficult to make portable. Instead, use File::Basename, and the basename or dirname methods.

      A reply falls below the community's threshold of quality. You may see it by logging in.
Re: foreach inside print
by eserte (Deacon) on May 18, 2004 at 11:58 UTC
    foreach does not return anything (well, maybe it does, but not what you expect). You can use multiple prints as suggested elsewhere, or use a join-map combination instead.

    Update: join is not necessary here.