File Coverage

blib/lib/Class/Meta/Method.pm
Criterion Covered Total %
statement 82 82 100.0
branch 54 58 93.1
condition 21 30 70.0
subroutine 17 17 100.0
pod 12 12 100.0
total 186 199 93.4


line stmt bran cond sub pod time code
1             package Class::Meta::Method;
2              
3             =head1 NAME
4              
5             Class::Meta::Method - Class::Meta class method introspection
6              
7             =head1 SYNOPSIS
8              
9             # Assuming MyApp::Thingy was generated by Class::Meta.
10             my $class = MyApp::Thingy->my_class;
11             my $thingy = MyApp::Thingy->new;
12              
13             print "\nMethods:\n";
14             for my $meth ($class->methods) {
15             print " o ", $meth->name, $/;
16             $meth->call($thingy);
17             }
18              
19             =head1 DESCRIPTION
20              
21             This class provides an interface to the C objects that describe
22             methods. It supports a simple description of the method, a label, and its
23             visibility (private, protected, trusted, or public).
24              
25             Class::Meta::Method objects are created by Class::Meta; they are never
26             instantiated directly in client code. To access the method objects for a
27             Class::Meta-generated class, simply call its C method to retrieve
28             its Class::Meta::Class object, and then call the C method on the
29             Class::Meta::Class object.
30              
31             =cut
32              
33             ##############################################################################
34             # Dependencies #
35             ##############################################################################
36 21     21   124 use strict;
  21         40  
  21         38771  
