File Coverage

blib/lib/Method/Utils.pm
Criterion Covered Total %
statement 72 72 100.0
branch 13 14 92.8
condition 2 6 33.3
subroutine 13 13 100.0
pod 3 3 100.0
total 103 108 95.3


line stmt bran cond sub pod time code
1             # You may distribute under the terms of either the GNU General Public License
2             # or the Artistic License (the same terms as Perl itself)
3             #
4             # (C) Paul Evans, 2011 -- leonerd@leonerd.org.uk
5              
6             package Method::Utils;
7              
8 3     3   38084 use strict;
  3         5  
  3         93  
9 3     3   11 use warnings;
  3         4  
  3         139  
10              
11             our $VERSION = '0.01_001';
12              
13 3     3   24 use Exporter 'import';
  3         3  
  3         564  
14              
15             our @EXPORT_OK = qw(
16             possibly
17              
18             inwardly
19             outwardly
20             );
21              
22             =head1 NAME
23              
24             C - functional-style utilities for method calls
25              
26             =cut
27              
28             =head1 FUNCTIONS
29              
30             All of the following functions are intended to be used as method call
31             modifiers. That is, they return a C reference to a C reference
32             which allows them to be used in the following syntax
33              
34             $ball->${possibly "bounce"}( "10 metres" );
35              
36             Since the returned double-reference can be dereferenced by C<${ }> to obtain
37             the C reference directly, it can be used to create new methods. For
38             example:
39              
40             *bounce_if_you_can = ${possibly "bounce"};
41              
42             The following utilities are described from the perspective of directly
43             invoking the returned code, as in the first example.
44              
45             =cut
46              
47             =head2 possibly $method
48              
49             Invokes the named method on the object or class and return what it returned,
50             if it exists. If the method does not exist, returns C in scalar context
51             or the empty list in list context.
52              
53             =cut
54              
55             sub possibly
56             {
57 8     8 1 1792 my $mth = shift;
58             \sub {
59 8     8   7 my $self = shift;
60 8 100       40 return unless $self->can( $mth );
61 4         9 $self->$mth( @_ );
62 8         36 };
63             }
64              
65             =head2 inwardly $method
66              
67             =head2 outwardly $method
68              
69             Invokes the named method on the object or class for I class that
70             provides such a method in the C<@ISA> heirarchy, not just the first one that
71             is found. C starts its search at the topmost class; that is, the
72             class name (or type of the object) provided, and starts searching down towards
73             superclasses. C starts its search at the base-most superclass,
74             searching upward before finally ending at the topmost class.
75              
76             In the case of multiple inheritance, subclasses are always searched in the
77             order that they appear in the C<@ISA> array.
78              
79             In the case that multiple inheritance brings the same subclass in more than
80             once, they are arranged into a consistent order. That is, C ensures
81             that no superclass will be searched until every subclass that uses it has been
82             searched first; while C ensures that no superclass will be searched
83             before every subclass that it uses has been searched already.
84              
85             =cut
86              
87             sub inwardly
88             {
89 2     2 1 10 my $mth = shift;
90             \sub {
91 2     2   3 my $self = shift;
92              
93 2         3 my @packages;
94 2   33     8 my @queue = ref $self || $self;
95 2         2 my %seen;
96 2         4 while( @queue ) {
97 13         12 my $class = shift @queue;
98 13         12 push @packages, $class;
99 13 100       17 if( defined $seen{$class} ) {
100 2         4 undef $packages[$seen{$class}];
101 2         2 $seen{$class} = $#packages;
102 2         3 next;
103             }
104             else {
105 11         11 $seen{$class} = $#packages;
106 3     3   13 unshift @queue, do { no strict 'refs'; @{$class."::ISA"} };
  3         4  
  3         699  
  11         5  
  11         9  
  11         52  
107             }
108             }
109              
110 2         3 for my $class ( @packages ) {
111 3     3   15 no strict 'refs';
  3         5  
  3         537  
112 13 100       35 defined $class or next;
113 11 100       8 defined &{$class."::$mth"} or next;
  11         24  
114 9         7 &{$class."::$mth"}( $self, @_ );
  9         21  
115             }
116             }
117 2         14 }
118              
119             sub outwardly
120             {
121 1     1 1 1 my $mth = shift;
122             \sub {
123 1     1   2 my $self = shift;
124              
125 1         9 my @packages;
126 1   33     6 my @queue = ref $self || $self;
127 1         2 my %seen;
128 1         2 while( @queue ) {
129 7         18 my $class = shift @queue;
130 7         8 push @packages, $class;
131 7 100       8 if( defined $seen{$class} ) {
132 1         2 undef $packages[$seen{$class}];
133 1         2 $seen{$class} = $#packages;
134 1         2 next;
135             }
136             else {
137 6         5 $seen{$class} = $#packages;
138 3     3   14 unshift @queue, reverse do { no strict 'refs'; @{$class."::ISA"} };
  3         3  
  3         157  
  6         5  
  6         4  
  6         18  
139             }
140             }
141              
142 1         2 for my $class ( reverse @packages ) {
143 3     3   13 no strict 'refs';
  3         3  
  3         350  
144 7 100       19 defined $class or next;
145 6 50       40 defined &{$class."::$mth"} or next;
  6         13  
146 6         3 &{$class."::$mth"}( $self, @_ );
  6         13  
147             }
148             }
149 1         7 }
150              
151             =head1 AUTHOR
152              
153             Paul Evans
154              
155             =cut
156              
157             0x55AA;