Beefy Boxes and Bandwidth Generously Provided by pair Networks
good chemistry is complicated,
and a little bit messy -LW
 
PerlMonks  

comment on

( [id://3333]=superdoc: print w/replies, xml ) Need Help??

I've been taking my first steps with merlyn's CGI::Prototype, which I find pretty nice overall, but I'm running into a conceptual block here. In summary: inheritance doesn't work as I expect. Not even Class::Prototyped-type inheritance. In fact, I can't figure out how inheritance works with CGI::Prototype!

The script and module below illustrate the problem.

I'll describe the script first. Most of it is assignments and definitions. Things don't get moving until the call to activate at the very end. Users of CGI::Prototype will find this pattern familiar. They will also recognize the methods defined in package Zero in the middle block as being among those called by CGI::Prototype::activate.

# cgi.pl use strict; use warnings; @One::ISA = @Two::ISA = 'Zero'; { package Zero; use base 'CGI::' . shift; sub dispatch { shift->param ? 'Two' : 'One'; } sub render { print my $self = shift, "\n"; print "$_: " . $self->param( $_ ) . "\n" for $self->param; } } @MY_Zero::ISA = 'Zero'; shift->activate; __END__

Passing the string 'Prototype' as the first argument to the script will cause Zero to be a subclass of CGI::Prototype. (The package I define below is called CGI::Classic, so 'Classic' is another meaningful value to pass as the first argument to the script.)

The dispatch method, which is called by the inherited activate method, returns 'One' if there are no CGI parameters, and 'Two' otherwise. Eventually this will result in the execution of either One->render or Two->render, as the case may be. The render method as defined in Zero prints the caller and the CGI params, if any.

In its next-to-last step the script defines another subclass of Zero, called 'MY_Zero'. Finally, it calls activate on the class passed as the script's second argument. Subsequent arguments, if any, should be in the form of 'key=value' strings.

With 'Prototype' as first argument, things work as expected if the second argument is 'Zero':

% perl cgi.pl Prototype Zero
One
% perl cgi.pl Prototype Zero foo=1 bar=2
Two
foo: 1
bar: 2

...but bomb if the second argument is 'MY_Zero':

% perl cgi.pl Prototype MY_Zero
One
Content-type: text/plain

ERROR: Two->initialize_CGI not called at /usr/lib/perl5/CGI/Prototype.pm line 173.

To show what I had expected to happen, I defined CGI::Classic. This module is, first, a drastically simplified toy version of CGI::Prototype. In particular, its (tiny) activate method doesn't even follow the original's logic (e.g. no testing of the result of the respond method, etc.). But the most fundamental difference between CGI::C and CGI::P is that CGI::C does not use Class::Prototype at all:

# CGI/Classic.pm use strict; use warnings; { package CGI::Classic; use CGI; my $CGI; sub activate { $CGI = CGI->new; shift->dispatch->render; } sub param { shift; $CGI->param( @_ ) }; sub dispatch { die 'subclass responsibility' } sub render { die 'subclass responsibility' } } 1; __END__

Now the script works with both 'Zero' and 'MY_Zero' as second argument.

% perl cgi.pl Classic MY_Zero
One
% perl cgi.pl Classic MY_Zero foo=1 bar=2
Two
foo: 1
bar: 2
% perl cgi.pl Classic Zero baz=3 frobozz=4
Two
baz: 3
frobozz: 4

I guessed that the problem resulted from the fact that Class::Prototyped uses a model of inheritance that is different from Perl's standard model, so I also tried a version of the script in which the last call to activate has the following form:

shift; # discard script's second argument Zero->new( 'parent*' => 'Zero' )->activate;

...but I get the same error as before.

Here's where I run out of steam. I find the innards of Class::Prototyped pretty difficult to understand, and I'm not even sure that that's were the problem is.

I ran into this problem when I tried to write a test script for some CGIP-based classes. I wanted to override some methods of the main class for testing, and that's when I created a class analogous to 'MY_Zero' above.

So I have a question and a comment. The question is: how do I do what I want to do (i.e. create a subclass of my main class for the purpose of overriding its methods for testing)? The comment is that the problem illustrated above strikes me as pretty serious, because it completely defeats reasonable expectations about how inheritance should work.

(Something tells me I'm going to learn a lot of Perl soon...)

the lowliest monk


In reply to Subclassing and CGI::Prototype by tlm

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



  • Are you posting in the right place? Check out Where do I post X? to know for sure.
  • Posts may use any of the Perl Monks Approved HTML tags. Currently these include the following:
    <code> <a> <b> <big> <blockquote> <br /> <dd> <dl> <dt> <em> <font> <h1> <h2> <h3> <h4> <h5> <h6> <hr /> <i> <li> <nbsp> <ol> <p> <small> <strike> <strong> <sub> <sup> <table> <td> <th> <tr> <tt> <u> <ul>
  • Snippets of code should be wrapped in <code> tags not <pre> tags. In fact, <pre> tags should generally be avoided. If they must be used, extreme care should be taken to ensure that their contents do not have long lines (<70 chars), in order to prevent horizontal scrolling (and possible janitor intervention).
  • Want more info? How to link or How to display code and escape characters are good places to start.
Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others sharing their wisdom with the Monastery: (5)
As of 2024-03-28 16:35 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found