File Coverage

blib/lib/Class/MakeMethods/Template/Universal.pm
Criterion Covered Total %
statement 24 45 53.3
branch 4 16 25.0
condition n/a
subroutine 12 16 75.0
pod 4 6 66.6
total 44 83 53.0


line stmt bran cond sub pod time code
1             package Class::MakeMethods::Template::Universal;
2              
3 92     92   3102 use Class::MakeMethods::Template '-isasubclass';
  92         177  
  92         765  
4              
5             $VERSION = 1.008;
6 92     92   601 use strict;
  92         183  
  92         127864  
7             require 5.00;
8             require Carp;
9              
10             =head1 NAME
11              
12             Class::MakeMethods::Template::Universal - Meta-methods for any type of object
13              
14             =head1 SYNOPSIS
15              
16             package MyObject;
17             use Class::MakeMethods::Template::Universal (
18             'no_op' => [ 'twiddle' ],
19             'croak' => [ 'fail', { croak_msg => 'Curses!' } ]
20             );
21            
22             package main;
23              
24             MyObject->twiddle; # Does nothing
25             if ( $foiled ) { MyObject->fail() } # Dies with croak_msg
26              
27             =head1 DESCRIPTION
28              
29             =head1 UNIVERSAL META-METHODS
30              
31             The following meta-methods and behaviors are applicable across
32             multiple types of classes and objects.
33              
34             =head2 Universal:generic
35              
36             This is not a directly-invokable method type, but instead provides code expressions for use in other method-generators.
37              
38             You can use any of these features in your meta-method interfaces without explicitly importing them.
39              
40             B
41              
42             =over 4
43              
44             =item *
45              
46             --private
47              
48             Causes the method to croak if it is called from outside of the package which originally declared it.
49              
50             Note that this protection can currently be circumvented if your class provides the method_init behavior, or another subroutine that calls methods by name.
51              
52             =item *
53              
54             --protected
55              
56             Causes the method to croak if it is called from a package other than the declaring package and its inheritors.
57              
58             Note that this protection can currently be circumvented if your class provides the method_init behavior, or another subroutine that calls methods by name.
59              
60             =item *
61              
62             --public
63              
64             Cancels any previous -private or -protected declaration.
65              
66             =item *
67              
68             --self_closure
69              
70             Causes the method to return a function reference which is bound to the arguments provided when it is first called.
71              
72             For examples of usage, see the test scripts in t/*closure.t.
73              
74             =item *
75              
76             --lvalue
77              
78             Adds the ":lvalue" attribute to the subroutine declaration.
79              
80             For examples of usage, see the test scripts in t/*lvalue.t.
81              
82             =item *
83              
84             --warn_calls
85              
86             For diagnostic purposes, call warn with the object reference, method name, and arguments before executing the body of the method.
87              
88              
89             =back
90              
91              
92             B
93              
94             =over 4
95              
96             =item *
97              
98             attributes
99              
100             Runtime access to method parameters.
101              
102             =item *
103              
104             no_op -- See below.
105              
106             =item *
107              
108             croak -- See below.
109              
110             =item *
111              
112             method_init -- See below.
113              
114             =back
115              
116             =cut
117              
118             sub generic {
119             {
120             'code_expr' => {
121             '_SELF_' => '$self',
122             '_SELF_CLASS_' => '(ref _SELF_ || _SELF_)',
123             '_SELF_INSTANCE_' => '(ref _SELF_ ? _SELF_ : undef)',
124             '_CLASS_FROM_INSTANCE_' => '(ref _SELF_ || croak "Can\'t invoke _STATIC_ATTR_{name} as a class method")',
125             '_ATTR_{}' => '$m_info->{*}',
126             '_STATIC_ATTR_{}' => '_ATTR_{*}',
127             '_ATTR_REQUIRED_{}' =>
128             '(_ATTR_{*} or Carp::croak("No * parameter defined for _ATTR_{name}"))',
129             '_ATTR_DEFAULT_{}' =>
130 0     0   0 sub { my @a = split(' ',$_[0],2); "(_ATTR_{$a[0]} || $a[1])" },
  0         0  
131            
132             _ACCESS_PRIVATE_ => '( ( (caller)[0] eq _ATTR_{target_class} ) or croak "Attempted access to private method _ATTR_{name}")',
133             _ACCESS_PROTECTED_ => '( UNIVERSAL::isa((caller)[0], _ATTR_{target_class}) or croak "Attempted access to protected method _ATTR_{name}" )',
134              
135             '_CALL_METHODS_FROM_HASH_' => q{
136             # Accept key-value attr list, or reference to unblessed hash of attrs
137             my @args = (scalar @_ == 1 and ref($_[0]) eq 'HASH') ? %{$_[0]} : @_;
138             while ( scalar @args ) { local $_ = shift(@args); $self->$_( shift(@args) ) }
139             },
140            
141             },
142             'modifier' => {
143             'self_closure' => q{ my @args = @_; return sub { unshift @_, @args; * } },
144             'warn_calls' => q{ warn $self."->_STATIC_ATTR_{name}(".join(', ',@_).")\n"; * },
145             'public' => q{ * },
146             'private' => q{ _ACCESS_PRIVATE_; * },
147             'protected' => q{ _ACCESS_PROTECTED_; * },
148             '-folding' => [
149             # Public is the default; all three options are mutually exclusive.
150             '-public' => '',
151             '-private -public' => '-public',
152             '-protected -public' => '-public',
153             '-private -protected' => '-protected',
154             '-protected -private' => '-private',
155             ],
156             'lvalue' => { _SUB_ATTRIBS_ => ': lvalue' },
157             },
158             'behavior' => {
159             -import => {
160             'Template::Universal:no_op' => 'no_op',
161             'Template::Universal:croak' => 'croak',
162             'Template::Universal:method_init' => 'method_init',
163             },
164             attributes => sub {
165 0     0   0 my $m_info = $_[0];
166             return sub {
167 0         0 my $self = shift;
168 0 0       0 if ( scalar @_ == 0 ) {
    0          
169 0         0 return $m_info;
170             } elsif ( scalar @_ == 1 ) {
171 0         0 return $m_info->{ shift() };
172             } else {
173 0         0 %$m_info = ( %$m_info, @_ );
174             }
175             }
176 0         0 },
177             },
178             }
179 92     92 0 3868 }
180              
181             ########################################################################
182              
183             =head2 no_op
184              
185             For each meta-method, creates a method with an empty body.
186              
187             use Class::MakeMethods::Template::Universal (
188             'no_op' => [ 'foo bar baz' ],
189             );
190              
191             You might want to create and use such methods to provide hooks for
192             subclass activity.
193              
194             No interfaces or parameters supported.
195              
196             =cut
197              
198             sub no_op {
199             {
200             'interface' => {
201             default => 'no_op',
202             'no_op' => 'no_op'
203             },
204             'behavior' => {
205 0     0   0 no_op => sub { my $m_info = $_[0]; sub { } },
  0         0  
  0         0  
206             },
207             }
208 92     92 1 1395 }
209              
210             ########################################################################
211              
212             =head2 croak
213              
214             For each meta-method, creates a method which will croak if called.
215              
216             use Class::MakeMethods::Template::Universal (
217             'croak' => [ 'foo bar baz' ],
218             );
219              
220             This is intended to support the use of abstract methods, that must
221             be overidden in a useful subclass.
222              
223             If each subclass is expected to provide an implementation of a given method, using this abstract method will replace the generic error message below with the clearer, more explicit error message that follows it:
224              
225             Can't locate object method "foo" via package "My::Subclass"
226             The "foo" method is abstract and can not be called on My::Subclass
227              
228             However, note that the existence of this method will be detected by UNIVERSAL::can(), so it is not suitable for use in optional interfaces, for which you may wish to be able to detect whether the method is supported or not.
229              
230             The -unsupported and -prohibited interfaces provide alternate error
231             messages, or a custom error message can be provided using the
232             'croak_msg' parameter.
233              
234             =cut
235              
236 2     2 0 6 sub abstract { 'croak --abstract' }
237              
238             sub croak {
239             {
240             'interface' => {
241             default => 'croak',
242             'croak' => 'croak',
243             'abstract' => {
244             '*'=>'croak', -params=> { 'croak_msg' =>
245             q/Can't locate abstract method "*" declared in "*{target_class}", called from "CALLCLASS"./
246             }
247             },
248             'abstract_minimal' => {
249             '*'=>'croak', -params=> { 'croak_msg' =>
250             "The * method is abstract and can not be called" }
251             },
252             'unsupported' => {
253             '*'=>'croak', -params=> { 'croak_msg' =>
254             "The * method does not support this operation" }
255             },
256             'prohibited' => {
257             '*'=>'croak', -params=> { 'croak_msg' =>
258             "The * method is not allowed to perform this activity" }
259             },
260             },
261             'behavior' => {
262             croak => sub {
263 7     7   11 my $m_info = $_[0];
264             sub {
265 3 50   3   6935 $m_info->{'croak_msg'} =~ s/CALLCLASS/ ref( $_[0] ) || $_[0] /ge
  3 50       23  
266             if $m_info->{'croak_msg'};
267 3         653 Carp::croak( $m_info->{'croak_msg'} );
268             }
269 7         50 },
270             },
271             }
272 92     92 1 2672 }
273              
274             ########################################################################
275              
276             =head2 method_init
277              
278             Creates a method that accepts a hash of key-value pairs, or a
279             reference to hash of such pairs. For each pair, the key is interpreted
280             as the name of a method to call, and the value is the argument to
281             be passed to that method.
282              
283             Sample declaration and usage:
284              
285             package MyObject;
286             use Class::MakeMethods::Template::Universal (
287             method_init => 'init',
288             );
289             ...
290            
291             my $object = MyObject->new()
292             $object->init( foo => 'Foozle', bar => 'Barbados' );
293            
294             # Equivalent to:
295             $object->foo('Foozle');
296             $object->bar('Barbados');
297              
298             You might want to create and use such methods to allow easy initialization of multiple object or class parameters in a single call.
299              
300             B: including methods of this type will circumvent the protection of C and C methods, because it an outside caller can cause an object to call specific methods on itself, bypassing the privacy protection.
301              
302             =cut
303              
304             sub method_init {
305             {
306 92     92 1 987 'interface' => {
307             default => 'method_init',
308             'method_init' => 'method_init'
309             },
310             'code_expr' => {
311             '-import' => { 'Template::Universal:generic' => '*' },
312             },
313             'behavior' => {
314             method_init => q{
315             _CALL_METHODS_FROM_HASH_
316             return $self;
317             }
318             },
319             }
320             }
321              
322             ########################################################################
323              
324             =head2 forward_methods
325              
326             Creates a method which delegates to an object provided by another method.
327              
328             Example:
329              
330             use Class::MakeMethods::Template::Universal
331             forward_methods => [
332             --target=> 'whistle', w,
333             [ 'x', 'y' ], { target=> 'xylophone' },
334             { name=>'z', target=>'zither', target_args=>[123], method_name=>do_zed },
335             ];
336              
337             Example: The above defines that method C will be handled by the
338             calling C on the object returned by C, whilst methods C
339             and C will be handled by C, and method C will be handled
340             by calling C on the object returned by calling C.
341              
342             B:
343              
344             =over 4
345              
346             =item forward (default)
347              
348             Calls the method on the target object. If the target object is missing, croaks at runtime with a message saying "Can't forward bar because bar is empty."
349              
350             =item delegate
351              
352             Calls the method on the target object, if present. If the target object is missing, returns nothing.
353              
354             =back
355              
356             B: The following additional parameters are supported:
357              
358             =over 4
359              
360             =item target
361              
362             I. The name of the method that will provide the object that will handle the operation.
363              
364             =item target_args
365              
366             Optional ref to an array of arguments to be passed to the target method.
367              
368             =item method_name
369              
370             The name of the method to call on the handling object. Defaults to the name of the meta-method being created.
371              
372             =back
373              
374             =cut
375              
376             sub forward_methods {
377             {
378             'interface' => {
379             default => 'forward',
380             'forward' => 'forward'
381             },
382             'params' => { 'method_name' => '*' },
383             'behavior' => {
384 4     4   7 'forward' => sub { my $m_info = $_[0]; sub {
385 5     5   1484 my $target = $m_info->{'target'};
386 5 50       21 my @args = $m_info->{'target_args'} ? @{$m_info->{'target_args'}} : ();
  0         0  
387 5 50       74 my $obj = (shift)->$target(@args)
388             or Carp::croak("Can't forward $m_info->{name} because $m_info->{target} is empty");
389 5         35 my $method = $m_info->{'method_name'};
390 5         22 $obj->$method(@_);
391 4         31 }},
392 0     0   0 'delegate' => sub { my $m_info = $_[0]; sub {
393 0         0 my $target = $m_info->{'target'};
394 0 0       0 my @args = $m_info->{'target_args'} ? @{$m_info->{'target_args'}} : ();
  0         0  
395 0 0       0 my $obj = (shift)->$target(@args)
396             or return;
397 0         0 my $method = $m_info->{'method_name'};
398 0         0 $obj->$method(@_);
399 0         0 }},
400             },
401             }
402 2     2 1 39 }
403              
404              
405             ########################################################################
406              
407             =head1 SEE ALSO
408              
409             See L for general information about this distribution.
410              
411             See L for information about this family of subclasses.
412              
413             =cut
414              
415             1;