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

I recognize that this may be too much to ask of total strangers on a forum, but I am a complete and utter self-taught Perl newbie (have been crash-coursing with online tutorials over the past two weeks) and I’m struggling to write a script for a self-designed project that’s due in two weeks. I have no formal programming education, just self-taught HTML and CSS.

I feel like I’ve come as far as I can on my own, and now I need to know:

1. If my idea is conceptually sound

and

2. The best way to implement templating for this particular script

I apologize in advance if my Perl knowledge is so rudimentary that I need further explanation of your explanations.

My project is called The Spam Oracle. It’s a simple website with an HTML form; enter a question and hit submit, and a random snippet of spam is returned as the answer to your question. (The front end is already mostly built: here.) I want the user’s submission to have some bearing on what’s returned, but in a randomized way (the project is meant to be working with Burroughs-esque cut-up concepts).

I’m envisioning the randomizing element working like this:

The script uses the second-to-last character of the submission to determine which one of five spam-filled text files it will open (a-e opens infinity01.txt; f-j opens infinity02, etc) and then returns a random number (between 1 and 5) of randomly selected lines from that file. I’ve decided to use the second-to-last character because the final character will frequently be a question mark, and I imagine the first will often be a W (Who, What, When, Where, Why, etc) or H (How) – which will make the randomization appear quite stultified.

Here’s a very rough draft of my script, with some questions in the comments and a couple more at the end:

#!/usr/bin/perl –Tw use strict; use CGI ':standard'; use Template; my $t = Template->new; my $cut = param(‘cut’); # submit button’s name attribute = cut my $cut = substr($cut, -1, 1); # redefine ‘cut’ to be only 2nd-to-last letter of submission # does this substr overwrite the param definition of $cut? my $range = 5; # define number of lines (for random_line function) as a # random integer between 1 and 5 my $minimum = 1; # with an offset so range starts at 1 and not 0 my $nr_of_lines = int(rand($range)) + $minimum; # analyze $cut value, open appropriate infinity file and # call random number of lines if (my $cut =~ /[a-e]/i) { # does $cut need “my”? if yes, inside or outside parens? open (INFINITY01, "infinity01.txt") or die "file is temporarily unavailable: $!\n"; # need another nested set of curly brackets for print func? # or is print irrelevant; ie, should the template be called # here? where does the flow control language belong – here, # or in template? and how should it be phrased? print random_line($INFINITY01 [, $nr_of_lines]); # is $INFINITY01 the correct way to reference the file here? # should it be $infinity01? infinity01.txt? # why is $nr_of_lines in brackets, and what function does # the comma serve? I found this function at cpan, but # haven’t been able to find much else about it online. # does “my” need to be added to $nr_of_lines? if yes, inside # brackets or out? close INFINITY01; } elsif (my $cut =~ /[f-j]/i) { open (INFINITY02, "infinity02.txt") or die "file is temporarily unavailable: $!\n"; print random_line($INFINITY02 [, $nr_of_lines]); close INFINITY02; } elsif ($cut =~ /[k-o]/i) { open (INFINITY03, "infinity03.txt") or die "file is temporarily unavailable: $!\n"; print random_line($INFINITY03 [, $nr_of_lines]); close INFINITY03; } elsif ($cut =~ /[p-t]/i) { open (INFINITY04, "infinity04.txt") or die "file is temporarily unavailable: $!\n"; print random_line($INFINITY04 [, $nr_of_lines]); close INFINITY04; } elsif ($cut =~ /[u-z/i) { open (INFINITY05, "infinity05.txt") or die "file is temporarily unavailable: $!\n"; print random_line($INFINITY05 [, $nr_of_lines]); close INFINITY05; # include fail-safe statement in case $cut doesn’t match any # letter of the alphabet } else { print "Yes, no, maybe so.\n"; } }
So will this work, assuming I get all my syntax correct and handle the templating issue properly?

Also: Do the spam source files (infinities) need "\n" characters at the end of each line in order for the rand function to work (i.e., to recognize each line in the file as a separate line)?

I know it’s a huge favor to ask for so much help on such rudimentary code. Thanks a million, in advance, to anyone who can assist with any or all of this.

cheers,
jess

