<div dir="ltr">I get that. This reminds me of the mess I went through to auto-populate things based on the symbol table.<div><br></div><div>You have a main program that's basically this:<br><br><div style="font-family:"Fira Code","Droid Sans Mono Slashed",monospace;font-size:12px;line-height:16px;white-space:pre"><div style="color:rgb(0,0,0)"><span style="color:rgb(175,0,219)">use</span> strict ;</div><div style="color:rgb(0,0,0)"><span style="color:rgb(175,0,219)">use</span> warnings ;</div><div style="color:rgb(0,0,0)"><br></div><div style="color:rgb(0,0,0)"><span style="color:rgb(0,0,255)">my</span> <span style="color:rgb(0,16,128)">$api</span> = API->new(<span style="color:rgb(0,16,128)">@ARGV</span>) ;</div><div style="color:rgb(0,0,0)"><span style="color:rgb(0,16,128)">$api</span>->run() ;</div><font color="#000000"><br></font><div style="color:rgb(0,0,0)"><span style="color:rgb(175,0,219)">package</span> <span style="color:rgb(38,127,153)">API</span> ;</div><div style="color:rgb(0,0,0)"><span style="color:rgb(175,0,219)">use</span> lib <span style="color:rgb(163,21,21)">'/depot/gcore/apps/lib'</span> ;<br></div><div style="color:rgb(0,0,0)"><span style="color:rgb(175,0,219)">use</span> base <span style="color:rgb(163,21,21)">'API_Base'</span> ;</div><div style="color:rgb(0,0,0)"><span style="color:rgb(175,0,219)">use</span> API_PED ;<br></div><div style="color:rgb(0,0,0)"><br></div><div style=""><font color="#af00db">-----

And then API_Base cut down looks like 


