Beefy Boxes and Bandwidth Generously Provided by pair Networks
laziness, impatience, and hubris
 
PerlMonks  

Packaging up my code sensibly

by punkish (Priest)
on Jun 12, 2005 at 15:52 UTC ( [id://465971]=perlquestion: print w/replies, xml ) Need Help??

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

Package experts,

In the begining, I had one long index.cgi. Then I read a Simple Module Tutorial and got the following --

## index.cgi use strict; use CGI::Simple; use HTML::Template; use MyPackage; # The following are imported from the .conf file below use vars qw( $WIKI_TITLE $CGIURL $DB $TEMPLATE_PATH $TEMPLATE_URL $DEFAULT_TARGET $DEFAULT_ACTION $DEBUGGING $PAGENAME_PATTERN $EMAIL_PATTERN $CGIPATH ); # A set_message handler allows creation of a nice looking, # custom error page. This is based on the example # provided in CGI::Carp docs BEGIN { require 'home.conf'; sub handleErrors { my ($err) = @_; my $t = HTML::Template->new( filename => "$TEMPLATE_PATH/error.tmpl", ); $err =~ s/$CGIPATH //g; $t->param( CGIURL => $CGIURL, TEMPLATE_URL => $TEMPLATE_URL, WIKI_TITLE => $WIKI_TITLE, PAGENAME => 'Error', ERROR => $err, ); print $t->output; } set_message(\&handleErrors); } yadda yadda # grab the cgi vars my $cgi_action = $cgi->param('action'); yadda yadda ## dispatch table follows # Dispatch logic SWITCH: { ($cgi_action eq 'edit') && do { edit($cgi_target, $cgi_searchterm); last SWITCH; }; ($cgi_action eq 'find') && do { find($cgi_target, $cgi_searchterm); last SWITCH; }; yadda yadda # default action view($cgi_target, $cgi_searchterm); }

Now I want to move code for each "run mode" (to borrow CGI::Application's terminology, into its own separate Package like below --

## index.cgi use strict; use CGI::Simple; use HTML::Template; use MyPackage; ## and then, in MyPackage use MyPackage::View; use MyPackage::Edit; use MyPackage::Find; yadda yadda

Things that trip me up are --

  • how to share the various methods, objects, and vars across packages short of re-init-ing them. For example, I create an H::T object in my CGI::Carp handler. I create another one inside MyPackage. If I were to create sub-packages, I would have to somehow get hold of the H::T object in there (right now, I have on H::T object created based on the run-mode, then its various params are populated in different subs).
  • I may have to share the config values I imported in my index.cgi using require 'home.conf'. Prefixing every darn var with $main:: will get tiring and will be error prone.
  • Additionally, there is common code (various subs) that is used by more than one run mode. Where would I put that?

To many of the wise monks here, this SoPW entry might seem beginner stuff. But for me, it is the land of the unknown. I guess I am looking for a "Intermediate|Advanced Module(s) Tutorial."

Update: 465945 seems to hit tangentially on what I am asking above, but not quite.

--

when small people start casting long shadows, it is time to go to bed

Replies are listed 'Best First'.
Re: Packaging up my code sensibly
by biosysadmin (Deacon) on Jun 12, 2005 at 16:11 UTC

    For your first point, you should read this thread on code reuse and method sharing, there are several ideas that are discussed for sharing objects through utility classes and superclasses.

    For your second point, why not just have a MyPackage::Config file? Just something simple like this should work:

    use MyPackage::Config; my $cgi_url = MyPackage::Config->cgi_url;
    On the one had it may seem like overkill to make a module just for just reading config files, but I've done that before and I've found that abstracting out the reading/writing of configuration files makes your program read well. It also separates your configuration file format out, so that if you ever decide to change from a require'd file, then you only have to change that in one place. I personally think that requiring or eval'ing code in that manner is a bad idea, but that's a separate discussion.

    Even better, once you make that configuration file object, you can share it using whatever method you use to share HTML::Template objects from your first question. :)

    I actually think your third question may be answered in the linked thread as well. That thread is actually more pertinent to this question than the first.

      Thanks for the reply. Your linked thread is quite specific to CGI::App, and while I learned a little bit from it, I am still in the confused land.

      Wrt reading a conf file, that is not really a problem. I am already reading an external conf file. I can also use Config::Simple or its many other brethren. However, the problem more is how to share these values among the various imported modules. I guess, that is really what I need a tutorial on.

      I am not really share my H::T objects right now. I have only one module MyPackage.pm that I bring in. I create an H::T object in it. However, if I chop up MyPackage.pm into many sub-packages, I will have to schlep H::T object back and forth. I am not quite sure how to do that correctly.

      --

      when small people start casting long shadows, it is time to go to bed
        Isn't what you need is a singleton object to store your values? Something that you'll call like this :
        use MyModules::Config; # here's the singleton magic: # "new" recalls the existing instance if any. my $conf=Config->new();
        from each script. And the Config package would look like this : This way, all your modules can share the same config without passing any parameter around : just call my $conf=Config->new() from each module, the first to call it will load the configuration data, the others will simply share that instance.
Re: Packaging up my code sensibly
by tlm (Prior) on Jun 12, 2005 at 19:53 UTC

    What does home.conf look like?

    the lowliest monk

      At this point I wanted to keep things simple, so I didn't use Config::Simple. My home.conf is just --

      $WIKI_TITLE = 'MyWiki'; $DEFAULT_TARGET = 'WelcomeToMyWiki'; $DEFAULT_ACTION = 'view'; $DEBUGGING = 0; $PAGENAME_PATTERN = "[A-Z][a-z0-9]+([A-Z][a-z0-9]+)+"; $EMAIL_PATTERN = '\w+@\w+\.\w+'; $DB = '/Volumes/koel/Users/punkish/Sites/mywiki/data/myw +iki.db'; $TEMPLATE_PATH = '/Volumes/koel/Users/punkish/Sites/mywiki/template +s'; $TEMPLATE_URL = '/~punkish/mywiki/templates'; $CGIPATH = '/Volumes/koel/Users/punkish/Sites/mywiki/index.cg +i'; $CGIURL = '/~punkish/mywiki';

      --

      when small people start casting long shadows, it is time to go to bed

        I think you will find it useful to become acquainted with Exporter, which is one of Perl's standard mechanisms for facilitating code sharing (basically it streamlines the process of importing identifiers from different namespaces, so that you don't need to prepend their package names).

        Other than this, I couldn't answer your question in a node of "reasonable length" (though a more knowledgeable monk might; after all, economy is a mark of mastery). I think that a book-length treatment of modules and/or OO in Perl (like the Alpaca book or Object Oriented Perl) would be the place to look for answers.

        As far as your sharing your config data, if I wanted to keep things as simple as you have them, one possibility (which is similar to wazoox's proposal but without the singleton idea from OO design) is to use a hash to hold all the config info, along with a barebones accessor for it.

        the lowliest monk

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others examining the Monastery: (5)
As of 2024-04-16 04:36 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found