File Coverage

blib/lib/Class/Meta/Constructor.pm
Criterion Covered Total %
statement 102 102 100.0
branch 53 60 88.3
condition 24 35 68.5
subroutine 14 14 100.0
pod 9 9 100.0
total 202 220 91.8


line stmt bran cond sub pod time code
1             package Class::Meta::Constructor;
2              
3             =head1 NAME
4              
5             Class::Meta::Constructor - Class::Meta class constructor introspection
6              
7             =head1 SYNOPSIS
8              
9             # Assuming MyApp::Thingy was generated by Class::Meta.
10             my $class = MyApp::Thingy->my_class;
11              
12             print "\nConstructors:\n";
13             for my $ctor ($class->constructors) {
14             print " o ", $ctor->name, $/;
15             my $thingy = $ctor->call($class->package);
16             }
17              
18             =head1 DESCRIPTION
19              
20             This class provides an interface to the C objects that describe
21             class constructors. It supports a simple description of the constructor, a
22             label, and the constructor visibility (private, protected, trusted,or public).
23              
24             Class::Meta::Constructor objects are created by Class::Meta; they are never
25             instantiated directly in client code. To access the constructor objects for a
26             Class::Meta-generated class, simply call its C method to retrieve
27             its Class::Meta::Class object, and then call the C method on
28             the Class::Meta::Class object.
29              
30             =cut
31              
32             ##############################################################################
33             # Dependencies #
34             ##############################################################################
35 21     21   116 use strict;
  21         43  
  21         41374  
