Beefy Boxes and Bandwidth Generously Provided by pair Networks
laziness, impatience, and hubris

Revision 2: Switch/case as a dispatch table with C-style fall-through

by Roy Johnson (Monsignor)
on May 16, 2005 at 15:20 UTC ( #457491=note: print w/replies, xml ) Need Help??

in reply to Switch/case as a dispatch table with C-style fall-through

I have reworked the construct as discussed earlier. I include a minimal test suite here to demonstrate the expected behavior.
#!perl use strict; use warnings; use Test::More tests => 13; use Case; my $case = Case::switch( 'foo' => sub {5} ); ok($case, 'create switch'); is($case->('foo'), 5, 'found'); is($case->('bar'), undef, 'default default'); $case = Case::switch( Case::default => sub { 'given' } ); is($case->('foo'), 'given', 'supplied default'); $case = Case::switch( qw(foo bar baz) => sub {'fell thru'}, Case::default => sub {'too far'} ); is($case->('foo'), 'fell thru', 'normal fall-thru'); $case = Case::switch( qw(foo bar) => sub {'one ' . $Case::action->('baz')}, sorbet => sub {'to cleanse the palate'}, baz => sub {'chain'} ); is($case->('foo'), 'one chain', 'chaining'); $case = Case::switch( qw(foo bar) => sub {"got $_"}, qw(baz) => sub {$Case::action->('foo')}, 'roy' => sub { 'special '. $Case::action->('foo')}, Case::default => sub { 'Just wasting space' } ); is($case->('foo'), 'got foo', 'arg is $_'); is($case->('baz'), 'got baz', 'arg is $_ when chained'); is($case->('roy'), 'special got roy', 'cat chained return'); # Weird ones ok(Case::switch(), 'completely empty'); ok(Case::switch(sub{}), 'default only'); ok(Case::switch('foo'), 'term, no sub'); diag("Should get a malformed switch warning"); ok(Case::switch(sub{}, sub{}), 'malformed switch warning');
and the module itself, which is more lightweight and (I think) elegant than before:
package Case; use Carp; use Exporter; @ISA=(Exporter); @EXPORT_OK=qw(switch default); use strict; use warnings; sub default {} sub switch { my %swash; my $default = \&default; my $code; my $assigned_code; # Handle degenerate case return $default if (@_ == 0); # Handle default if ((ref $_[-1]) eq 'CODE' and (@_ ==1 or ref $_[-2] eq 'CODE')) { $default = pop(@_); } for my $item (reverse @_) { if ((my $reftype = ref $item) eq 'CODE') { carp "Malformed switch: action with no terms" if $code and ! $assigned_code; $code = $item; $assigned_code = 0; } elsif ($reftype) { croak "switch cannot handle $reftype-ref arguments"; } else { $swash{$item} = $code; ++$assigned_code; } } carp "Malformed switch: action with no terms" if $code and ! $assigned_code; return sub { local($_) = @_; local $Case::action = sub { ($swash{$_[0]} || $default)->() }; &$Case::action; }; } 1;

Caution: Contents may have been coded under pressure.

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://457491]
[Eily]: I just wrote a oneliner to solve a (non perl) colleague's problem, and it worked on the first try
[Eily]: and he wasn't impressed
1nickt adds gingersnaps to the platter on the sideboard.
[Eily]: sure it was a pretty standard one liner (of the $h{$1} = $2 if /regex/; END { pp \%h; } variety), but he's not supposed to know that!
[Eily]: what's the point of writing perl if people aren't impressed :P
[sierpinski]: Haha
[Discipulus]: i'm with you!
[Discipulus]: with eskimo greeting is a little bit impressing, anyway

How do I use this? | Other CB clients
Other Users?
Others browsing the Monastery: (7)
As of 2017-04-26 15:06 GMT
Find Nodes?
    Voting Booth?
    I'm a fool:

    Results (482 votes). Check out past polls.