[Purdue-pm] Perl 5 Dispatch Tables

Dave Jacoby jacoby.david at gmail.com
Wed May 29 07:50:23 PDT 2019


I get that. This reminds me of the mess I went through to auto-populate
things based on the symbol table.

You have a main program that's basically this:

use strict ;
use warnings ;

my $api = API->new(@ARGV) ;
$api->run() ;

package API ;
use lib '/depot/gcore/apps/lib' ;
use base 'API_Base' ;
use API_PED ;

----- And then API_Base cut down looks like
sub new ( $class, @argv ) {
my $self ;
my $cgi = CGI->new() ;
$self->{method} = $ENV{REQUEST_METHOD} || 'GET' ;
%{ $self->{param} } = map { $_ => scalar $cgi->param($_) } $cgi->param() ;
( undef, @{ $self->{pathinfo} } ) = split m{/}mxs, $cgi->path_info() ;
return bless $self, $class ;
}

# I honestly don't know why I can't combine this with run_command, but
# I tried it and gave up
sub run ($self) {
my @vars = map{ $self->{$_} } qw{ pathinfo param method } ;
return $self->run_command( $self->{pathinfo}, $self->{param}, $self->{method}
) ;
}

# where the work is handled
sub run_command ( $self, $pathinfo, $param, $method ) {
my $command = $pathinfo->[0] || 'test' ;
my $s = $self->can("api_$command") ;

# can() tells us if an object has a method called METHOD, which is
# good for telling if it is a usable function
# http://perldoc.perl.org/UNIVERSAL.html

# y/-/_/ because function names cannot be foo-bar, only foo_bar
if (!$s) {
$command =~ y/-/_/ ;
$s = $self->can("api_$command") ;
}

# after this, we'll fail out if it still isn't in the table
if (!$s) {
$self->wrap( $self->fail( $pathinfo, $param, $method ) ) ;
exit ;
}

#if it isn't a code ref, we'll fail out as well
if ( 'CODE' ne ref $s ) {
$self->wrap( $self->fail( $pathinfo, $param, $method ) ) ;
exit ;
}
# $self->$s if callable, so we'll call it.
return $self->wrap( $self->$s( $pathinfo, $param, $method ) ) ;
}

----

Where the key is, given looking for an entry in the Purdue Electronic
Directory, the call would be in the symbol table as api_ped, so we see
if that function exists, using can('api_ped'). So, we need to be sure that
sub api_ped() is in there.
package API_PED ;

# simlified somewhat
our $VERSION = 0.1 ;
our @EXPORT ;
# because sub NAME and push @EXPORT, NAME violates DRY
for my $entry ( keys %API_PED:: ) {
next if $entry !~ /^api_/mxs ;
push @EXPORT, $entry ;
}

sub api_ped ( $self , $etc ) {
# talks to PED returns response
}
----
(Lots of web API JSON specific things cut)

So the behavior of program.pl here is determined almost entirely by
which modules it uses and if the sub names are prepended with 'api_'.

Yes, that CAN violate DRY, but 1) the benefits of data-driven dev
are there and powerful, and 2) it doesn't necessary violate DRY. So, I
guess the question moves to what is worse: DRY or Scary Magic.

On Tue, May 28, 2019 at 8:20 PM Mark Senn <mark at purdue.edu> wrote:

> > I'm not sure how a typical dispatch table is violating DRY.
> > [... -mark]
> > sub create_dispatch_table ($config) {
> >   my $dispatch = {
> >   'thing_one' => \&thing_one,
> >   'thing_two' => \&thing_two,
> >   };
> >   return($dispatch);
> > }
> > [... -mark]
>
> From
> https://dzone.com/articles/software-design-principles-dry-and-kiss
>     The DRY Principle: Don't Repeat Yourself
>     DRY stand for "Don't Repeat Yourself," a basic principle of software
>     development aimed at reducing repetition of information.
>
> From my earlier message:
>     In short, I don't use conventional dispatch tables because they
>     violate the don't repeat yourself principle.  I'm only dispatching
>     to subs based on trusted information and the core of the idea is
>
> I should have written
>     I only use dispatch tables to dispatch to non-anonymous subs
>     based on trusted information.
>
> To me,
>     my $dispatch = {
>     'thing_one' => \&thing_one,
>     'thing_two' => \&thing_two,
>     };
> is an example of repetition.  For the case I wrote about, this code
> is not needed.  Since it's not needed I don't use it---it's just
> more code to support.  Given a word w, I always call a subroutine
> whose name can be computed from w.  In other words, I don't need to do
>     'thing_one' -> \&some_name_that_cannot_be_be computed_from_thing_one
>
> -mark
> _______________________________________________
> Purdue-pm mailing list
> Purdue-pm at pm.org
> https://mail.pm.org/mailman/listinfo/purdue-pm
>


-- 
Dave Jacoby
jacoby.david at gmail.com

Don't panic when the crisis is happening, or you won't enjoy it.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.pm.org/pipermail/purdue-pm/attachments/20190529/3d819522/attachment-0001.html>


More information about the Purdue-pm mailing list