metaperl has asked for the wisdom of the Perl Monks concerning the following question:
I found that looking through the test suite and the actual code was a lot easier than reading the docs! You might do the same before asking any questions. However, even after such research, I still have a few ants in my pants before getting down to business with CGI::Prototype.
When I read the docs, I was wondering why none of the methods appeared to have arguments. For example, I read this:
The render method uses the results from engine and template to process a selected template through Template Toolkit.
and I was wondering why the arguments were not shown alongside the method name like:
render ($engine, $template)
and it is because render() uses the slots engine and template from the default CGI::Prototype prototype object:
sub render { my $self = shift; my $tt = $self->engine; my $self_object = $self->reflect->object; # in case we have a classn +ame $tt->process($self->template, { self => $self_object }, \my $output) or die $tt->error; # passes Template::Exception upward $self->display($output); }
but in retrospect, nothing about this method requires $self to be an object with slots. $self could simply be a class name.
CGI::Prototype ships with this template method:
sub template { '[% self.CGI.header %]This page intentionally left blank.'; }
This is mixing concerns. Some of this output is for negotiating the CGI protocol and some is page-specific output. Also, some of this output is constant from page to page while another part is page-local.
It would have been nice to show the utility of CGI::Prototype's fine-grained series of callbacks by separating raw template output from output required for negotiating the CGI protocol.
I think render_enter would be a good place for the CGI information, while the page-local information does belong in template.
The docs say:
Called when a page gains control, either at the beginning for a response, or in the middle when switched for rendering. Defaults to + nothing.
There are two ways I became confused about this. The first was from trying to read it and understand it. The second was after looking at the activate() method.
I'm going to work through this phrase-by-phrase, to show you my confusion:
sub dispatch { my $self = shift; $self->param('rm') eq 'Webmail' and return 'Local::Page::Webmail' ; return 'Local::Page::Welcome'; }
However, I was not able to gain this knowledge until I studied the CGIP-flow.t test case closely. The docs are really too terse on this point.
Perhaps you could provide some checkpoints into sub activate showing where each possibility conjectured by the word ``either'' occur. Code is here for your convenience:
sub activate { my $self = shift; eval { $self->app_enter; my $this_page = $self->dispatch; $this_page->control_enter; $this_page->respond_enter; my $next_page = $this_page->respond; $this_page->respond_leave; if ($this_page ne $next_page) { $this_page->control_leave; $next_page->control_enter; } $next_page->render_enter; $next_page->render; $next_page->render_leave; $next_page->control_leave; $self->app_leave; }; $self->error($@) if $@; # failed something, go to safe mode }
render() should push its output into a slot so that so that render_leave can get it and process it.
Besides breaking with the slot-orientation that pervades this module's design up to now, render() calls display () instead of display being called at the top level from activate().
Just in case render_leave() wants to do some touch-up, no display should be done until all rendering phases are complete.
Of course, the nice thing about CGI::Prototype is that everything I am talking about can be done in my root class for my application based on CGI::Prototype.
The docs say ``Invoking $self->CGI gives you access to the CGI.pm object representing the incoming parameters''
but it not clear how $self is obtained or what namespace it exists in.
And that leads to my biggest issue with CGI::Prototype --- the use of prototyped instead of class-based objects. It is not clear what this approach added. Actually let me help you out here. Instead of having to haul in a module to handle lazy-loading: http://www.metaperl.com/article-pod/Catalog-lazy_loaders/lazy_loaders.html you could simply defer this functionality an protoyped-objects autoload slot.
Fewer people are familiar with this approach to objects. And the use of them was confusing to me as I explain next
I read your article:
http://www.stonehenge.com/merlyn/LinuxMag/col56.html as well as the Class::Prototyped docs. However I still have some issues with the implementation of CGI::Prototype
First, you have a normal Perl package which has subroutines which are written just like any normal class-based object-oriented Perl package would have. But you also do this:
our $_mirror = __PACKAGE__->reflect; # for slots that aren't subs
and then access the mirror twice:
$_mirror->addSlot ([qw(CGI FIELD autoload)] => sub { # must be reset in mod_perl require CGI; CGI->new; });
$_mirror->addSlot ([qw(engine FIELD autoload)] => sub { my $self = shift; require Template; Template->new or die "Creating tt: $Template::ERROR\n"; + });
am I to understand that you have created a prototyped-based object with
app_enter app_leave control_enter control_leave render_enter render_leave respond_enter respond_leave
as slots created by normal Perl subroutines and two additional on-demand slots named CGI and engine?
If so, the please tell me how I can overwrite the engine method in my subclasses.
I wrote a simple script which returned a simple page:, but when I attempted to access the object and grok with it's slots, I had some problems, which are explained in the script.
I think the docs could use some information like this but would appreciate some feedback on this very quickly please
#!/usr/bin/perl BEGIN { my $path='~/perl/lib:~/perl:~/perl/share/perl/5.8.4:~/perl/lib/perl/ +5.8.4'; for my $p (split ':', $path) { $p =~ s!~!/home/terry!; warn $p; unshift @INC, $p; } warn "@INC"; } use base qw(CGI::Prototype); my $o = __PACKAGE__->reflect; # The next line returns # Class::Prototyped::Mirror=REF(0x816811c) at nullapp.pl line 23. # Why does it not return CGI::Prorotype::Mirror=REF # or main::MIRROR=REF warn $o; # Why does this fail? warn $o->engine; warn $o->display('hi'); CGI::Prototype->activate;
Even though I am having some problems on the learning curve with CGI::Prototype, I cannot wait until I can cleanly handle authentication-based rendering and business logic in the appropriate callbacks.
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re: CGI::Prototype: questions and feedback
by cbatjesmond (Novice) on Jan 29, 2005 at 17:02 UTC | |
by merlyn (Sage) on Jan 29, 2005 at 17:30 UTC | |
by metaperl (Curate) on Jan 29, 2005 at 22:17 UTC | |
|
Re: CGI::Prototype: questions and feedback
by dynamo (Chaplain) on Jan 29, 2005 at 00:24 UTC | |
|
Re: CGI::Prototype: questions and feedback
by metaperl (Curate) on Jan 29, 2005 at 16:19 UTC | |
|
Re: CGI::Prototype: questions and feedback
by cbatjesmond (Novice) on Jan 31, 2005 at 01:25 UTC | |
|
Re: CGI::Prototype: questions and feedback
by metaperl (Curate) on Jan 29, 2005 at 16:32 UTC | |
|
Re: CGI::Prototype: questions and feedback
by metaperl (Curate) on Jan 30, 2005 at 02:46 UTC |