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

Reply via email to