Read (the perldoc) carefully

Another day in CGI/CGI::Application brought me another question.

My code:

    ... ...
    $out .= $cgi->hidden('rm', 'mode2');
    ... ...
    return $out;

Seems to be OK, just like the example code below, a little bit different though:

$output .= $q->hidden(-name => 'rm', -value => 'mode2');

And if I use a URL like this: "http://www.example.org/cgi-bin/page.cgi?rm=whatever", then the value of the hidden field will now become "whatever".

I thought it was immutable, just like you've written the following line in your code:

$out .= '<input type="hidden" name="rm"  value="mode2"  />';

The truth proved me wrong. So, what's wrong? I decided to read the source code of CGI.pm. Let's walk through the "hidden" subroutine.

sub hidden {
    my($self,@p) = self_or_default(@_);

&self_or_default() doesn't matter here. Now @p contains the list of ('-name', 'rm', '-value', 'mode2'). (I should use qw() instead...)

my(@result,@value);
my($name,$default,$override,@other) = 
    rearrange([NAME,[DEFAULT,VALUE,VALUES],[OVERRIDE,FORCE]],@p);

&rearrange() is the "smart rearrangement" subroutine, it rearranges the @p according to the array reference given as its first argument. (It uses a hash to write down the "name => index" pairs, i.e., where the elements in @p are located (E.g. $pos{NAME} will be 0, $pos{DEFAULT}/$pos{VALUE}/$pos{VALUES} will be 1, etc.), fills them into a "result" array and then return it.) Here, no doubt, $name got 'rm', $default got 'mode2', and $override got an undef.

my $do_override = 0;
if (ref($p[0]) || substr($p[0],0,1) eq '-') {
        @value = ref($default) ? @{$default} : $default;
        $do_override = $override;
} else {
        ... ...
}

substr($p[0],0,1) eq '-' is true, @value now holds 'mode2', $do_override is undef. At first I don't know you can assign a scalar to an array without warnings (I tested & confirmed it with Perl 5.10.1). Maybe it should be written as @value = ref($default) ? @{$default} : ($default);?

my @prev = $self->param($name);
@value = @prev if !$do_override && @prev;

Here I got what I want. @value is now assigned to whatever comes from the CGI parameter with the name of $name ('rm' in this case). And the solution is an easy one:

$output .= $q->hidden(-name => 'rm', -value => 'mode2', -override => 'yes');

After making sure that the code is now running correctly, I read the perldoc again, particularly at "Setting the Value(s) of a Named Parameter":

This sets the value for the named parameter 'foo' to an array of values. This is one way to change the value of a field AFTER the script has been invoked once before. (Another way is with the -override parameter accepted by all methods that generate form elements.)

I also learned the meaning of "override": override the passed-in value with the one you gave to hidden method.

More of the story:

I am pretty sure someone (including me) once wrote the following code to reverse a string:

my $str = "Hello, World!";
my @chars = split '', $str;
my @reversed_chars = reverse @chars;
my $reversed_str = join '', @reversed_chars;
print "reversed_str";

Or in a single line as a proof of progress:

print join '', reverse split '', $str;

If you ever read the perldoc of reverse, it's not hard to figure out a better way of doing this:

print scalar reverse $str;

Read the perldoc carefully (read the source code, the ultimate document, when needed).
RTFM as we all say, it worthing the repeating.

2 Comments

In general you should really try to avoid using CGI.pm to generate HTML. Not only does it have little gotcha's like the override thing (that will bite you over and over again) but it's ties your application down in how it creates and uses the HTML for the front end. Using templates is much more flexible and lets you change things in the front end without having to worry about them in the backend.

It doesn’t tie you down if you do it the right way. Namely, you should have the request processing logic all in one place, and the output generation logic all in another place, and use a data structure to communicate between these parts (filling it in during the first half, then rendering it during the second half). Using templates forces this structure on your code, which is why templates are a good idea for the average developer – but you don’t need them to achieve the same effect.

Leave a comment

About pid

user-pic I blog about Perl.