in reply to Best way to 'add modules' to web app?

It seems to me that if you write your system with good object-oriented technique, you shouldn't have a problem allowing the extension of functionality, regardless of the planning.

Keep in mind I know nothing about the specifics, but let's say, for example, you have a Forum::Format module. This module has the methods:

$f->formatPost() $f->outputPost()
You can also define the abstract or stub methods:
$f->preFormatPost() $f->postFormatPost() $f->preOutputPost() $f->postOutputPost()
If some other class is calling the  $f->formatPost() method, make sure it calls $f->preFormatPost() before and $f->postFormatPost() after. Even if the abstract versions of these classes do nothing, future module writers can have their classes inherit from Forum::Format and override these methods or even rewrite your Forum::Format module without changing a thing except for these two methods. I realize your system may be a bit more complex than this and having future writers rewrite one of your base classes is a bad idea, but the idea of leaving "hooks" for pre/post formatting (or other actions) is still sound.

Additionally, anything you do inside the Format method could call other methods that can be overridden. So if, within Format, you call $f->modifyHTML($text) or something similar, that method can be overridden to modify HTML differently in a child of the Forum::Format class.

Replies are listed 'Best First'.
Re: Re: Best way to 'add modules' to web app?
by BUU (Prior) on Jul 05, 2003 at 15:51 UTC
    The idea of providing easily over-rideable methods that would allow the 'client' to easily change functionality is basically what I was going for. However, I'm having a problem conceptualizing exactly how you tell the program that you over rode a sub method. From your example, if I write a Forum::Format module, then all my code dealing with it looks like: my $ff=new Forum::Format;. If someone doesn't like part of it and wants to inherit and over ride that sub, say his new module is Forum::Format::NoHtml how does he tell my application that it should be using this New and Improved class/object instead of the regular old Forum::Format
      The problem sounds more like a functional programming one (where you focus on evaluating "expression")than OOP one. I don't think inheritance (though it might not what you really meant) it's necessarily good for customization and even less for flexibility. It leads to too tight a coupling.

      OOP is a good way to deal with design time customization. At runtime, or so you could think, it's another story. Think about a calculator. It evaluates arbitrary expression at runtime. It all depends on how you model the problem and/or your spec.

      As to how one might conceptualize overriding a sub, I might think of a sub a value in a hash with rules determining which key (and therefore sub) to pick, either at runtime or design time. Think about this (trivial) example:
      sub make_binary { eval "sub { $_[0] }" } my %op ; $op{add} = make_binary '$_[0] + $_[1]' ; $op{sub} = make_binary '$_[0] - $_[1]' ; $op{mul} = make_binary '$_[0] * $_[1]' ; $op{div} = make_binary '$_[0] / $_[1]' ; $op{max} = make_binary '$_[0] > $_[1] ? $_[0] : $_[1]' ; for (sort keys %op) { print "2 $_ 3 = " . $op{$_}->(2,3) . "\n"; }
      Kind of customization via "templating."
      I'd explain in detail how you do this, but I'm walking out the door as I speak. Instead, take a look at the code for CGI::Kwiki and how they accomplish it. (Hint: Use a simple, global config file that contains what classes you should use.)
      From your example, if I write a Forum::Format module, then all my code dealing with it looks like: my $ff=new Forum::Format;. If someone doesn't like part of it and wants to inherit and over ride that sub, say his new module is Forum::Format::NoHtml how does he tell my application that it should be using this New and Improved class/object instead of the regular old Forum::Format

      Don't hard code the class name. Have a factory that gives you the appropriate formatter object based on a configuration file, environment variable, mod_perl setting or whatever.

      Take a look at Class::Factory for one way of doing this.