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

I'm so very tired and I'd like an answer right away... Yes, I know, how selfish of me, and I'm new here, to boot. Anyway, I'm trying to role my own Wiki and it's been pretty fun. The only problem, however weird (I try to cover all bases) is that if the user submits a page containing one zero (0, no quotes, no parens) or nothing at all, the database just spits out another edit page, as if nothing was submitted at all. How can I make Perl realize the difference between undefined and a 0 and a blank? Yes, I use warnings and strict religiously... But as you can see, the code is getting pretty nasty, as I've tried to "force the zero" many a way...
#!/usr/local/bin/perl -w use diagnostics; use strict; use CGI; use HTML::Entities; #anomolie. no blank pages, no zeroes, ask the perl gods. my $c = new CGI; dbmopen(my %WIKI, "wiki", 0644); my(@p, $p, $q, $error); @p = $c->param; $p = (defined $p[0] and $p[0] eq "keywords" ? $c->param("keywords") : +$p[0]) || "WelcomePage"; $error = ($p !~ /^(search|edit)?([A-Z][a-z]+([A-Z][a-z]+)+)/ ? "Invali +dAction" : ""); $q = $p; $q =~ s/^[a-z]+(.*)/$1/; $WIKI{"$q"} = scalar(encode_entities($c->param($p))) if $p =~ /^edit/ +and defined(scalar($c->param($p))) and !($error); $WIKI{"$q"} =~ s/\&\#13\;//g if $WIKI{"$q"}; $p = $q if $p =~ /^edit/ and $c->param($p); print "Content-Type: text/html; charset=UTF-8\n\n", $c->start_html(-ti +tle=>$p), $c->h1($c->a({-href=>"/wiki/"},"HtmlismOpenWiki")." : ".($p + =~ /^edit/ ? $c->a({-href=>"?$q"},$p) : ($p =~ /^search/ ? $c->a({-h +ref=>"?$q"},$p) : $c->a({-href=>"?search$q"},$p)))); if ($p =~ /^edit.*/ and not $error and not $c->param($p)) { print $c->startform("post","/wiki/"), $c->textarea({-style=>"width:100%;height:3in",-name=>"$p",-default +=>($WIKI{$q} ? $WIKI{$q} : "")}), $c->p($c->submit), $c->endform } print wikimake(($error ? $c->p($error) : "")), wikimake(($WIKI{$q} && +($p =~ /^[A-Z]/ or $c->param($p)) ? $c->p($WIKI{$q}) : "")), ((($p =~ + /^[A-Z]/ or $c->param($p)) and !$error) ? ($c->hr.$c->p($c->a({-href +=>"?edit$q"},"Edit this page"))) : ""), $c->end_html; dbmclose(%WIKI); sub wikimake { my $z = shift; $z =~ s/\b([A-Z][a-z]+([A-Z][a-z]+)+)/$c->a({-href=>"?$1"},$1)/eg; $z =~ s/\n/$c->br/eg; return $z; }

Replies are listed 'Best First'.
(jeffa) Re: Vanishing Data
by jeffa (Bishop) on May 02, 2002 at 02:41 UTC
    Grasshopper needs meditation first:
    #!/usr/local/bin/perl -l use strict; foreach (0,'',undef) { print "'$_' is zero number" if $_ == 0; print "'$_' is zero string" if $_ eq '0'; print "'$_' is empty string" if $_ =~ /^$/; print "'$_' is empty string" if $_ eq ''; print "'$_' is undef" if ! defined $_; }

    jeffa

    L-LL-L--L-LL-L--L-LL-L--
    -R--R-RR-R--R-RR-R--R-RR
    B--B--B--B--B--B--B--B--
    H---H---H---H---H---H---
    (the triplet paradiddle with high-hat)
    
      It's a really minor point, but this statement is not strictly true:
      print "'$_' is empty string" if $_ =~ /^$/;
      What you want is /^\z/, since /^$/ will also match a single newline, as evidenced by the following test:
      print "Empty matches ^\$ --> ", ("" =~ /^$/ ? 'yes' : 'no'), "\n"; print "Newline matches ^\$ --> ", ("\n" =~ /^$/ ? 'yes' : 'no'), "\n" +; print "Empty matches ^\\z --> ", ("" =~ /^\z/ ? 'yes' : 'no'), "\n"; print "Newline matches ^\\z --> ", ("\n" =~ /^\z/ ? 'yes' : 'no'), "\n +";
Re: Vanishing Data
by dws (Chancellor) on May 02, 2002 at 02:45 UTC
    I'm so very tired and I'd like an answer right away...

    Many problems are more evident when the code is clean. Your code is a mess. It's hard for me to tell what's going on in there, and I'm very familiar with the inner workings of Wikis.

    • Use meaningful variable names. $p and $q are terse, and you're overloading them. It's hard to follow what they're holding.
    • Your life would be simpler if you would use a fixed name for the <textarea>, rather than creating one on the fly, and then hoping you can retrieve it given info plucked from the URL.
    • Your life would be a lot simple if you would sort out which command is being invoked (e.g., edit, search) at the top, and call different top-level routines depending on the command. Your logic has a bit of a pretzel quality to it.
    • Encode the pattern for matching a valid page name once, rather than sprinkling it throughout the code. The more duplication you have, the greater the chance that you'll get one subtley wrong.

      Hey, I got my Wiki working exactly the way I wanted it through a bit of, what do you call it, refactoring? Is that like making small changes while keeping the program working? If so, that's what I did. I actually had to do it twice, the editor ate it up the first time.

      I used short variable names because I was fighting for the ShortestWiki (currently FinikiWiki). But I did choose more meaningful words (and then to be abbreviated)

      I still used a dynamic textarea name, but it works as intended. And I did jam all of the repeat regular expression validators together and made good use of if blocks.

      So I'd just like to say thank you. Maybe you'd like to try my wiki out?

Re: Vanishing Data
by Anonymous Monk on May 02, 2002 at 16:40 UTC
    Do not use defined! Use length!