One useful extension technique for a server-side application like this is to support a "plugins" directory in to which users can place Perl modules that will be automatically loaded when your application is initializing itself. Then you can document some key functions within your code, and show people how to override them in their plugin.

Here's an untested schematic example:

# In myscript.cgi, or your mod_perl configuration, or wherever: # This could be relative to the script path or config file my $plugin_dir = '/opt/myscript/plugins'; sub load_plugins { # Read in the names of all .pm or .pl files in the plugins dir. # (Even better would be a recursive search of subdirectories.) unless ( opendir(PLUGINDIR, $plugin_dir) { warn "Plugin dir '$plugin_dir' is missing or unreadable."; return; } my @filenames = grep /\.p[ml]/, readdir(PLUGINDIR); closedir(PLUGINDIR); # Put the plugins directory in our library search path. # This allows one plugin to use or require another one. local @INC = ( $plugin_dir, @INC ); # Try to load all of the plugin files, but don't die trying. foreach my $plugin ( sort @filenames ) { eval "require $plugin"; if ( $@ ) { warn "Skipping plugin $plugin: $@" } } } sub print_output { print @_; } load_plugins(); print_output( "<html>Here's my CGI script output.</html>" );

Then, as a user, if I install this script, and read your documentation, I can "add on" some functionality by writing my own code into a file in the plugin_dir that modifies your original functions. For example:

# In $plugins_dir/uppercase.pm: sub print_output { print map { uc } @_; }

A key benefit of this approach is that when the original author releases an updated version of the main program, users can install it without worrying about overwriting their local customizations. Of course, if you make big changes to the main script, the plugins may not work properly anymore, so you need to either promise to maintain a backwards-compatible API, or check version numbers or such.

Following standard techniques of good program design when writing your application should generally also make it easier for your application to be extended this way. For example, finding common sequences of operations and breaking them out into subroutines with clear, descriptive names helps construct a clear API that someone else can later come along and extend.

If you have multiple plugins that all want to be involved in the same process, they'll need to wrap around each other or use some kind of event-handler logic to let them cooperate.

Here's a brute-force wrapping technique:

# In $plugins_dir/uppercase.pm: my $inner_print_output; BEGIN { $inner_print_output = \&print_output } sub print_output { &$inner_print_output( map { uc } @_ ); }
# In $plugins_dir/remove_whitespace.pm: my $inner_print_output; BEGIN { $inner_print_output = \&print_output } sub print_output { &$inner_print_output( map { s/\s//g } @_ ); }

Because of the "sort @filenames" expression in load_plugins, these files will be loaded in alphabetical order; first remove_whitespace.pm wraps around the original print_output, then uppercase.pm wraps around that. The result is that uppercase.pm's print_output calls remove_whitespace.pm print_output which calls our original print_output. Feel free to use some other sort order, but make sure it's consistent so that users can control the order they want things loaded in.

Note that the core concept described here is orthogonal to whether you're using functions or objects; if your web application is implemented using objects and factories, as described in other responses to this question, the "plugins" modules can define new classes and register them as needed.


In reply to Modules as Application "Plugins" by simonm
in thread Best way to 'add modules' to web app? by BUU

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.