1
package Class::Meta::Constructor;
3
# $Id: Constructor.pm 2449 2005-12-30 00:07:53Z theory $
7
Class::Meta::Constructor - Class::Meta class constructor introspection
11
# Assuming MyApp::Thingy was generated by Class::Meta.
12
my $class = MyApp::Thingy->my_class;
14
print "\nConstructors:\n";
15
for my $ctor ($class->constructors) {
16
print " o ", $ctor->name, $/;
17
my $thingy = $ctor->call($class->package);
22
This class provides an interface to the C<Class::Meta> objects that describe
23
class constructors. It supports a simple description of the constructor, a
24
label, and the constructor visibility (private, protected, trusted,or public).
26
Class::Meta::Constructor objects are created by Class::Meta; they are never
27
instantiated directly in client code. To access the constructor objects for a
28
Class::Meta-generated class, simply call its C<my_class()> method to retrieve
29
its Class::Meta::Class object, and then call the C<constructors()> method on
30
the Class::Meta::Class object.
34
##############################################################################
36
##############################################################################
39
##############################################################################
41
##############################################################################
42
our $VERSION = "0.52";
44
##############################################################################
46
##############################################################################
54
A protected method for constructing a Class::Meta::Constructor object. Do not
55
call this method directly; Call the
56
L<C<add_constructor()>|Class::Meta/"add_constructor"> method on a Class::Meta
65
# Check to make sure that only Class::Meta or a subclass is constructing a
66
# Class::Meta::Constructor object.
68
Class::Meta->handle_error("Package '$caller' cannot create $pkg "
70
unless UNIVERSAL::isa($caller, 'Class::Meta')
71
|| UNIVERSAL::isa($caller, __PACKAGE__);
73
# Make sure we can get all the arguments.
74
$class->handle_error("Odd number of parameters in call to new() when "
75
. "named parameters were expected")
80
$class->handle_error("Parameter 'name' is required in call to new()")
82
$class->handle_error("Constructor '$p{name}' is not a valid constructor "
83
. "name -- only alphanumeric and '_' characters "
87
# Make sure the name hasn't already been used for another constructor or
89
$class->handle_error("Method '$p{name}' already exists in class "
90
. "'$class->{package}'")
91
if exists $class->{ctors}{$p{name}}
92
or exists $class->{meths}{$p{name}};
94
# Check the visibility.
95
if (exists $p{view}) {
96
$class->handle_error("Not a valid view parameter: '$p{view}'")
97
unless $p{view} == Class::Meta::PUBLIC
98
|| $p{view} == Class::Meta::PROTECTED
99
|| $p{view} == Class::Meta::TRUSTED
100
|| $p{view} == Class::Meta::PRIVATE;
102
# Make it public by default.
103
$p{view} = Class::Meta::PUBLIC;
106
# Check the creation constant.
107
$p{create} = 1 unless defined $p{create};
109
# Validate or create the method caller if necessary.
111
my $ref = ref $p{caller};
112
$class->handle_error("Parameter caller must be a code reference")
113
unless $ref && $ref eq 'CODE';
115
$p{caller} = UNIVERSAL::can($class->{package}, $p{name})
119
# Create and cache the constructor object.
120
$p{package} = $class->{package};
121
$class->{ctors}{$p{name}} = bless \%p, ref $pkg || $pkg;
124
push @{ $class->{all_ctor_ord} }, $p{name};
125
if ($p{view} > Class::Meta::PRIVATE) {
126
push @{$class->{prot_ctor_ord}}, $p{name}
127
unless $p{view} == Class::Meta::TRUSTED;
128
if ($p{view} > Class::Meta::PROTECTED) {
129
push @{$class->{trst_ctor_ord}}, $p{name};
130
push @{$class->{ctor_ord}}, $p{name}
131
if $p{view} == Class::Meta::PUBLIC;
135
# Store a reference to the class object.
139
return $class->{ctors}{$p{name}};
143
##############################################################################
145
##############################################################################
147
=head2 Instance Methods
151
my $name = $ctor->name;
153
Returns the constructor name.
157
my $package = $ctor->package;
159
Returns the package name of the class that constructor is associated with.
163
my $desc = $ctor->desc;
165
Returns the description of the constructor.
169
my $desc = $ctor->label;
171
Returns label for the constructor.
175
my $view = $ctor->view;
177
Returns the view of the constructor, reflecting its visibility. The possible
178
values are defined by the following constants:
182
=item Class::Meta::PUBLIC
184
=item Class::Meta::PRIVATE
186
=item Class::Meta::TRUSTED
188
=item Class::Meta::PROTECTED
194
my $class = $ctor->class;
196
Returns the Class::Meta::Class object that this constructor is associated
197
with. Note that this object will always represent the class in which the
198
constructor is defined, and I<not> any of its subclasses.
202
sub name { $_[0]->{name} }
203
sub package { $_[0]->{package} }
204
sub desc { $_[0]->{desc} }
205
sub label { $_[0]->{label} }
206
sub view { $_[0]->{view} }
207
sub class { $_[0]->{class} }
211
my $obj = $ctor->call($package, @params);
213
Executes the constructor. Pass in the name of the class for which it is being
214
executed (since, thanks to subclassing, it may be different than the class
215
with which the constructor is associated). All other parameters will be passed
216
to the constructor. Note that it uses a C<goto> to execute the constructor, so
217
the call to C<call()> itself will not appear in a call stack trace.
223
my $code = $self->{caller}
224
or $self->class->handle_error("Cannot call constructor '",
229
##############################################################################
233
$ctor->build($class);
235
This is a protected method, designed to be called only by the Class::Meta
236
class or a subclass of Class::Meta. It takes a single argument, the
237
Class::Meta::Class object for the class in which the constructor was defined,
238
and generates constructor methods for the Class::Meta::Constructor object.
240
Although you should never call this method directly, subclasses of
241
Class::Meta::Constructor may need to override its behavior.
246
my ($self, $specs) = @_;
248
# Check to make sure that only Class::Meta or a subclass is building
251
$self->class->handle_error("Package '$caller' cannot call " . ref($self)
253
unless UNIVERSAL::isa($caller, 'Class::Meta')
254
|| UNIVERSAL::isa($caller, __PACKAGE__);
256
# Just bail if we're not creating the constructor.
257
return $self unless delete $self->{create};
259
# Build a construtor that takes a parameter list and assigns the
260
# the values to the appropriate attributes.
261
my $name = $self->name;
264
my $package = ref $_[0] ? ref shift : shift;
265
my $class = $specs->{$package};
267
# Throw an exception for attempts to create items of an abstract
269
$class->handle_error(
270
"Cannot construct objects of astract class $package"
271
) if $class->abstract;
273
# Just grab the parameters and let an error be thrown by Perl
274
# if there aren't the right number of them.
276
my $new = bless {}, $package;
278
# Assign all of the attribute values.
279
if (my $attrs = $class->{attrs}) {
280
foreach my $attr (@{ $attrs }{ @{ $class->{all_attr_ord} } }) {
281
# Skip class attributes.
282
next if $attr->context == Class::Meta::CLASS;
283
my $key = $attr->name;
284
if (exists $p{$key} && $attr->authz >= Class::Meta::SET) {
285
# Let them set the value.
286
$attr->set($new, delete $p{$key});
288
# Use the default value.
289
$new->{$key} = $attr->default unless exists $new->{$key};
294
# Check for params for which attributes are private or don't exist.
295
if (my @attributes = keys %p) {
296
# Attempts to assign to non-existent attributes fail.
297
my $c = $#attributes > 0 ? 'attributes' : 'attribute';
299
$class->handle_error(
300
"No such $c '@attributes' in $self->{package} objects"
306
# Add protected, private, or trusted checks, if required.
307
if ($self->view == Class::Meta::PROTECTED) {
309
my $pkg = $self->package;
310
my $class = $self->class;
312
$class->handle_error("$name is a protected constrctor of $pkg")
313
unless caller->isa($pkg);
316
} elsif ($self->view == Class::Meta::PRIVATE) {
318
my $pkg = $self->package;
319
my $class = $self->class;
321
$class->handle_error("$name is a private constructor of $pkg")
322
unless caller eq $pkg;
327
# Install the constructor.
328
$self->{caller} ||= $sub;
330
*{"$self->{package}::$name"} = $sub;
338
Please send bug reports to <bug-class-meta@rt.cpan.org> or report them via the
339
CPAN Request Tracker at L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=Class-Meta>.
343
David Wheeler <david@kineticode.com>
347
Other classes of interest within the Class::Meta distribution include:
351
=item L<Class::Meta|Class::Meta>
353
=item L<Class::Meta::Class|Class::Meta::Class>
355
=item L<Class::Meta::Method|Class::Meta::Method>
357
=item L<Class::Meta::Attribute|Class::Meta::Attribute>
361
=head1 COPYRIGHT AND LICENSE
363
Copyright (c) 2002-2005, David Wheeler. All Rights Reserved.
365
This module is free software; you can redistribute it and/or modify it under
366
the same terms as Perl itself.