Issues with CGI::Prototype

reading the code is clearer than reading the docs

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.

emphasize slots not arguments

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 protocol information should be in separate phase

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.

control_enter's docs are confusing:

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:

  • ``Called when a page gains control''
  • What you mean is a page (synonomous with package in your docs) gains control when dispatch returns a string representing it. For example, given the ``pages'' Local::Page::Welcome, Local::Page::News, Local::Page::Webmail, we issue control to one of these pages like so:
    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.

  • ``...Switched for rendering?''
  • What is switched for rendering? Under what conditions is it switched for rendering? Even after looking at activate() and the test suite, I don't know what you mean by switched for rendering and when such a switch might occur.

  • ``either at the beginning for a response, or in the middle when switched for rendering. ''
  • Am I to take this to mean that a page can gain control at either of these times? How do I know which of the times (beginning of response or middle) it is begin called? Also, you say ``in the middle''... in the middle of what? Also, you say ``either''... when you say either what leads to one of the selections being made.

    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 broke with the slot-oriented tradition

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.

Core slot CGI

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

prototype-based objects

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;


THE FUTURE

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.


In reply to CGI::Prototype: questions and feedback by metaperl

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.