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

Hello All,

This is sort of a funky question, so I'll try to explain the best I can.

I have a fairly complex web-based program, I'd like to allow people who use the program to 'roll their own' parts of the program. See? no makey sense, let me explain with an example:

Say I have the common form handler; a user submits a form, the form info gets mailed to whomever; the user gets a thank you message from the scrpt.

Now, say, instead of having the script generate a thank you page, I want it to redirect to a different page.. BUT! I don't want to implicitly add this feature into the script, I just want the script to have hooks to a uniquely specified function or something. That way, anyone with enough know-how can easily make a new chunk oh code that the main part of the program can call, but I don't want this new chunk to live inside the main program, it should be on it's own.

Am I making sense? I'm not sure. An idea on the top of my head is to have a variable that controls if the program should use its built in way of doing things. Something like:

if($roll_your_own == 1){ system('a_different_script.pl'); }else{ go_at_it_yourself(); }

In this example, I'm calling an outside script to handle the job. Right away, this doesn't seem to be the best thing to do; since I'm not sure exactly the outside script will retreive all the arguments, and there's always security concerns with system();

Would a better way be to have a module specifically designed to all you to put your own code in? something like:

if($roll_your_own == 1){ require RollYourOwn RollYourOwn::rollit($do_this) }else{ go_at_it_yourself(); }

I know this must be something that other people have come across in big scripts; they want to have the ability to add the functionalitly, but not have that functionality in the distribution, since the functionality could be so local it wouldn't make sense in other uses of the program.

-justin simoni
!skazat!

Replies are listed 'Best First'.
Re: Allowing the over riding of a program's design
by chromatic (Archbishop) on Feb 06, 2002 at 21:52 UTC
    It's doable. You just need a flexible dispatch mechanism. For example, you could say that an application has to be object oriented, inheriting from a certain application class. This allows you to take advantage of polymorphism. (Doesn't CGI::Application do this?)

    Another approach is to require everything to register handlers for operations. Keep them in a hash, keyed by operation name, and store sub references. If you assume everything will take a request object (or the CGI object) as its first parameter, you'll do pretty well.

    It can also be done with individual scripts, but it's a lot more flexible if you use modules with (at least) some interface or objects.

Re: Allowing the over riding of a program's design
by Spudnuts (Pilgrim) on Feb 06, 2002 at 23:59 UTC
    This isn't a very scalable approach, and has a dirty feel to me:
    if ($roll_your_own == 1) { $ENV{'CONTENT_LENGTH'} = length($cgi->query_string()); open(CGI, "|a_different_script.cgi") or die($!); print CGI $cgi->query_string(); close(CGI) or die($!); }

    In its favor, it should pass all of the arguments it receives, and it does so without letting them be evaluated by the shell.

    Update: I noticed that the CONTENT_LENGTH value is not necessarily accurate in the receiving script. Reset it before opening the pipe.

Re: Allowing the over riding of a program's design
by trs80 (Priest) on Feb 07, 2002 at 06:46 UTC
    You can use callback (I hope I haven't twisted them into somthing else) that will do what you need. I use them in OOP and assign a default sub via a method, that is I create a method to return the default sub routine (action/code) if one isn't passed into the mehtod that uses the sub.
    Here is the method that returns the default code (sub):
    sub default_code { my ($self,$extra) = @_; my $sub = sub { my ($extra,$optional,$optional) = @_; # do something }; return $sub; }
    The method that might use this sub allows for a callback or overriding sub that is passed in via the method options.
    $object->display( { my_code => sub { my ($hashref) = shift; foreach (keys %$hashref) { # more code } }; } );
    Then in the display method
    sub display { my ($self,$args) = @_; # $args->{'my_code'} has our "custom code" # here is where we determine which one to use my $action = $args->{'my_code'} || $self->default_code; $action->($args); }
    I don't know if this good style or not, but it has been working well for what I needed.

      If anything, this is an interesting snippet of code use. I bet I could allow people to add the overriding code via a form in the admin screens.... That in itself might not be good style as well, but a good idea at least to throw in the pot.

      -justin simoni
      !skazat!