RE: [cgiapp] Subclassing form, futher thoughts
Hi Sebastian -- Now, my index.cgi would look like this: #!/usr/bin/perl use CGI qw(:standard); my $q = new CGI; my $modules = { sales = 'Sales', invent = 'Inventory', }, }; # Set a default $q-param('mod' = 'main') unless $q-param('mod'); # Dynamically pull in the right section's module require ComponentManager/$modules-{$q-param('mod')}{load}.pm; # And fire it off my $app = ComponentManager::$modules-{$q-param('mod')}{load}-new($q); $app-run(); It looks like you're well on your way to building quite the Rube Goldberg machine! If I understand what you're trying to do, if you want to run your Sales app, you would make a request like this: http://my.site/index.cgi?mod=sales ...For Inventory, you would do this: http://my.site/index.cgi?mod=invent Tell me -- what is the advantage of doing that instead of doing: http://my.site/sales.cgi http://my.site/invent.cgi The latter would have two advantages. First, this is how CGI::Application (or a sub-class thereof) wants to work. Second, your instance script (sales.cgi or invent.cgi -- instead of index.cgi) becomes MUCH more simple: #!/usr/bin/perl -w use Sales; my $app = Sales; $app-run(); What could be more simple than that? What does this system NOT do that your system does? I would seriously consider taking about twelve paces BACK and re-evaluating your architecture. CGI::Application is intended to make your code EASY -- not turn it into a interconnected snarl of undocumented dependencies. In general, if your instance script looks more complicated than what I've written above, you're probably doing something wrong. So far, the above seems like it will be a good solution. On another note, I would however like to pass html to run() at the base-class level, and have it place it in the output appropriately. There is currently no way to do that gracefully, because the http headers are built into the run method. Why on earth would you want to put *ANY* HTML in your code? And assuming you have a good reason, why would you pass it through run()? One thought that comes to mind is to have run() accept two scalars, the values being strings that it prepends and appends, respectively, to the runmode's output. Don't know how great an idea that is. Don't try to override the run() method. Don't do it! It is not intended to be used this way. It may change in future version. Heck, I might change it out of spite! :-) Another possibility might be to, within the run() sub, simply store the return value of cgiapp_prerun(), to be output just before the run-mode's return value. That would solve the header problem, and for any common footers we could just use teardown(). There are a lot of ways to do what you want to do without breaking the CGI::Application architecture all over the place. For starters, HTML::Template supports a TMPL_INCLUDE tag which will pull in external HTML. If you don't like H:T, most other templating systems have similar features. And you *should* be using a templating system! If you've never used one, STOP EVERYTHING and go read the POD for HTML::Template, right now! Don't write another line of code before you know how to use it! TTYL, -Jesse- - Web Archive: http://www.mail-archive.com/cgiapp@lists.vm.com/ To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
Re: [cgiapp] Subclassing form, futher thoughts
On Wed, 12 Jun 2002 11:15:01 -0400, Jesse Erlbaum [EMAIL PROTECTED] spoke gently: Hi Sebastian -- Now, my index.cgi would look like this: #!/usr/bin/perl use CGI qw(:standard); my $q = new CGI; my $modules = { sales = 'Sales', invent = 'Inventory', }, }; # Set a default $q-param('mod' = 'main') unless $q-param('mod'); # Dynamically pull in the right section's module require ComponentManager/$modules-{$q-param('mod')}{load}.pm; # And fire it off my $app = ComponentManager::$modules-{$q-param('mod')}{load}-new($q); $app-run(); It looks like you're well on your way to building quite the Rube Goldberg machine! If I understand what you're trying to do, if you want to run your Sales app, you would make a request like this: http://my.site/index.cgi?mod=sales ...For Inventory, you would do this: http://my.site/index.cgi?mod=invent Tell me -- what is the advantage of doing that instead of doing: http://my.site/sales.cgi http://my.site/invent.cgi The latter would have two advantages. First, this is how CGI::Application (or a sub-class thereof) wants to work. Second, your instance script (sales.cgi or invent.cgi -- instead of index.cgi) becomes MUCH more simple: #!/usr/bin/perl -w use Sales; my $app = Sales; $app-run(); The primary loss is the single point of access. I could live with that, and simple is Good(tm), but when I see a dozen nearly identical CGI scripts in a directory I don't think simple, I think Hmmm, _one_ would be better. What could be more simple than that? What does this system NOT do that your system does? I would seriously consider taking about twelve paces BACK and re-evaluating your architecture. CGI::Application is intended to make your code EASY -- not turn it into a interconnected snarl of undocumented dependencies. In general, if your instance script looks more complicated than what I've written above, you're probably doing something wrong. Architecturally, my example above is actually quite simple, and could easily work in a single pm file, using base run-modes like 'SALES_LIST' or 'INVENT_SAVEITEM'...etc. I only implemented the dynamic loading to ease administration, personally I hate working in files longer that a few thousand lines, and this project will easily outgrow that in total. On another note, I would however like to pass html to run() at the base-class level, and have it place it in the output appropriately. There is currently no way to do that gracefully, because the http headers are built into the run method. Why on earth would you want to put *ANY* HTML in your code? And assuming you have a good reason, why would you pass it through run()? I guess I was not clear. I'm not putting html in my code. The desired result is that I want to print a common header, without specifying it each time in each run-mode sub. I think the easiest way would be to allow cgiapp_prerun() to optionally return html, _just like any other runmode does_. C::A-run() could print it just before it prints the runmode sub's output, thereby providing a hook for for printing common content each time. Don't try to override the run() method. Don't do it! It is not intended to be used this way. It may change in future version. Heck, I might change it out of spite! :-) :) Another possibility might be to, within the run() sub, simply store the return value of cgiapp_prerun(), to be output just before the run-mode's return value. That would solve the header problem, and for any common footers we could just use teardown(). There are a lot of ways to do what you want to do without breaking the CGI::Application architecture all over the place. For starters, HTML::Template supports a TMPL_INCLUDE tag which will pull in external HTML. If you don't like H:T, most other templating systems have similar features. And you *should* be using a templating system! If you've never used one, STOP EVERYTHING and go read the POD for HTML::Template, right now! Don't write another line of code before you know how to use it! I do use HTML::Template. My CGI's usually have three HTML::Template objects: a header, content, and footer. I realize that each of my content templates could just TMPL_INCLUDE the header and footer files, but I choose not to do it that way, for maintenance reasons. When things change, it can be a big can of worms. I see no reason that my content templates should have to know anything about the framework/headers/footers of the site. They should be autonomous, pluggable anywhere. Isn't that how the rest of the world does it? I realize that, using my multiple template objects, each of my run-modes could... return $app-param('header')-output() . $app-param('content')-output() . $app-param('footer')-output(); ...and I may end up doing just that. It would have the benefit, for example,
Re: [cgiapp] Subclassing form
Why not just create an AUTOLOAD parameter, and return your header, desired application output, and footer from that function. For example (untested, buyer beware), $self-run_modes('AUTOLOAD' = 'header_body_footer'); sub header_body_footer { my ($self, $rm, @rest) = @_; ... return $self-props('header') . do_runmode($rm) . $self-props ('footer'); } This circumvents some of the benefits of using C::A, but may work for your purposes. Brian [EMAIL PROTECTED] mTo: [EMAIL PROTECTED] cc: 06/10/02 06:08 Subject: [cgiapp] Subclassing form PM I'm just looking into CGI::Application, and after reading the pod and viewing the code, I have two main questions... (1) Should there be a NO_HEADERS and/or NO_OUTPUT (or similar) parameter that the run() method takes? I ask for two reasons: A. If I want to override the run method, for instance to print a standard header/footer each time the app is run(), I would imagine that it go like this: package My::App; use base 'CGI::Application'; sub new { my $class = shift; my $s = $class-SUPER::new(@_); $s-param('header' = $s-load_tmpl('header_common.html')); $s-param('footer' = $s-load_tmpl('footer_common.html')); return $s; } sub run { my $s = shift; print $s-_send_headers(); # Shouldn't this be a public method? # Print the head template print $s-param('header'); # Now call C::A's run method... $s-SUPER::run(NO_HEADERS= 1); # or maybe... print $s-SUPER::run(NO_HEADERS= 1, NO_OUTPUT = 1); # or even $s-param('NO_HEADERS' = 1); $s-SUPER::run(); # Now print the footer template print $s-param('footer'); } B. If I have a hierarchy of C::A objects, the second (or third, gasp) won't need to print an HTTP header at all. (2) Lastly, on the heels of #B above: How do _you_ implement an app hierarchy? An application has different modules (sectional groupings of functionality.) Sales, Inventory, Reports, etc, each having it's own set of run-modes, or even sub-modules with sub-run-modes. I'd like to use the same URL for the whole shebang. I envision the base app's run-mode being a param called module with a value like sales, then the base app can dynamically load the proper 'sub app' code and object, then that $subapp runs off with a second traditional run-mode to do stuff. Or should I just use run-mode values like: 'Parts_Save' or 'Jobs_List' or 'Reports_JobTotals' Then I could use $app-prerun() to trim off the first part, load the specified code library, then run prerun_mode to save the trimmed run-mode back to app object. Am I way off base? TIA Sebastian - Web Archive: http://www.mail-archive.com/cgiapp@lists.vm.com/ To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED] - Web Archive: http://www.mail-archive.com/cgiapp@lists.vm.com/ To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
[cgiapp] Subclassing form
I'm just looking into CGI::Application, and after reading the pod and viewing the code, I have two main questions... (1) Should there be a NO_HEADERS and/or NO_OUTPUT (or similar) parameter that the run() method takes? I ask for two reasons: A. If I want to override the run method, for instance to print a standard header/footer each time the app is run(), I would imagine that it go like this: package My::App; use base 'CGI::Application'; sub new { my $class = shift; my $s = $class-SUPER::new(@_); $s-param('header' = $s-load_tmpl('header_common.html')); $s-param('footer' = $s-load_tmpl('footer_common.html')); return $s; } sub run { my $s = shift; print $s-_send_headers(); # Shouldn't this be a public method? # Print the head template print $s-param('header'); # Now call C::A's run method... $s-SUPER::run(NO_HEADERS= 1); # or maybe... print $s-SUPER::run(NO_HEADERS= 1, NO_OUTPUT = 1); # or even $s-param('NO_HEADERS' = 1); $s-SUPER::run(); # Now print the footer template print $s-param('footer'); } B. If I have a hierarchy of C::A objects, the second (or third, gasp) won't need to print an HTTP header at all. (2) Lastly, on the heels of #B above: How do _you_ implement an app hierarchy? An application has different modules (sectional groupings of functionality.) Sales, Inventory, Reports, etc, each having it's own set of run-modes, or even sub-modules with sub-run-modes. I'd like to use the same URL for the whole shebang. I envision the base app's run-mode being a param called module with a value like sales, then the base app can dynamically load the proper 'sub app' code and object, then that $subapp runs off with a second traditional run-mode to do stuff. Or should I just use run-mode values like: 'Parts_Save' or 'Jobs_List' or 'Reports_JobTotals' Then I could use $app-prerun() to trim off the first part, load the specified code library, then run prerun_mode to save the trimmed run-mode back to app object. Am I way off base? TIA Sebastian - Web Archive: http://www.mail-archive.com/cgiapp@lists.vm.com/ To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]