File Coverage

blib/lib/Switch/Perlish.pm
Criterion Covered Total %
statement 76 76 100.0
branch 38 42 90.4
condition 31 42 73.8
subroutine 21 21 100.0
pod 5 5 100.0
total 171 186 91.9


line stmt bran cond sub pod time code
1             package Switch::Perlish;
2            
3             require Exporter;
4             @ISA = 'Exporter';
5             @EXPORT = qw/ switch case default fallthrough stop /;
6             $VERSION = '1.0.5';
7            
8 10     10   98709 use Switch::Perlish::Smatch;
  10         39  
  10         736  
9            
10 10     10   77 use strict;
  10         18  
  10         304  
11 10     10   56 use warnings;
  10         24  
  10         377  
12            
13 10     10   52 use vars qw/ $MATCH $TOPIC $SWITCH $CASE $FALLING $CSTYLE /;
  10         21  
  10         2140  
14            
15             {
16             package Switch::Perlish::Control::_success;
17             package Switch::Perlish::Control::_fallthrough;
18             package Switch::Perlish::Control::_stop;
19             }
20            
21 10     10   239 use constant SUCCESS => 'Switch::Perlish::Control::_success';
  10         22  
  10         911  
22 10     10   56 use constant FALLTHROUGH => 'Switch::Perlish::Control::_fallthrough';
  10         21  
  10         440  
23 10     10   51 use constant STOP => 'Switch::Perlish::Control::_stop';
  10         21  
  10         546  
24            
25             sub import {
26 10     10   52 no warnings;
  10         22  
  10         1110  
27 11     11   3932 $CSTYLE = pop(@_) eq 'C';
28 11         5174 Switch::Perlish->export_to_level(1, @_);
29             }
30            
31 10     10   55 use Carp 'croak';
  10         18  
  10         677  
32 10     10   64 use Scalar::Util qw/ reftype blessed /;
  10         17  
  10         3461  