</font><div style="color:rgb(0,0,0);line-height:16px"><div><span style="color:rgb(0,0,255)">sub</span> <span style="color:rgb(121,94,38)">new</span> ( <span style="color:rgb(0,16,128)">$class</span>, <span style="color:rgb(0,16,128)">@argv</span> )  {</div><div>    <span style="color:rgb(0,0,255)">my</span> <span style="color:rgb(0,16,128)">$self</span> ;</div><div>    <span style="color:rgb(0,0,255)">my</span> <span style="color:rgb(0,16,128)">$cgi</span> = CGI->new() ;</div><div>    <span style="color:rgb(0,16,128)">$self</span>->{method} = <span style="color:rgb(0,16,128)">$ENV</span>{REQUEST_METHOD} || <span style="color:rgb(163,21,21)">'GET'</span> ;</div><div>    %{ <span style="color:rgb(0,16,128)">$self</span>->{param} } = <span style="color:rgb(121,94,38)">map</span> { <span style="color:rgb(0,16,128)">$_</span> => <span style="color:rgb(121,94,38)">scalar</span> <span style="color:rgb(0,16,128)">$cgi</span>->param(<span style="color:rgb(0,16,128)">$_</span>) } <span style="color:rgb(0,16,128)">$cgi</span>->param() ;</div><div>    ( <span style="color:rgb(121,94,38)">undef</span>, @{ <span style="color:rgb(0,16,128)">$self</span>->{pathinfo} } ) = <span style="color:rgb(121,94,38)">split</span> <span style="color:rgb(121,94,38)">m</span><span style="color:rgb(129,31,63)">{/}</span><span style="color:rgb(175,0,219)">mxs</span>, <span style="color:rgb(0,16,128)">$cgi</span>->path_info() ;</div><div>    <span style="color:rgb(175,0,219)">return</span> <span style="color:rgb(121,94,38)">bless</span> <span style="color:rgb(0,16,128)">$self</span>, <span style="color:rgb(0,16,128)">$class</span> ;</div><div>    }</div><br><div><span style="color:rgb(0,128,0)"># I honestly don't know why I can't combine this with run_command, but</span></div><div><span style="color:rgb(0,128,0)"># I tried it and gave up</span></div><div><span style="color:rgb(0,0,255)">sub</span> <span style="color:rgb(121,94,38)">run</span> (<span style="color:rgb(0,16,128)">$self</span>) {</div><div>    <span style="color:rgb(0,0,255)">my</span> <span style="color:rgb(0,16,128)">@vars</span> = <span style="color:rgb(121,94,38)">map</span>{ <span style="color:rgb(0,16,128)">$self</span>->{<span style="color:rgb(0,16,128)">$_</span>} } <span style="color:rgb(163,21,21)">qw{ pathinfo param method }</span> ;</div><div>    <span style="color:rgb(175,0,219)">return</span> <span style="color:rgb(0,16,128)">$self</span>->run_command( <span style="color:rgb(0,16,128)">$self</span>->{pathinfo}, <span style="color:rgb(0,16,128)">$self</span>->{param}, <span style="color:rgb(0,16,128)">$self</span>->{method} ) ;</div><div>    }</div><br><div><span style="color:rgb(0,128,0)"># where the work is handled</span></div><div><span style="color:rgb(0,0,255)">sub</span> <span style="color:rgb(121,94,38)">run_command</span>  ( <span style="color:rgb(0,16,128)">$self</span>, <span style="color:rgb(0,16,128)">$pathinfo</span>, <span style="color:rgb(0,16,128)">$param</span>, <span style="color:rgb(0,16,128)">$method</span> ) {</div><div>    <span style="color:rgb(0,0,255)">my</span> <span style="color:rgb(0,16,128)">$command</span> = <span style="color:rgb(0,16,128)">$pathinfo</span>->[0] || <span style="color:rgb(163,21,21)">'test'</span> ;</div><div>    <span style="color:rgb(0,0,255)">my</span> <span style="color:rgb(0,16,128)">$s</span> = <span style="color:rgb(0,16,128)">$self</span>->can(<span style="color:rgb(163,21,21)">"api_</span><span style="color:rgb(0,16,128)">$command</span><span style="color:rgb(163,21,21)">"</span>) ;</div><br><div>    <span style="color:rgb(0,128,0)"># can() tells us if an object has a method called METHOD, which is</span></div><div>    <span style="color:rgb(0,128,0)"># good for telling if it is a usable function</span></div><div>    <span style="color:rgb(0,128,0)"># <a href="http://perldoc.perl.org/UNIVERSAL.html">http://perldoc.perl.org/UNIVERSAL.html</a></span></div><br><div>    <span style="color:rgb(0,128,0)"># y/-/_/ because function names cannot be foo-bar, only foo_bar</span></div><div>    <span style="color:rgb(175,0,219)">if</span> (!<span style="color:rgb(0,16,128)">$s</span>) {</div><div>        <span style="color:rgb(0,16,128)">$command</span> =~ <span style="color:rgb(121,94,38)">y</span><span style="color:rgb(129,31,63)">/-/_/</span> ;</div><div>        <span style="color:rgb(0,16,128)">$s</span> = <span style="color:rgb(0,16,128)">$self</span>->can(<span style="color:rgb(163,21,21)">"api_</span><span style="color:rgb(0,16,128)">$command</span><span style="color:rgb(163,21,21)">"</span>) ;</div><div>        }</div><br><div>    <span style="color:rgb(0,128,0)"># after this, we'll fail out if it still isn't in the table</span></div><div>    <span style="color:rgb(175,0,219)">if</span> (!<span style="color:rgb(0,16,128)">$s</span>) {</div><div>        <span style="color:rgb(0,16,128)">$self</span>->wrap( <span style="color:rgb(0,16,128)">$self</span>->fail( <span style="color:rgb(0,16,128)">$pathinfo</span>, <span style="color:rgb(0,16,128)">$param</span>, <span style="color:rgb(0,16,128)">$method</span> ) ) ;</div><div>        <span style="color:rgb(175,0,219)">exit</span> ;</div><div>        }</div><br><div>    <span style="color:rgb(0,128,0)">#if it isn't a code ref, we'll fail out as well</span></div><div>    <span style="color:rgb(175,0,219)">if</span> ( <span style="color:rgb(163,21,21)">'CODE'</span> <span style="color:rgb(121,94,38)">ne</span> <span style="color:rgb(121,94,38)">ref</span> <span style="color:rgb(0,16,128)">$s</span> ) {</div><div>        <span style="color:rgb(0,16,128)">$self</span>->wrap( <span style="color:rgb(0,16,128)">$self</span>->fail( <span style="color:rgb(0,16,128)">$pathinfo</span>, <span style="color:rgb(0,16,128)">$param</span>, <span style="color:rgb(0,16,128)">$method</span> ) ) ;</div><div>        <span style="color:rgb(175,0,219)">exit</span> ;</div><div>        }</div><div>    <span style="color:rgb(0,128,0)"># $self->$s if callable, so we'll call it.</span></div><div>    <span style="color:rgb(175,0,219)">return</span> <span style="color:rgb(0,16,128)">$self</span>->wrap( <span style="color:rgb(0,16,128)">$self</span>-><span style="color:rgb(0,16,128)">$s</span>( <span style="color:rgb(0,16,128)">$pathinfo</span>, <span style="color:rgb(0,16,128)">$param</span>, <span style="color:rgb(0,16,128)">$method</span> ) ) ;</div><div>    }</div><br></div><div style="color:rgb(0,0,0);line-height:16px">----</div><div style="color:rgb(0,0,0);line-height:16px"><br></div><div style="color:rgb(0,0,0);line-height:16px">Where the key is, given looking for an entry in the Purdue Electronic </div><div style="color:rgb(0,0,0);line-height:16px">Directory, the call would be in the symbol table as api_ped, so we see </div><div style="color:rgb(0,0,0);line-height:16px">if that function exists, using can('api_ped').

So, we need to be sure that sub api_ped() is in there.

<div style="line-height:16px"><div><span style="color:rgb(175,0,219)">package</span> <span style="color:rgb(38,127,153)">API_PED</span> ;</div><br></div><div style="line-height:16px"># simlified somewhat