36              
37             ##############################################################################
38             # Package Globals #
39             ##############################################################################
40             our $VERSION = '0.66';
41              
42             ##############################################################################
43             # Constructors #
44             ##############################################################################
45              
46             =head1 INTERFACE
47              
48             =head2 Constructors
49              
50             =head3 new
51              
52             A protected method for constructing a Class::Meta::Constructor object. Do not
53             call this method directly; Call the
54             L|Class::Meta/"add_constructor"> method on a Class::Meta
55             object, instead.
56              
57             =cut
58              
59             sub new {
60 42     42 1 704 my $pkg = shift;
61 42         72 my $class = shift;
62              
63             # Check to make sure that only Class::Meta or a subclass is constructing a
64             # Class::Meta::Constructor object.
65 42         83 my $caller = caller;
66 42 100 100     314 Class::Meta->handle_error("Package '$caller' cannot create $pkg "
67             . "objects")
68             unless UNIVERSAL::isa($caller, 'Class::Meta')
69             || UNIVERSAL::isa($caller, __PACKAGE__);
70              
71             # Make sure we can get all the arguments.
72 40 100       148 $class->handle_error("Odd number of parameters in call to new() when "
73             . "named parameters were expected")
74             if @_ % 2;
75 39         179 my %p = @_;
76              
77             # Validate the name.
78 39 100       147 $class->handle_error("Parameter 'name' is required in call to new()")
79             unless $p{name};
80 37 100       163 $class->handle_error("Constructor '$p{name}' is not a valid constructor "
81             . "name -- only alphanumeric and '_' characters "
82             . "allowed")
83             if $p{name} =~ /\W/;
84              
85             # Make sure the name hasn't already been used for another constructor or
86             # method.
87 36 100 66     335 $class->handle_error("Method '$p{name}' already exists in class "
88             . "'$class->{package}'")
89             if exists $class->{ctors}{$p{name}}
90             or exists $class->{meths}{$p{name}};
91              
92             # Check the visibility.
93 34 100       108 if (exists $p{view}) {
94 9         40 $p{view} = Class::Meta::_str_to_const($p{view});
95 9 100 100     123 $class->handle_error("Not a valid view parameter: '$p{view}'")
      100        
      100        
96             unless $p{view} == Class::Meta::PUBLIC
97             || $p{view} == Class::Meta::PROTECTED
98             || $p{view} == Class::Meta::TRUSTED
99             || $p{view} == Class::Meta::PRIVATE;
100             } else {
101             # Make it public by default.
102 25         75 $p{view} = Class::Meta::PUBLIC;
103             }
104              
105             # Use passed code or create the constructor?
106 31 100       110 if ($p{code}) {
107 1         3 my $ref = ref $p{code};
108 1 50 33     10 $class->handle_error(
109             'Parameter code must be a code reference'
110             ) unless $ref && $ref eq 'CODE';
111 1         3 $p{create} = 0;
112             } else {
113 30 100       140 $p{create} = 1 unless exists $p{create};
114             }
115              
116             # Validate or create the method caller if necessary.
117 31 100       107 if ($p{caller}) {
118 1         2 my $ref = ref $p{caller};
119 1 50 33     6 $class->handle_error("Parameter caller must be a code reference")
120             unless $ref && $ref eq 'CODE';
121             } else {
122 30 100       134 $p{caller} = UNIVERSAL::can($class->{package}, $p{name})
123             unless $p{create};
124             }
125              
126             # Create and cache the constructor object.
127 30         89 $p{package} = $class->{package};
128 30   33     264 $class->{ctors}{$p{name}} = bless \%p, ref $pkg || $pkg;
129              
130             # Index its view.
131 30         63 push @{ $class->{all_ctor_ord} }, $p{name};
  30         110  
132 30 100       114 if ($p{view} > Class::Meta::PRIVATE) {
133 28 100       108 push @{$class->{prot_ctor_ord}}, $p{name}
  27         120  
134             unless $p{view} == Class::Meta::TRUSTED;
135 28 100       119 if ($p{view} > Class::Meta::PROTECTED) {
136 27         100 push @{$class->{trst_ctor_ord}}, $p{name};
  27         103  
137 27 100       154 push @{$class->{ctor_ord}}, $p{name}
  26         85  
138             if $p{view} == Class::Meta::PUBLIC;
139             }
140             }
141              
142             # Store a reference to the class object.
143 30         81 $p{class} = $class;
144              
145             # Let 'em have it.
146 30         182 return $class->{ctors}{$p{name}};
147             }
148              
149              
150             ##############################################################################
151             # Instance Methods #
152             ##############################################################################
153              
154             =head2 Instance Methods
155              
156             =head3 name
157              
158             my $name = $ctor->name;
159              
160             Returns the constructor name.
161              
162             =head3 package
163              
164             my $package = $ctor->package;
165              
166             Returns the package name of the class that constructor is associated with.
167              
168             =head3 desc
169              
170             my $desc = $ctor->desc;
171              
172             Returns the description of the constructor.
173              
174             =head3 label
175              
176             my $desc = $ctor->label;
177              
178             Returns label for the constructor.
179              
180             =head3 view
181              
182             my $view = $ctor->view;
183              
184             Returns the view of the constructor, reflecting its visibility. The possible
185             values are defined by the following constants:
186              
187             =over 4
188              
189             =item Class::Meta::PUBLIC
190              
191             =item Class::Meta::PRIVATE
192              
193             =item Class::Meta::TRUSTED
194              
195             =item Class::Meta::PROTECTED
196              
197             =back
198              
199             =head3 class
200              
201             my $class = $ctor->class;
202              
203             Returns the Class::Meta::Class object that this constructor is associated
204             with. Note that this object will always represent the class in which the
205             constructor is defined, and I any of its subclasses.
206              
207             =cut
208              
209 40     40 1 223 sub name { $_[0]->{name} }
210 2     2 1 6 sub package { $_[0]->{package} }
211 3     3 1 19 sub desc { $_[0]->{desc} }
212 3     3 1 16 sub label { $_[0]->{label} }
213 85     85 1 443 sub view { $_[0]->{view} }
214 5     5 1 26 sub class { $_[0]->{class} }
215              
216             =head3 call
217              
218             my $obj = $ctor->call($package, @params);
219              
220             Executes the constructor. Pass in the name of the class for which it is being
221             executed (since, thanks to subclassing, it may be different than the class
222             with which the constructor is associated). All other parameters will be passed
223             to the constructor. Note that it uses a C to execute the constructor, so
224             the call to C itself will not appear in a call stack trace.
225              
226             =cut
227              
228             sub call {
229 47     47 1 22363 my $self = shift;
230 47 100       203 my $code = $self->{caller} or $self->class->handle_error(
231             q{Cannot call constructor '}, $self->name, q{'}
232             );
233 46         185 goto &$code;
234             }
235              
236             ##############################################################################
237              
238             =head3 build
239              
240             $ctor->build($class);
241              
242             This is a protected method, designed to be called only by the Class::Meta
243             class or a subclass of Class::Meta. It takes a single argument, the
244             Class::Meta::Class object for the class in which the constructor was defined,
245             and generates constructor method for the Class::Meta::Constructor, either by
246             installing the code reference passed in the C parameter or by creating
247             the constructor from scratch.
248              
249             Although you should never call this method directly, subclasses of
250             Class::Meta::Constructor may need to override its behavior.
251              
252             =cut
253              
254             sub build {
255 26     26 1 1760 my ($self, $specs) = @_;
256              
257             # Check to make sure that only Class::Meta or a subclass is building
258             # constructors.
259 26         60 my $caller = caller;
260 26 100 66     1621 $self->class->handle_error("Package '$caller' cannot call " . ref($self)
261             . "->build")
262             unless UNIVERSAL::isa($caller, 'Class::Meta')
263             || UNIVERSAL::isa($caller, __PACKAGE__);
264              
265             # Just bail if we're not creating or installing the constructor.
266 25 50 66     1403 return $self unless delete $self->{create} || $self->{code};
267              
268             # Build a construtor that takes a parameter list and assigns the
269             # the values to the appropriate attributes.
270 25         191 my $name = $self->name;
271              
272             my $sub = delete $self->{code} || sub {
273 119 50   119   44906 my $package = ref $_[0] ? ref shift : shift;
274 119         320 my $class = $specs->{$package};
275              
276             # Throw an exception for attempts to create items of an abstract
277             # class.
278 119         542 $class->handle_error(
279             "Cannot construct objects of astract class $package"
280             ) if $class->abstract;
281              
282             # Is there a sub passed as the last argument?
283 118 100       582 my $sub = @_ % 2 && ref $_[-1] eq 'CODE' ? pop @_ : undef;
284              
285             # Just grab the parameters and let an error be thrown by Perl
286             # if there aren't the right number of them.
287 118         554 my %p = @_;
288 118         956 my $new = bless {} => $package;
289              
290             # Assign all of the attribute values.
291 118         200 my @req;
292 118         430 if (my $attrs = $class->{attrs}) {
293 111         166 foreach my $attr (@{ $attrs }{ @{ $class->{all_attr_ord} } }) {
  111         811  
  111         285  
294             # Skip class attributes.
295 394         1205 next if $attr->context == Class::Meta::CLASS;
296 386         1059 my $key = $attr->name;
297 386 100       2291 if (exists $p{$key} && $attr->authz >= Class::Meta::SET) {
    50          
298             # Let them set the value.
299 134         527 $attr->set($new, delete $p{$key});
300             } elsif (!exists $new->{$key}) {
301             # Use the default value.
302 252         731 $new->{$key} = $attr->default;
303 252         767 push @req, $attr if $attr->required;
304             }
305             }
306             }
307              
308             # Check for params for which attributes are private or don't exist.
309 78         373 if (my @attributes = keys %p) {
310             # Attempts to assign to non-existent attributes fail.
311 2 50       8 my $c = $#attributes > 0 ? 'attributes' : 'attribute';
312 2         4 local $" = q{', '};
313 2         35 $class->handle_error(
314             "No such $c '@attributes' in $self->{package} objects"
315             );
316             }
317              
318             # Run the block passed, if there is one.
319 76         232 $sub->($new) if $sub;
320              
321             # Enforce required attributes.
322 76         754 if (@req and my @miss = grep { !defined $new->{ $_->name } } @req ) {
  65         300  
323 1 50       6 my $c = $#miss > 0 ? 'Attributes' : 'Attribute';
324 1         2 my $a = join q{', '}, map { $_->name } @miss;
  1         5  
325 1         10 $class->handle_error(
326             "$c '$a' must be defined in $self->{package} objects"
327             );
328             }
329              
330 75         550 return $new;
331 25   100     388 };
332              
333             # Add protected, private, or trusted checks, if required.
334 25 100       103 if ($self->view == Class::Meta::PROTECTED) {
    100          
335 1         4 my $real_sub = $sub;
336 1         4 my $pkg = $self->package;
337 1         14 my $class = $self->class;
338             $sub = sub {
339 9 100   9   6514 $class->handle_error("$name is a protected constrctor of $pkg")
340             unless caller->isa($pkg);
341 6         21 goto &$real_sub;
342 1         5 };
343             } elsif ($self->view == Class::Meta::PRIVATE) {
344 1         2 my $real_sub = $sub;
345 1         4 my $pkg = $self->package;
346 1         4 my $class = $self->class;
347             $sub = sub {
348 7 100   7   4297 $class->handle_error("$name is a private constructor of $pkg")
349             unless caller eq $pkg;
350 2         6 goto &$real_sub;
351 1         6 };
352             }
353              
354             # Install the constructor.
355 25   33     266 $self->{caller} ||= $sub;
356 21     21   167 no strict 'refs';
  21         42  
  21         1998  
357 25         46 *{"$self->{package}::$name"} = $sub;
  25         282  
358             }
359              
360             1;
361             __END__