[Purdue-pm] Perl 5 Dispatch Tables

Dave Jacoby jacoby.david at gmail.com
Wed May 29 08:57:59 PDT 2019


Of course, the OTHER option is ... bulky?

my %dispatch;
$dispatch{ foo } = sub { ... code goes here .. }
$dispatch{ bar } = sub { ... code goes here .. }
$dispatch{ blee } = sub { ... code goes here .. }

code reuse is almost impossible by this method.


On Wed, May 29, 2019 at 10:50 AM Dave Jacoby <jacoby.david at gmail.com> wrote:

> 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.
>


-- 
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/b74e53ab/attachment.html>


More information about the Purdue-pm mailing list