Discussion:
[cgi-prototype-users] changing page with respond
Carl Franks
2005-08-15 21:49:13 UTC
Permalink
I find that if I try to change the current page, by returning a
different value from 'respond', it dies with "initialize_CGI not
called".
I think this is because when the new page's package is required, it
reruns the code in CGI/Prototype.pm which add's the 'dummy' CGI slot
which dies with that exact error message.

(I thought that a module's body was only run once, for the first 'use'
or 'require', but I can't see any other explanation for what's
happening).

Am I doing this correctly?
Should I file a bug report on rt?

(Sample code below).

Cheers,
Carl


# file One.pm
package One;
use warnings;
use strict;
use base 'CGI::Prototype';

sub respond {
require Two;
return 'Two';
}

1;

# file Two.pm
package Two;
use warnings;
use strict;
use base 'CGI::Prototype';

sub template {
return \'[% self.CGI.header %]Two';
}

1;

# file test.t
#!/usr/bin/perl
use strict;
use warnings;
use CGI::Prototype::Mecha;
use Test::More tests => 2;
use Data::Dumper;
use lib '.';

my $t = CGI::Prototype::Mech->new( protoapp => 'One' );

$t->get( 'http://mecha/' );

ok $t->success;
ok $t->res =~ 'Two';

print STDERR Dumper $t->res;
Carl Franks
2005-08-16 09:33:27 UTC
Permalink
Ok, I've figured out what was going wrong and how to fix it, however
it's brought up another issue.

Firstly, my apologies that the code I posted didn't run - it was
copy-typed from one machine to another.
The line:
my $t = CGI::Prototype::Mech->new( protoapp => "One" );
should have read:
my $t = CGI::Prototype::Mecha->new( protoapp => "One" );


The problem was caused, because CGI::Prototype does:

our $_mirror = __PACKAGE__->reflect;

$_mirror->addSlot
(CGI => sub { die shift, "->initialize_CGI not called" });

which adds the dummy CGI slot to the CGI::Prototype __PACKAGE__,
but then the initialize_CGI method adds the real CGI slot to $self,
which is the package 'One'...

sub initialize_CGI {
my $self = shift;
$self->reflect->addSlot
([qw(CGI FIELD autoload)] => sub {
require CGI;
CGI::_reset_globals();
CGI->new;
});
}

When control passes to $next_page, which is package 'Two', it
inherit's CGI::Prototype's dummy CGI slot, but not the 'real' CGI slot
which is in 'One'.

The solution to that is to change the line in CGI::Prototype's
initialize_CGI from:
$self->reflect->addSlot
to:
$_mirror->addSlot

When this is done, the application works correctly.

However, my test file still does not pass... this is because in
CGI::Prototype::Mecha's 'new' method, it overrides the 'display' slot
for package 'One' (the protoapp that is passed).
When control passes to 'Two', it doesn't have the overridden 'display'
method, and so uses it's inherited 'display' from CGI::Prototype,
which prints to STDOUT.

Does anyone have any thoughts on how to deal with this?
Though, I admit to not being /too/ concerned about it, because my test
suite uses WWW::Mechanize through a real webserver.

I will post my suggested change to the initialize_CGI method to rt.

Cheers,
Carl
Randal L. Schwartz
2005-08-17 18:49:40 UTC
Permalink
Carl> Ok, I've figured out what was going wrong and how to fix it, however
Carl> it's brought up another issue.

Carl> Firstly, my apologies that the code I posted didn't run - it was
Carl> copy-typed from one machine to another.
Carl> The line:
Carl> my $t = CGI::Prototype::Mech->new( protoapp => "One" );
Carl> should have read:
Carl> my $t = CGI::Prototype::Mecha->new( protoapp => "One" );

The problem here is probably one of documentation. Your protoapp
doesn't exist, that's why it's broken. It's not One, because Two
doesn't inherit from One.

You need your app, from which your pages inherit. Then the
display method gets added into the right place.
--
Randal L. Schwartz - Stonehenge Consulting Services, Inc. - +1 503 777 0095
<***@stonehenge.com> <URL:http://www.stonehenge.com/merlyn/>
Perl/Unix/security consulting, Technical writing, Comedy, etc. etc.
See PerlTraining.Stonehenge.com for onsite and open-enrollment Perl training!
Loading...