Replies are listed 'Best First'.
Re: will this random-text script work? how do i integrate a template?
by madbombX (Hermit) on Jan 14, 2007 at 20:50 UTC
    My first recommendation would be to read Ovid's CGI Course and HTML::Template Tutorial from the tutorials section.. This will take care of CGI and HTML::Template. There are better ways to use CGI in my opinion. Since you don't really make use of your template here, I can't make any corrections. But if this is a web based script, I strongly suggest using HTML::Template for templating using the above mentioned tutorial as a reference. For example:
    use CGI qw( :standard ); my $q = new CGI; my $cut = $q->param('cut'); ### work with cut here
      Thanks! These look promising -- I'll read through them tonight.

      (Didn't include my template because I haven't written it yet. I'm that confused, still. But hopefully these tutorials will clear things up.)

Re: will this random-text script work? how do i integrate a template?
by CountZero (Bishop) on Jan 14, 2007 at 21:45 UTC
    My, oh my! You have far too many my's in your code/

    Each my for the same variable will mask the previous contents of that variable so it is effectively lost to your script. So only use my once for each variable.

    As for opening and reading your text files, I don't know how large they are, but if they have quite a size, the web-server will take a big hit if for every access to your script it has to read a huge file just to get a few random lines. In such case it is much better to put all your lines in database and get the content from the database.

    Finally, where did you get the random_line subroutine? I see it nowhere defined in your script, so I would be surprised if it works.

    PS: I wouldn't bother with finding the second to last letter of the input and using that as a randomizing device. Just do a straight random pick out of all of your lines of spam-quotes. It will work as good and none will be the wiser.

    CountZero

    "If you have four groups working on a compiler, you'll get a 4-pass compiler." - Conway's Law

      You should start your script with a use File::Random qw/:all/;

      This will load the File::Random module and make all of its subroutines available in your script.

      Then you can do something like:

      my $dir = '//path/to/my/SpamQuoteFilesDirectory'; my $file = random_file(-dir => $dir); my @lines = random_line($fname, int(rand(5)) + 1);
      This script will choose at random 1 file out of all the files in your '//path/to/my/SpamQuoteFilesDirectory' and from this file choose at random 1 to 5 lines and store them in the array @lines.

      BTW, you did install File::Random first didn't you?

      CountZero

      "If you have four groups working on a compiler, you'll get a 4-pass compiler." - Conway's Law

        Thank you! And one more question -- hopefully the last: I've put File::Random and Want in a directory within the home directory of my hosting account, per related advice given here.

        What's confusing me are these instructions at CPAN, about running the Makefile.Pl, and additionally the reference in the Dreamhost link above about the "use lib" command. I've tried to research all this myself, but I think I don't know enough about programming to figure it out.

        Where/how do I need to take these final steps, so my script knows where to find the modules?

      Yeah, the my thing was really confusing me. Thanks for the clarification.

      How large a text file is too large to be practical, roughly speaking? I know even less about databases than I do about Perl, so I'd like to stick with some semblance of my original approach if it's feasible.

      Last, I found the random_line subroutine here: http://search.cpan.org/~bigj/File-Random-0.17/Random.pm#FUNCTION_random_line(%24filename_%5B%2C_%24nr_of_lines%5D)

      What do I need to add to my script to make it work?

      (And as I continue to struggle with this project, the option of simplifying things down and abandoning the randomizing device becomes more and more attractive.)

Re: will this random-text script work? how do i integrate a template?
by chromatic (Archbishop) on Jan 15, 2007 at 01:26 UTC

    Any time you see code that is almost the same, except for variable names or constants, make it the same:

    sub get_random_line { my $filename = shift; open my $fh, '<', $filename or die "Cannot read '$filename': $!\n" +; return random_line( $fh ); } my $filename; if (my $cut =~ /[a-e]/i) { $filename = 'infinity01.txt' } elsif ( ... ) { ... } my $random_line = get_random_line( $filename );
Re: will this random-text script work? how do i integrate a template?
by ysth (Canon) on Jan 14, 2007 at 22:15 UTC
    This is kind of a meta-response, but I have the suspicion you are using a word processor instead of a programming editor. If so, I'd highly recommend you switch.

      Or at the least run it through perltidy before you inflict it upon others.

        perltidy is not going to do well with the ‘mismatched quotes’, I suspect.
      Your suspicion is correct, and yeah, I should know better. Thanks for the nudge.