in reply to A dispatch table to match named params of a sub

You were very close:

$ cat sploot.pl #!/usr/bin/env perl use strict; use warnings; use Data::Dumper; use Test::More; my %sub = ( t01=>{ name=>\&mine, args=>[qw/one first two second/] }, ); $sub{t01}{name}(@{$sub{t01}{args}}); sub mine { my %args = @_; ok( $args{one} eq 'first', 'arg one' ); ok( $args{two} eq 'second', 'arg two' ); done_testing; } $ perl sploot.pl ok 1 - arg one ok 2 - arg two 1..2

The bit that hurt you was that you didn't tell perl to expand the arguments into a list. So your function just got an array ref, so you probably got the "odd number of elements for hash" error. I elided the '->' since they're not strictly necessary, but they don't hurt either. (I typed it in, rather than cut & paste for some odd reason...)

...roboticus

When your only tool is a hammer, all problems look like your thumb.

Replies are listed 'Best First'.
Re^2: A dispatch table to match named params of a sub
by neilwatson (Priest) on Jun 29, 2015 at 16:46 UTC

    The trouble with dereferencing: $sub{t01}{name}(@{$sub{t01}{args}});, is that all my other subs take a single argument, their dispatch entry looks like:

    { name => \&mysub, arg => "some string" }

    So I have this one snowflake-of-a-sub that wants named params :( How can handle this exception elegantly?

    Neil Watson
    watson-wilson.ca

      nielwatson:

      That shouldn't be a problem: Just put all arguments in your dispatch has in arrayrefs, and when they're unwrapped, they'll be simple positional parameters. Having one is just fine. It's probably the most general form, as you can also pass an array of arguments, too, so you get it all: single arguments, multiple arguments, arrays, hashes and named arguments (hashes!).

      $ cat sploot.pl #!/usr/bin/env perl use strict; use warnings; use Data::Dumper; use Test::More; my %sub = ( t01=>{ name=>\&mine, args=>[qw/one first two second/] }, t02=>{ name=>\&yours, args=>[ 'foo' ] }, t03=>{ name=>\&ours, args=>[qw/The quick red fox/] }, ); for my $T (keys %sub) { $sub{$T}->{name}->(@{$sub{$T}{args}}); } done_testing; sub mine { # named arguments example my %args = @_; ok( $args{one} eq 'first', 'arg one' ); ok( $args{two} eq 'second', 'arg two' ); } sub yours { # single argument example my $message = shift; ok( $message eq 'foo', 'A single argument' ); } sub ours { # array example my @args = @_; ok( "The quick red fox" eq join(" ", @args), 'Argument array' ); } Roboticus@Waubli ~ $ perl sploot.pl ok 1 - Argument array ok 2 - A single argument ok 3 - arg one ok 4 - arg two 1..4

      Update: Added array example & text

      ...roboticus

      When your only tool is a hammer, all problems look like your thumb.

      nielwatson:

      Note: I posted this as a separate reply to prevent it from getting tangled up in the update above.

      Since all your other subroutines take a single argument, you could also pass in an arrayref (as you currently do) and expand it into a hash inside the subroutine, *or* pass in a hashref and use it directly:

      $ cat sploot2.pl #!/usr/bin/env perl use strict; use warnings; use Data::Dumper; use Test::More; my %sub = ( t01=>{ name=>\&mine, args=>[qw/one first two second/] }, t02=>{ name=>\&mine2, args=>{qw/one first two second/} }, ); for my $T (keys %sub) { $sub{$T}->{name}->($sub{$T}{args}); } done_testing; sub mine { # named arguments example my %args = @{$_[0]}; ok( $args{one} eq 'first', 'arg one' ); ok( $args{two} eq 'second', 'arg two' ); } sub mine2 { # named arguments example my $args = shift; ok( $args->{one} eq 'first', 'arg one (b)' ); ok( $args->{two} eq 'second', 'arg two (b)' ); } Roboticus@Waubli ~ $ perl sploot2.pl ok 1 - arg one (b) ok 2 - arg two (b) ok 3 - arg one ok 4 - arg two 1..4

      ...roboticus

      When your only tool is a hammer, all problems look like your thumb.