37              
38             ##############################################################################
39             # Package Globals #
40             ##############################################################################
41             our $VERSION = '0.66';
42              
43             =head1 INTERFACE
44              
45             =head2 Constructors
46              
47             =head3 new
48              
49             A protected method for constructing a Class::Meta::Method object. Do not call
50             this method directly; Call the L|Class::Meta/"add_method">
51             method on a Class::Meta object, instead.
52              
53             =cut
54              
55             sub new {
56 33     33 1 2064 my $pkg = shift;
57 33         47 my $class = shift;
58              
59             # Check to make sure that only Class::Meta or a subclass is constructing a
60             # Class::Meta::Method object.
61 33         73 my $caller = caller;
62 33 100 100     238 Class::Meta->handle_error("Package '$caller' cannot create $pkg "
63             . "objects")
64             unless UNIVERSAL::isa($caller, 'Class::Meta')
65             || UNIVERSAL::isa($caller, __PACKAGE__);
66              
67             # Make sure we can get all the arguments.
68 31 100       104 $class->handle_error("Odd number of parameters in call to new() "
69             . "when named parameters were expected")
70             if @_ % 2;
71              
72 30         118 my %p = @_;
73              
74             # Validate the name.
75 30 100       93 $class->handle_error("Parameter 'name' is required in call to "
76             . "new()") unless $p{name};
77 28 100       107 $class->handle_error("Method '$p{name}' is not a valid method "
78             . "name -- only alphanumeric and '_' characters allowed")
79             if $p{name} =~ /\W/;
80              
81             # Make sure the name hasn't already been used for another method
82             # or constructor.
83 27 100 66     219 $class->handle_error("Method '$p{name}' already exists in class "
84             . "'$class->{package}'")
85             if exists $class->{meths}{$p{name}}
86             || exists $class->{ctors}{$p{name}};
87              
88             # Check the visibility.
89 25 100       7214 if (exists $p{view}) {
90 11         49 $p{view} = Class::Meta::_str_to_const($p{view});
91 11 100 100     132 $class->handle_error("Not a valid view parameter: '$p{view}'")
      100        
      100        
92             unless $p{view} == Class::Meta::PUBLIC
93             || $p{view} == Class::Meta::PROTECTED
94             || $p{view} == Class::Meta::TRUSTED
95             || $p{view} == Class::Meta::PRIVATE;
96             } else {
97             # Make it public by default.
98 14         37 $p{view} = Class::Meta::PUBLIC;
99             }
100              
101             # Check the context.
102 23 100       63 if (exists $p{context}) {
103 4         18 $p{context} = Class::Meta::_str_to_const($p{context});
104 4 100 100     98 $class->handle_error("Not a valid context parameter: "
105             . "'$p{context}'")
106             unless $p{context} == Class::Meta::OBJECT
107             || $p{context} == Class::Meta::CLASS;
108             } else {
109             # Make it public by default.
110 19         47 $p{context} = Class::Meta::OBJECT;
111             }
112              
113             # Validate or create the method caller if necessary.
114 21 100       58 if ($p{caller}) {
115 4         12 my $ref = ref $p{caller};
116 4 50 33     36 $class->handle_error(
117             'Parameter caller must be a code reference'
118             ) unless $ref && $ref eq 'CODE'
119             } else {
120 17 100       1417 $p{caller} = eval "sub { shift->$p{name}(\@_) }"
121             if $p{view} > Class::Meta::PRIVATE;
122             }
123              
124 17 100       64 if ($p{code}) {
125 5         12 my $ref = ref $p{code};
126 5 50 33     27 $class->handle_error(
127             'Parameter code must be a code reference'
128             ) unless $ref && $ref eq 'CODE';
129             }
130              
131             # Create and cache the method object.
132 17         45 $p{package} = $class->{package};
133 17   33     128 $class->{meths}{$p{name}} = bless \%p, ref $pkg || $pkg;
134              
135             # Index its view.
136 17         26 push @{ $class->{all_meth_ord} }, $p{name};
  17         54  
137 17 100       55 if ($p{view} > Class::Meta::PRIVATE) {
138 15 100       45 push @{$class->{prot_meth_ord}}, $p{name}
  14         36  
139             unless $p{view} == Class::Meta::TRUSTED;
140 15 100       41 if ($p{view} > Class::Meta::PROTECTED) {
141 14         20 push @{$class->{trst_meth_ord}}, $p{name};
  14         159  
142 14 100       78 push @{$class->{meth_ord}}, $p{name}
  13         38  
143             if $p{view} == Class::Meta::PUBLIC;
144             }
145             }
146              
147             # Store a reference to the class object.
148 17         38 $p{class} = $class;
149              
150             # Let 'em have it.
151 17         74 return $class->{meths}{$p{name}};
152             }
153              
154             ##############################################################################
155             # Instance Methods #
156             ##############################################################################
157              
158             =head2 Instance Methods
159              
160             =head3 name
161              
162             my $name = $meth->name;
163              
164             Returns the method name.
165              
166             =head3 package
167              
168             my $package = $meth->package;
169              
170             Returns the method package.
171              
172             =head3 desc
173              
174             my $desc = $meth->desc;
175              
176             Returns the description of the method.
177              
178             =head3 label
179              
180             my $desc = $meth->label;
181              
182             Returns label for the method.
183              
184             =head3 view
185              
186             my $view = $meth->view;
187              
188             Returns the view of the method, reflecting its visibility. The possible
189             values are defined by the following constants:
190              
191             =over 4
192              
193             =item Class::Meta::PUBLIC
194              
195             =item Class::Meta::PRIVATE
196              
197             =item Class::Meta::TRUSTED
198              
199             =item Class::Meta::PROTECTED
200              
201             =back
202              
203             =head3 context
204              
205             my $context = $meth->context;
206              
207             Returns the context of the method, essentially whether it is a class or
208             object method. The possible values are defined by the following constants:
209              
210             =over 4
211              
212             =item Class::Meta::CLASS
213              
214             =item Class::Meta::OBJECT
215              
216             =back
217              
218             =head3 args
219              
220             A description of the arguments to the method. This can be anything you like,
221             but I recommend something like a string for a single argument, an array
222             reference for a list of arguments, or a hash reference for parameter
223             arguments.
224              
225             =head3 returns
226              
227             A description of the return value or values of the method.
228              
229             =head3 class
230              
231             my $class = $meth->class;
232              
233             Returns the Class::Meta::Class object that this method is associated
234             with. Note that this object will always represent the class in which the
235             method is defined, and I any of its subclasses.
236              
237             =cut
238              
239 10     10 1 69 sub name { $_[0]->{name} }
240 10     10 1 41 sub package { $_[0]->{package} }
241 3     3 1 15 sub desc { $_[0]->{desc} }
242 3     3 1 14 sub label { $_[0]->{label} }
243 19     19 1 67 sub view { $_[0]->{view} }
244 4     4 1 19 sub context { $_[0]->{context} }
245 2     2 1 67 sub args { $_[0]->{args} }
246 2     2 1 15 sub returns { $_[0]->{returns} }
247 10     10 1 68 sub class { $_[0]->{class} }
248              
249             =head3 call
250              
251             my $ret = $meth->call($obj, @args);
252              
253             Calls the method on the C<$obj> object, passing in any arguments. Note that it
254             uses a C to execute the method, so the call to C itself will not
255             appear in a call stack trace.
256              
257             =cut
258              
259             sub call {
260 12     12 1 2841 my $self = shift;
261 12 100       52 my $code = $self->{caller}
262             or $self->class->handle_error("Cannot call method '", $self->name, "'");
263 11         383 goto &$code;
264             }
265              
266             ##############################################################################
267              
268             =head3 build
269              
270             $meth->build($class);
271              
272             This is a protected method, designed to be called only by the Class::Meta
273             class or a subclass of Class::Meta. It takes a single argument, the
274             Class::Meta::Class object for the class in which the method was defined. Once
275             it checks to make sure that it is only called by Class::Meta or a subclass of
276             Class::Meta or of Class::Meta::Method, C installs the method if it
277             was specified via the C parameter to C.
278              
279             Although you should never call this method directly, subclasses of
280             Class::Meta::Method may need to override it in order to add behavior.
281              
282             =cut
283              
284             sub build {
285 14     14 1 21 my ($self, $class) = @_;
286              
287             # Check to make sure that only Class::Meta or a subclass is building
288             # methods.
289 14         26 my $caller = caller;
290 14 50 33     63 $self->class->handle_error(
291             "Package '$caller' cannot call " . ref($self) . "->build"
292             ) unless UNIVERSAL::isa($caller, 'Class::Meta')
293             || UNIVERSAL::isa($caller, __PACKAGE__);
294              
295             # Install the method if we've got it.
296 14 100       44 if (my $code = delete $self->{code}) {
297 5         13 my $pack = $self->package;
298 5         18 my $name = $self->{name};
299 5 100       19 if ($self->{view} < Class::Meta::PUBLIC ) {
300             # Add a constraint to the code ref.
301 3         2 my $real_meth = $code;
302 3 100       10 if ($self->{view} == Class::Meta::PROTECTED) {
    100          
    50          
303             $code = sub {
304 4 100   4   3672 $self->class->handle_error(
305             "$name is a protected method of $pack"
306             ) unless UNIVERSAL::isa(scalar caller, $pack);
307 2         9 goto &$real_meth;
308 1         3 };
309             } elsif ($self->{view} == Class::Meta::PRIVATE) {
310             $code = sub {
311 4 100   4   24 $self->class->handle_error(
312             "$name is a private method of $pack"
313             ) unless caller eq $pack;
314 1         5 goto &$real_meth;
315 1         5 };
316             } elsif ($self->{view} == Class::Meta::TRUSTED) {
317 1         3 my $trusted = $self->class->trusted;
318             $code = sub {
319 4     4   4626 my $caller = caller;
320 4 100       18 goto &$real_meth if $caller eq $pack;
321 3         5 for my $pkg ( @{ $trusted } ) {
  3         9  
322 3 100       33 goto &$real_meth if UNIVERSAL::isa($caller, $pkg);
323             }
324             $self->class->handle_error(
325 2         9 "$name is a trusted method of $pack"
326             );
327 1         4 };
328             }
329             }
330              
331 21     21   168 no strict 'refs';
  21         650  
  21         1993  
332 5         6 *{"$pack\::$name"} = $code;
  5         25  
333             }
334              
335 14         54 return $self;
336             }
337              
338             1;
339             __END__