Beefy Boxes and Bandwidth Generously Provided by pair Networks
more useful options
 
PerlMonks  

Developing CGI::Application based modules outside of the default @INC

by LesleyB (Friar)
on Apr 09, 2008 at 17:24 UTC ( [id://679305]=perlquestion: print w/replies, xml ) Need Help??

LesleyB has asked for the wisdom of the Perl Monks concerning the following question:

Hi

I have this instance script

#!/usr/bin/perl -T use Bufferlass; use lib '/home/pgcroft/sites/bufferlass.org.uk/trunk/src/'; use strict; use warnings; ## The Instance script ## can contain ## new(), run(), ## new make take the params TMPL_PATH, QUERY, PARAMS as hashes of valu +es ## e.g. TMPL_PATH => 'MyApp/' ## QUERY is an already existing CGI query object ## PARAMS => { 'custom_thing_1' => 1, 'custom_thing_2' => '20 +', 'another' => qw/123 456/ } my $bufferlass = Bufferlass->new(); $bufferlass->run();

and this module

package Bufferlass::Bufferlass; use base 'CGI::Application'; use strict; ## ## methodology ## Subclassing and Override mehods. ## this module must define the setup(), teardown(), cgiapp_init(), cgi +app_prerun(), cgiapp_postrun(), cgiapp_get_query(), delete() ## Application Module Methods ## delete(), dump(), dump_html(), error_mode(), get_current_runmode(), + header_add(), header_props(), header_type(), load_tmpl() ## mode_param(), param(), prerun_mode(), query(), run_mode(), start_mo +de(), tmpl_path() # ## ## Subclassing and Override methods ## sub setup { ## called by inherited new structure ## should contain ## mode_param() ## start_mode() ## error_mode() ## run_modes() ## tmpl_path() ## is a good place to to define properties specific to the application + using the $webapp->param() approach ## can simply be a defn of run_modes and start_mode } sub teardown { ## called *automatically* after application runs ## clean up after operations ## e.g. disconnect database connection established in setup() ## can also be used to store info about the app on server } sub cgiapp_init { ## called *automatically* just before the setup() me +thod ## provides an optional initialisation hook ### receives all the parameters sent to the new() method ## could be used in an application superclass which inherits CGI::Appl +ication then base all web-based applications on this. ## thereby having a suite of applications that share particular charac +tertistics } sub cgiapp_prerun { ## called *automatically* before a selected run_mo +de ## provides an optional pre_run mode hook ## receives the value of the run_mode ## as with cgiapp_init the cgiapp_prerun could be places in a supercla +ss based on CGI::Application ## subsequent applications based on the superclass would then inherit +similar characeritsics. } sub cgiapp_postrun { ## will be called after a run_mode has finished b +ut before HTTP headers are generated ## receives a reference to output from a run method in addition to the + CGI-App object ## useful when ## want to emclose the output in further HTML ## run_mode returns structured data such as XML which needs to be t +ransformed in some way e.g. via XSLT ## post-process CGI-App output through something like HTML::Mason ## need to modify HTTP headers in a particular way across all run_m +odes ## have access to all CGI-App object methods normally available in a r +un_mode ## could use load_tmpl() to change the template used ## could change the headers to a redirect via header_type() and header +_prop() methods. ## could make changes only when in a certain run_mode and with certain + param() value . } sub cgiapp_get_query { ## loads CGI.pm via require. ## returns a CGIquery object ## can be overridden to use a different query object which must be com +patible with CGI.pm or wrap chosen ## query interface in a wrapper class to achieve compatibility } ## ## Inherited Methods ## sub delete { ## deletes a parameter previously stroed via PARAMS param +eter to new() or param() method. ## Useful where application makes decisions on existence of certain pa +rameters } sub dump { ## debugging function ## retruns text containing the environment and web-form data of the re +quest ## human readable format } sub dump_html { ## debugging function ## returns environment and web-form data of request ## human readable via browser } sub error_mode { ##contains name of run_mode to call when planned run_ +mode fails ## death not trapped so can die here } sub get_current_runmode { ## returns name of run_mode being run as tex +t scalar ## will return undef if the run mode has not been initialised e.g. in +setup() } sub header_add { ## adds headers to the outgoing response headers. ## refer to CGI.pm docs on header() for exact usage. ## preserves existing headers, ## scalar value replaces existing value for that key ## array ref values appended to existing values for that key ## useful for setting an additional cookie after one has been set } sub header_props { ## expects a hash of CGI.pm compatible HTTP header +properties ## these values will be passed to the CGI.pm header() and redirect() m +ethods ## clobbers existing headers ## works in conjunction with header_type() method } sub header_type { ## expects 'header', 'redirect', 'none' ## specifies type of header to be sent back to browser ## defaults to header ## 'none' hides headers } sub load_tmpl { ## expects name of a template file, reference to templ +ate data or a FILEHANDLE ## returns an HTML::Template object ## defaults to the name of the run_mode with the extension '.html' if +argument not found ## uses HTML::Template methods for arguments ## sets HTML::Template path option if tmpl_path() value set ## sends remaining parameters to relevant HTML::Template method ## can be overrridden to enable use of other templating systems such a +s TT or Petal } sub mode_param { ## accessor/mutator method ## generally called via setup() ## determines run mode to call ## takes string, code reference, or uses $ENV{PATH_INFO} via path_info + => n } sub param { ## sets application instance properties accessible through +out application ## sets or gets ## retruns an array of all currently existing paramaetrs if used in ar +ray context ## set lots of params using hash or hashref ## useful where similar applications need to share code base } sub prerun_mode { ## accessor/mutator changing the run mode about to b +e executed ## e.g. force back to login page ## may only be called in the context of a cgiapp_prerun() method. } sub query { ## retrieves CGI.pm query object ## new() method creates one automagically or uses that of the QUERY pa +rameter } sub run_modes { ## accessor/mutator specifies dispatch table for appli +cation states ## arrayref of run mode names that represent the subroutine names dire +ctly ## hashref allows use of anternative name or code ref ## can be called multiple times with new values for existing run_modes + overwriting existing values ## and adding new ones ## run method uses this data to send application to correct function b +y reading the CGI paramater specified by mode_param() ## and defaults to 'rm' for run mode. ## use AUTOLOAD to catch exceptions on non-existent run modes } sub start_mode { ## contains the name of mode as specified by the run_ +modes() table ## The mode key specified here will be used whenever the value of CGI +form parameter specified bu mode_param() ## is not defined - typically the first time an application is execute +d. } sub tmpl_path() { ## accessor/mutator sets/gets path to directories wh +ere templates are stored ## accepts text scalar or array ref of multiple paths. ## used by load_templ to find template files ## uses HTML::Template path option } 1;

I would really like to develop outside the /var/www and standard @INC directories - just to get the basics working.

Hence the use lib '...'; statemnt in the instance script. However I get the error

Can't locate Bufferlass.pm in @INC (@INC contains: /etc/perl /usr/loca +l/lib/perl/5.8.8 /usr/local/share/perl/5.8.8 /usr/lib/perl5 /usr/shar +e/perl5 /usr/lib/perl/5.8 /usr/share/perl/5.8 /usr/local/lib/site_per +l) at ./bufferlass.cgi line 2. BEGIN failed--compilation aborted at ./bufferlass.cgi line 2.

which means that my module is not being seen and the path to it doesn't appear to be added to @INC.

The directory structure is

./bufferlass.cgi

./Bufferlass/Bufferlass.pm

I've managed to get progress using

perl -T -I/home/pgcroft/sites/bufferlass.org.uk/trunk/src/Bufferlass +bufferlass.cgi Can't locate object method "new" via package "Bufferlass" at bufferlas +s.cgi line 15.

which I am happier with (although I have yet to understand how to fix that error). At least the -I argument works.

This problem is symptomatic of previous problems I have had developing modules. Everything works okay if I use the default include directories but I would really rather not while in development. I would rather be able to specify the directory containing the module's directory and subsequent subdirs i.e. /path/to/directory/containing/module/ because this allows me wider scope that having to declare the path to each and every module as in

/path/to/directory/containing/module/Module1/

/path/to/directory/containing/module/Module2/

How can I achieve this?

I hope whatever I am doing wrong is obvious to the wise here.

Regards

L.

Replies are listed 'Best First'.
Re: Developing CGI::Application based modules outside of the default @INC
by runrig (Abbot) on Apr 09, 2008 at 17:37 UTC
    use Bufferlass; ... my $bufferlass = Bufferlass->new();
    Your module/package is named Bufferlass::Bufferlass, and its relative file path is Bufferlass/Bufferlass.pm. Therefore you want:
    use Bufferlass::Bufferlass; ... my $bufferlass = Bufferlass::Bufferlass->new();
    Or maybe you want to rename your package to just 'Bufferlass', and put the pm file in the directory above where it currently is. Look at where some of the standard modules are relative to @INC, and what their package names are (e.g. Env, File::Copy).
      You've just made it crystal clear where I have been going wrong. Thank you.
Re: Developing CGI::Application based modules outside of the default @INC
by rhesa (Vicar) on Apr 09, 2008 at 18:59 UTC
    In addition to runrig's comments: put the use lib line before useing any of your custom classes.
      doh! Thank you for posting the obvious :)
Re: Developing CGI::Application based modules outside of the default @INC
by sundialsvc4 (Abbot) on Apr 09, 2008 at 20:51 UTC

    As an aside, when you are eveloping a CGI application you really don't want to rely upon “the default @INC,” because if someone were somehow able to alter the (external...) value, they would fundamentally alter the behavior of the program.

    Therefore, it is wisest to specify an explicit use lib statement.

    You may find the FindBin package useful... it has been extensively discussed here in the past, with all its pluses and minuses. You should also review “taint mode.” (I'm making these suggestions partly for the benefit of “the peanut gallery,” not to imply that you're not familiar with these things already.)

      Actually if you are on a linux/unix platform, I would strongly recommend getting your @INC path from $ENV{PERL5LIB}. This way you never have to change your code and you can change libraries from development or testing or production or anywhere else simply by changing the environment variable. This works equally well for CGI based applications as it does for CLI.
        This works equally well for CGI based applications as it does for CLI.

        Not quite true. Public CGI should use taint mode (as does the code in the original post), which means the environment is untrusted and PERL5LIB has no effect. Environment variables not set by CGI input should be trustworthy though.

        Taint::Runtime can get around this, as can something like this at the start of your script:

        BEGIN { if ($ENV{PERL5LIB} && $ENV{PERL5LIB} =~ /^(.*)$/) { eval "use lib (".join(',', map "'$_'", split ':', $1).");"; die $@ if $@; } }
        (updated to fix a typo)
      This member of the peanut gallery appreciates your thoughtfulness. ++

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://679305]
Approved by starbolin
Front-paged by starbolin
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others contemplating the Monastery: (3)
As of 2024-03-29 07:20 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found