I apologize for cross posting modules, but CGI::Ex::App from CGI::Ex lets you do it in either of the following ways:
sub allow_morph { 1 }
# OR
my $app = MyApp->new({allow_morph => 1});
That's all. What is then going on behind the scenes is that when a run mode is called ("step" in CGI::Ex::App) the system will see if a corresponding module exists, and if so, will re-bless the object into that class for the duration of the run mode, and then return to its former class after the run mode finishes.
By default the module name of the run mode is the class of the running object combined with the run mode name. So, if my object was called "MyApp" and the run mode was "test_step" the class looked for would be "MyApp::TestStep". This is also easy to override though by providing a module_package hook like this.
sub test_step_module_package { 'MyTestStepModule' }
From this point on the application would use the MyTestStepModule class whenever the test_step_module was needed.
The following is a complete CGI::Ex::App application that allows morphing on each step that will run from commandline, Apache/cgi, or Apache/mod_perl(1&2).
#!/usr/bin/perl -w
package Foo;
use strict;
use warnings;
use base qw(CGI::Ex::App);
Foo->navigate;
sub allow_morph { 1 }
package Foo::Main;
use base qw(Foo);
sub file_print { return \ "Great! You got here!\n" }
Which would print the following when run from the commandline.
Content-Type: text/html
Great! You got here!
To see everything that occurred behind the scenes you could add the following lines of code to the Foo class:
use CGI::Ex::Dump qw(debug);
sub post_navigate {
debug shift->dump_history;
}
In addition to the previous output, you would now also see something similar to the following:
debug: cgi-bin/foo.pl line 15
shift->dump_history = [
"Elapsed: 0.07506",
"main - morph - morph (changed Foo to Foo::Main) - 0.00000
+ - 1",
"main - morph_package - morph_package - 0.00004 - Foo::Mai
+n",
"main - run_step - run_step - 0.03927 - 1",
" main - pre_step - pre_step - 0.00001 - 0",
" main - skip - skip - 0.00001 - 0",
" main - prepare - prepare - 0.00001 - 1",
" main - info_complete - info_complete - 0.00005 - 0",
" main - ready_validate - ready_validate - 0.00001
+- 0",
" main - prepared_print - prepared_print - 0.03901 - 1"
+,
" main - hash_base - hash_base - 0.00005 - HASH(0x8
+31890c)",
" main - hash_common - hash_common - 0.00001 - {}",
" main - hash_form - hash_form - 0.00002 - {}",
" main - hash_fill - hash_fill - 0.00001 - {}",
" main - hash_swap - hash_swap - 0.00001 - {}",
" main - hash_errors - hash_errors - 0.00001 - {}",
" main - print - print - 0.03871 - 1",
" main - file_print - file_print - 0.00001 - SC
+ALAR(0x825f7a0)",
" main - swap_template - swap_template - 0.0348
+8 - Great! You got here!\n",
" main - template_args - template_args - 0.
+00001 - HASH(0x8335aac)",
" main - fill_template - fill_template - 0.0031
+9 - 1",
" main - fill_args - fill_args - 0.00001 -
+{}",
" main - print_out - print_out - 0.00047 - 1",
" main - post_print - post_print - 0.00001 - 0",
"main - unmorph - unmorph (changed from Foo::Main to Foo)
+- 0.00000 - 1"
];
The interesting portion is the morph line where it says it was changed from Foo to Foo::Main and the unmorph line where it was changed from Foo::Main back to Foo. We have been using this in production (well not this exact example) for a number of years and it has served us very well. I'm sure something vaguely similar exists for CGI::Application, and if not, it should be possible to add it.
my @a=qw(random brilliant braindead); print $a[rand(@a)];
|