Chip Turner ([EMAIL PROTECTED]) said something to this effect on 05/23/2001:
> If I could make a suggestion -- don't depend upon a CGI.pm interface
> for form variables. Abstract it away. One option would be to use
> closures:
I agree with not relying upon CGI, but using closures still
requires some knowledge of the object type. Something simpler
would be to assume that an object passed in has a param method
that behaves the way CGI.pm's and Apache::Request's param do.
Something like:
my $q = CGI->new;
# or:
# my $q = Apache::Request->new($r);
# and so on.
my $widget = Widget::Controller->new('factory' => $q);
(I made up the term 'factory'; I hope it's clear what I mean from
the context.)
# Widget::Controller:
sub new {
my $class = shift;
my %args = @_;
# stuff...
if (defined $args{'factory'} &&
UNIVERSAL::can($args{'factory'}, 'param'))
{
$self->{'factory'} = $args->{'factory'};
}
# more stuff
}
This way, anything with a params method can be used. I am unsure
about whether Apache::ASP has a param method, but perhaps one
could be added:
# Apache::ASP
sub param {
my $self = shift;
my $what = shift;
if (defined $Request->Form->{$what}) {
return $Request->Form->{$what};
} ###### ^^^^^^^^^^^^^^^^^ what is this called?
# more stuff
}
Or whatever. You get the idea.
So, from within the Widget object or a subclass, you call:
my $val = $widget->factory->param('foo');
... and it doesn't matter what the factory is. This breaks down
with modules like HTML::Template which have a param method that
does completely different things, and (possibly) modules that
AUTOLOAD methods.
> That way the user can easily give you different sources of formvars
> (libapreq, Apache::ASP's hash, plus others not yet public) and yet you
> still get the flexibility you need.
It seems to me that, because CGI.pm has become the standard, and a
lot of people have experience programming CGI scripts with it, it
has become pretty standard for CGI-ish modules to have param
methods that behave like CGI.pm's does. This assumption is
underlying the above suggestion. Is that a good assumption?
Littering the code with tons of "if ref $_[0] eq 'ThisModule'"
seems ugly and hard to maintain, and has the potential to
introduce bugs and unintentional omissions too quickly.
> I would suggest using a class for this kind of thing, but
> realistically it's a bit much to expect users to derive classes just
> for something as simple as this. By supporting the coderef closure
> internally, you don't force users to understand what's going on, but
> still allow for more advanced users to use different interfaces. Plus
> you remove dependance on a web server.
I agree with you--it's the Right Thing To Do, but we aren't
writing Java here. Liberal use of UNIVERSAL::can should be all
that is needed to handle this situation.
A Widget::DefaultFactory (or whatever) class should be provided,
to be used by default, which has an empty param method.
As an aside, I like the approach the Template Toolkit takes for
using subclasses or replacements for internal functionality.
Defining your own module to be used internally (for example, a
new Provider, which is what reads the template file from disk or
a cache), you set $Template::Config::PROVIDER to the classname of
your replacement, and the other Template modules get the right
class by doing something like:
$Template::Config::PROVIDER = 'My::Groovy::Provider';
my $provider = Template::Config->provider(\%options);
And the right type of object gets returned (Template::Config
loads the module when it is called). My only complaint
about this is that the interface (assigning to a global) could be
cleaner.
Just some thoughts.
(darren)
--
The first human who hurled an insult instead of a stone was the founder of
civilization.
-- Sigmund Freud