33            
34             sub switch {
35 98     98 1 24866 local($TOPIC, $SWITCH) = @_;
36            
37 98 50       458 croak "Invalid code block provided: '$SWITCH'"
38             unless reftype($SWITCH) eq 'CODE';
39            
40             ## Restore this if we exit successfully so as not to make debugging trickier.
41 98         156 my $olderr = $@;
42            
43             ## Topicalize the topic for the switch block.
44 98         197 local *_ = \$TOPIC;
45            
46             ## We're not falling through until a successful match.
47 98         230 local $FALLING = 0;
48            
49             ## How the switch statement is evaluted:
50             ## A successful case (that doesn't fallthrough) will leave the block by
51             ## throwing an error object blessed into SUCCESS control exception. However,
52             ## the user might want to return early for whatever reason, so keep that
53             ## result too.
54 98         131 my @result = eval { $SWITCH->() };
  98         283  
55 98         2293 my $err = $@;
56            
57             ## If something was returned from the block explicitly or a case
58             ## succeeded then try to return what seems most appropriate.
59 98 100 66     488 if( ( @result and !$err ) or _left_ok($err) ) {
      100        
60 85         152 $@ = $olderr;
61 85 100       257 my @r = @result ? @result : @$err;
62 85 50       830 return defined wantarray ? wantarray ? @r : $r[-1] : ();
    100          
63             }
64            
65 13 100       93 die $err
66             if $@;
67             }
68            
69             sub _called_by {
70 180     180   286 my $name = $_[0];
71 180 100       437 my $depth = defined( $_[1] ) ? $_[1] : 4;
72 10     10   60 no warnings 'uninitialized';
  10         55  
  10         11494  
73 180         4261 return +(caller $depth)[3] =~ /::\Q$name\E$/;
74             }
75            
76             ## Did we leave the switch() from a control exception?
77             sub _left_ok {
78 86 0 0 86   543 return blessed($_[0]) and $_[0]->isa(SUCCESS)
79             or $_[0]->isa(STOP);
80             }
81            
82             ## Exit the switch block and set $@ to a S::P::_success control exception.
83             ## NB: This blessing trickery is for people who want the result propagated.
84 69     69   823 sub _end_case { die bless \@_, SUCCESS }
85            
86             sub fallthrough {
87             ## make sure we're not called out of context
88 2 100   2 1 13796 croak "Not called within a case statement"
89             if !_called_by(case => 5);
90 1         4 die bless( \do{
91 1         12 my $msg = "The fallthrough control exception from Switch::Perlish"
92             }, FALLTHROUGH );
93             }
94            
95             sub stop {
96             ## Make sure this isn't called out of context.
97 5 100   5 1 4434 croak "Not called within a case statement"
98             if !_called_by(case => 5);
99             ## Was, "The stop control exception from Switch::Perlish", but that could be
100             ## assigned to which isn't expected behaviour in the case of stop;.
101 4         30 die bless([], STOP );
102             }
103            
104             sub _exec_block {
105 88     88   120 my @ret = eval { $CASE->() };
  88         414  
106            
107             ## Check for fallthrough control exception.
108             return
109 88 100 100     34124 if blessed($@) and $@->isa(FALLTHROUGH);
110            
111             ## Check for stop control exception.
112 87 100 66     362 die $@
113             if blessed($@) and $@->isa(STOP);
114            
115             ## Propagate non-control exception.
116 83 100       211 die $@
117             if $@;
118            
119 79 100 66     303 _end_case @ret
      100        
120             unless $CSTYLE and $FALLING and !_called_by(default => 2);
121            
122 10         39 return @ret;
123             }
124            
125             sub case {
126             ## If you want smatching, use S::P::Smatch::match not S::P::case.
127 156 100   156 1 33741 croak "Not called within a switch statement\n"
128             if !_called_by('switch');
129            
130 155         528 local($MATCH, $CASE) = @_;
131            
132 155 100 66     603 croak "No case block provided"
133             if !defined($CASE) and !$CSTYLE;
134            
135             ## Single arg case and using CSTYLE and we're falling.
136             return
137 154 100 66     371 if $CSTYLE and $FALLING and @_ == 1;
      100        
138            
139             return
140             ## keep going if we're falling, otherwise smatch
141 152 100 66     1176 unless $CSTYLE and $FALLING
      100        
142             or Switch::Perlish::Smatch->match($TOPIC, $MATCH);
143            
144             ## There's been a match, so keep on falling.
145 86 100       313 $FALLING = 1
146             if $CSTYLE;
147            
148             ## Single arg case and using CSTYLE and we matched.
149             return
150 86 100 66     349 if $CSTYLE and $FALLING and @_ == 1;
      66        
151            
152 83         177 _exec_block;
153             }
154            
155             sub default {
156             ## Make sure we're in a switch block.
157 6 100   6 1 617 croak "Not called within a switch statement\n"
158             if !_called_by('switch');
159            
160 5         13 local $CASE = $_[0];
161            
162 5         13 _exec_block;
163             }
164            
165             1;
166            
167             =pod
168            
169             =head1 NAME
170            
171             Switch::Perlish - A Perlish implementation of the C statement.
172            
173             =head1 VERSION
174            
175             1.0.5 - Mostly cosmetic changes for this release.
176            
177             =head1 SYNOPSIS
178            
179             use Switch::Perlish;
180            
181             switch $var, sub {
182             case 'foo',
183             sub { print "$var is equal to 'foo'\n" };
184             case 42,
185             sub { print "$var is equal to 42\n";
186             fallthrough };
187             case [qw/ foo bar baz /],
188             sub { print "$var found in list\n" };
189             case { foo => 'bar' },
190             sub { print "$var key found in hash\n" };
191             case \&func,
192             sub { print "$var as arg to func() returned true\n" };
193             case $obj,
194             sub { print "$var is method in $obj and returned true\n" };
195             case qr/\bfoo\b/,
196             sub { print "$var matched against foo\n" };
197             default
198             sub { print "$var did not find a match\n" };
199             };
200            
201             =head1 BACKGROUND
202            
203             If you're unfamiliar with C then this is the best place to start. A
204             C statement is essentially syntactic sugar for an C/C/C
205             chain where the same C<$variable> is tested in every conditional e.g:
206            
207             my $foo = 'a string';
208             if($foo eq 'something') {
209             print '$foo matched "something"';
210             } elsif($foo eq 'a string') {
211             print '$foo matched "a string"';
212             } else {
213             print '$foo matched nothing';
214             }
215            
216             This simply matches C<$foo> against a series of strings, then defaulting to the
217             last C block if nothing matched. An equivalent C statement (using
218             this module) would be:
219            
220             use Switch::Perlish;
221             my $foo = 'a string';
222             switch $foo, sub {
223             case 'something',
224             sub { print '$foo matched "something"' };
225             case 'a string',
226             sub { print '$foo matched "a string"' };
227             default
228             sub { print '$foo matched nothing' };
229             };
230            
231             So the first argument to C is the thing to be tested (in the code above,
232             C<$foo>), and the second argument is the block of tests. Each C statement
233             matches its first argument against C<$foo>, and if the match is successful,
234             the associated block is executed, so running the above code outputs: C<$foo
235             matched "a string">. Note the use of semi-colon at the end of the C,
236             C and C calls - they're just simple subroutine calls.
237            
238             =head1 DESCRIPTION
239            
240             This is a Perl-oriented implementation of the C statement. It uses
241             smart-matching in Cs which can be configured and extended by the user.
242             There is no magical syntax so C/C/C expect coderefs,
243             which are most simply provided by anonymous subroutines. By default successful
244             C statements do not fall through[1]. To fall through a C block
245             call the C subroutine explicitly. For C style C
246             behaviour[2] simply call the module with an upper-case I i.e
247            
248             use Switch::Perlish 'C';
249            
250             I<< [1] To 'fall through' in a C block means that the C block
251             isn't exited upon success. >>
252            
253             I<< [2] upon a C succesfully matching all subsequent Cs succeed; to
254             break out from the current C completely use C. >>
255            
256             =head2 Smart Matching
257            
258             The idea behind I is that the given values are matched
259             in an intelligent manner, so as to get a meaningful result I
260             of the values' types. This allows for flexible code and a certain amount of
261             "just do it" when using I. Below is a basic example using
262             I (which is done implictly in C) where a simple value
263             is being matched against an array e.g
264            
265             use Switch::Perlish;
266            
267             my $num = $ARGV[0];
268            
269             switch $num, sub {
270             case undef,
271             sub { die "Usage: $0 NUM\n" };
272             case [0 .. 10],
273             sub { print "Your number was between 0 and 10" };
274             case [11 .. 100],
275             sub { print "Your number was between 11 and 100" };
276             case [101 .. 1000],
277             sub { print "Your number was between 101 and 1000" };
278             default
279             sub { print "Your number was less than 0 or greater than 1000" };
280             };
281            
282             So here the I is checking for the existence of C<$num> in the
283             provided arrays. In the above code I happen to be used, but any array
284             would suffice. To see how different value types compare with each other see.
285             L, which provides descriptions for all
286             the default comparators.
287            
288             The code behind this I can be found in
289             L which itself delegates to the appropriate comparator
290             subroutine depending on the value types. See L for more
291             details on the I implementation and how it can be extended.
292            
293             =head1 COMPARISON
294            
295             Because there is an existing module which implements C this section
296             intends to provide clarification of the differences that module, L,
297             and this one.
298            
299             =head2 Native vs. New
300            
301             To create a more natural C syntax, L uses source filters[3],
302             which facilitate the creation of this natural syntax. C
303             however uses the native syntax of perl, so what you code is what you see.
304             The big advantage of source filtering is the ability to create new syntax,
305             but it has several disadvantages - the new syntax can conflict with, and
306             break, existing code, the filtered code can be difficult to debug and because
307             you can't easily see the post-filtered code it can be difficult to integrate
308             into production code. The Itre> for this module is to have
309             the syntax of C without the baggage that goes with filtered code.
310            
311             =head2 Extensibility
312            
313             The L module deals with the Perl's types superbly, however, that is all,
314             so there is no extensibility as such. This module was designed from the outset
315             to allow an extensibilty of how types are dealt with, i.e how they are compared,
316             and this is done through the companion module L.
317            
318             =head2 The C keyword
319            
320             Unlike L, C requires the use of the the C keyword
321             when creating blocks. This is because there is no standard way of magically
322             coercing bare blocks into closures, unless one uses the C<(E)> prototype,
323             and that is only applicable where it is the first argument. Also, prototypes are
324             too restrictive for what is intended as a very I module e.g
325            
326             $ perl -e 'sub f(&) { print $_[0]->() } sub g{'foo'} my $r = \&g; f $r'
327             Type of arg 1 to main::f must be block or sub {} (not private variable)
328             at -e line 1, at EOF
329             Execution of -e aborted due to compilation errors.
330            
331             So, for now, 3 extra keystrokes are necessary when using blocks with
332             C.
333            
334             I<< [3] see. L for more info on source filters >>.
335            
336             =head1 SUBROUTINES
337            
338             =over
339            
340             =item C<< switch( $topic, $block ) >>
341            
342             Execute the given C<$block> allowing C statements to access the C<$topic>.
343             This, along with C and C, will also attempt to return in the same
344             manner as normal subroutines e.g you can assign to the result of them.
345            
346             =item C<< case( $match, $block ) >>
347            
348             If the current C<$topic> successfully I against C<$match> then
349             execute C<$block> and exit from current C, but if using C style
350             C behaviour, then continue executing the block and all subsequent
351             C C<$block>s until the end of the current C or a call to C.
352             Also, if using C style C behaviour then C<$block> is optional. I:
353             this subroutine cannot be called outside of C, if you want to use
354             I functionality, see. L.
355            
356             =item C<< default( $block ) >>
357            
358             Execute C<$block> and exit from C. I: this subroutine cannot be
359             called outside of C.
360            
361             =item C<< fallthrough() >>
362            
363             Fall through the the current C block i.e continue to evaluate the rest of
364             the C block. I: this subroutine cannot be called outside of C.
365            
366             =item C<< stop() >>
367            
368             Use in C blocks to exit the current C block, ideally when used
369             with the C style behaviour as it mimics C's C. I: this
370             subroutine cannot be called outside of C.
371            
372             =back
373            
374             =head2 Globals
375            
376             =over
377            
378             =item C<$SWITCH>
379            
380             The current C block.
381            
382             =item C<$CASE>
383            
384             The current C block.
385            
386             =item C<$TOPIC>
387            
388             The current topic block, also aliased to C<$_>.
389            
390             =item C<$MATCH>
391            
392             The current thing being matched against.
393            
394             =item C<$CSTYLE>
395            
396             If C is called with the I argument, this is set to
397             true and C style C behaviour is enabled.
398            
399             =item C<$FALLING>
400            
401             Set to true when falling through the current C block i.e set to true
402             when C has been called.
403            
404             =back
405            
406             =head1 SEE. ALSO
407            
408             L
409            
410             L
411            
412             L
413            
414             L
415            
416             L
417            
418             =head1 TODO
419            
420             =over
421            
422             =item *
423            
424             Implement localizing comparators
425            
426             =item *
427            
428             Test with earlier versions of C
429            
430             =item *
431            
432             Drop C for compatibility with older perls?
433            
434             =item *
435            
436             Allow lists as the topic and/or cases to match against
437            
438             =back
439            
440             =head1 AUTHOR
441            
442             Dan Brook C<< >>
443            
444             =head1 COPYRIGHT
445            
446             Copyright (c) 2006, Dan Brook. All Rights Reserved. This module is free
447             software. It may be used, redistributed and/or modified under the same
448             terms as Perl itself.
449            
450             =cut