<div style="line-height:16px"><div><span style="color:rgb(0,0,255)">our</span> <span style="color:rgb(0,16,128)">$VERSION</span> = 0.1 ;</div><div><span style="color:rgb(0,0,255)">our</span> <span style="color:rgb(0,16,128)">@EXPORT</span> ;</div><div><span style="color:rgb(175,0,219)">
# because sub NAME and push @EXPORT, NAME violates DRY</span></div><div><span style="color:rgb(175,0,219)">for</span> <span style="color:rgb(0,0,255)">my</span> <span style="color:rgb(0,16,128)">$entry</span> ( <span style="color:rgb(121,94,38)">keys</span> <span style="color:rgb(0,16,128)">%API_PED</span>:: ) {</div><div>    <span style="color:rgb(175,0,219)">next</span> <span style="color:rgb(175,0,219)">if</span> <span style="color:rgb(0,16,128)">$entry</span> !~ <span style="color:rgb(129,31,63)">/^api_/</span><span style="color:rgb(175,0,219)">mxs</span> ;</div><div>    <span style="color:rgb(121,94,38)">push</span> <span style="color:rgb(0,16,128)">@EXPORT</span>, <span style="color:rgb(0,16,128)">$entry</span> ;</div><div>    }</div><br></div><div style="line-height:16px"><div><span style="color:rgb(0,0,255)">sub</span> <span style="color:rgb(121,94,38)">api_ped</span> ( $self , $etc ) {</div><div>   # talks to PED returns response</div><div>}</div><div></div></div>
</div><div style="line-height:16px">----</div><span style="color:rgb(175,0,219)">
(Lots of web API JSON specific things cut)</span><br class="gmail-Apple-interchange-newline"></div><div style="color:rgb(0,0,0);line-height:16px"><br class="gmail-Apple-interchange-newline">So the behavior of <a href="http://program.pl">program.pl</a> here is determined almost entirely by </div><div style="color:rgb(0,0,0);line-height:16px">which modules it uses and if the sub names are prepended with 'api_'.</div></div><div style=""><font color="#af00db"><br></font></div><div style=""><font color="#af00db">Yes, that CAN violate DRY, but 1) the benefits of data-driven dev </font></div><div style=""><font color="#af00db">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.</font></div><div style="color:rgb(0,0,0)"><span style="color:rgb(0,128,0)"></span></div></div></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Tue, May 28, 2019 at 8:20 PM Mark Senn <<a href="mailto:mark@purdue.edu">mark@purdue.edu</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">> I'm not sure how a typical dispatch table is violating DRY.<br>
> [... -mark]<br>
> sub create_dispatch_table ($config) {<br>
>   my $dispatch = {<br>
>   'thing_one' => \&thing_one,<br>
>   'thing_two' => \&thing_two,<br>
>   };<br>
>   return($dispatch);<br>
> }<br>
> [... -mark]<br>
<br>
From<br>
<a href="https://dzone.com/articles/software-design-principles-dry-and-kiss" rel="noreferrer" target="_blank">https://dzone.com/articles/software-design-principles-dry-and-kiss</a><br>
    The DRY Principle: Don't Repeat Yourself<br>
    DRY stand for "Don't Repeat Yourself," a basic principle of software<br>
    development aimed at reducing repetition of information.<br>
<br>
>From my earlier message:<br>
    In short, I don't use conventional dispatch tables because they<br>
    violate the don't repeat yourself principle.  I'm only dispatching<br>
    to subs based on trusted information and the core of the idea is<br>
<br>
I should have written<br>
    I only use dispatch tables to dispatch to non-anonymous subs<br>
    based on trusted information.<br>
<br>
To me,<br>
    my $dispatch = {<br>
    'thing_one' => \&thing_one,<br>
    'thing_two' => \&thing_two,<br>
    };<br>
is an example of repetition.  For the case I wrote about, this code<br>
is not needed.  Since it's not needed I don't use it---it's just<br>
more code to support.  Given a word w, I always call a subroutine<br>
whose name can be computed from w.  In other words, I don't need to do<br>
    'thing_one' -> \&some_name_that_cannot_be_be computed_from_thing_one<br>
<br>
-mark<br>
_______________________________________________<br>
Purdue-pm mailing list<br>
<a href="mailto:Purdue-pm@pm.org" target="_blank">Purdue-pm@pm.org</a><br>
<a href="https://mail.pm.org/mailman/listinfo/purdue-pm" rel="noreferrer" target="_blank">https://mail.pm.org/mailman/listinfo/purdue-pm</a><br>
</blockquote></div><br clear="all"><div><br></div>-- <br><div dir="ltr" class="gmail_signature"><div dir="ltr"><div>Dave Jacoby<br>
<a href="mailto:jacoby.david@gmail.com" target="_blank">jacoby.david@gmail.com</a><br>
<br>Don't panic when the crisis is happening, or you won't enjoy it.</div></div></div>