~ubuntu-branches/ubuntu/jaunty/libclass-meta-perl/jaunty

« back to all changes in this revision

Viewing changes to lib/Class/Meta/AccessorBuilder/SemiAffordance.pm

  • Committer: Bazaar Package Importer
  • Author(s): Krzysztof Krzyzaniak (eloy)
  • Date: 2006-01-03 17:29:20 UTC
  • Revision ID: james.westby@ubuntu.com-20060103172920-h94p8qrrav90bzq0
Tags: upstream-0.52
ImportĀ upstreamĀ versionĀ 0.52

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
package Class::Meta::AccessorBuilder::SemiAffordance;
 
2
 
 
3
# $Id: SemiAffordance.pm 2405 2005-12-17 03:41:09Z theory $
 
4
 
 
5
=head1 NAME
 
6
 
 
7
Class::Meta::AccessorBuilder::SemiAffordance - Semi-Affordance style accessor generation
 
8
 
 
9
=head1 SYNOPSIS
 
10
 
 
11
  package MyApp::TypeDef;
 
12
 
 
13
  use strict;
 
14
  use Class::Meta::Type;
 
15
  use IO::Socket;
 
16
 
 
17
  my $type = Class::Meta::Type->add( key     => 'io_socket',
 
18
                                     builder => 'semi-affordance',
 
19
                                     desc    => 'IO::Socket object',
 
20
                                     name    => 'IO::Socket Object' );
 
21
 
 
22
=head1 DESCRIPTION
 
23
 
 
24
This module provides a semi-affordance style accessor builder for Class::Meta.
 
25
Affordance accessors are attribute accessor methods that separate the getting
 
26
and setting of an attribute value into distinct methods. The approach both
 
27
eliminates the overhead of checking to see whether an accessor is called as a
 
28
getter or a setter, which is common for Perl style accessors, while also
 
29
creating a psychological barrier to accidentally misusing an attribute.
 
30
 
 
31
 
 
32
=head2 Accessors
 
33
 
 
34
Class::Meta::AccessorBuilder::SemiAffordance create two different types of
 
35
accessors: getters and setters. What makes the accessors generated by this
 
36
class "semi-affordance" rather than "affordance" accessors is that the getter
 
37
is simply named for the attribute, while the setter is prepended by C<set_>.
 
38
This approach differs from that of affordance accessors, where the getter is
 
39
prepended by C<get_>.
 
40
 
 
41
The type of accessors created depends on the value of the C<authz> attribute
 
42
of the Class::Meta::Attribute for which the accessor is being created.
 
43
 
 
44
For example, if the C<authz> is Class::Meta::RDWR, then two accessor methods
 
45
will be created:
 
46
 
 
47
  my $value = $obj->io_socket;
 
48
  $obj->set_io_socket($value);
 
49
 
 
50
If the value of C<authz> is Class::Meta::READ, then only the get method
 
51
will be created:
 
52
 
 
53
  my $value = $obj->io_socket;
 
54
 
 
55
And finally, if the value of C<authz> is Class::Meta::WRITE, then only the set
 
56
method will be created (why anyone would want this is beyond me, but I provide
 
57
for the sake of completeness):
 
58
 
 
59
  my $value = $obj->io_socket;
 
60
 
 
61
=head2 Data Type Validation
 
62
 
 
63
Class::Meta::AccessorBuilder::SemiAffordance uses all of the validation checks
 
64
passed to it to validate new values before assigning them to an attribute. It
 
65
also checks to see if the attribute is required, and if so, adds a check to
 
66
ensure that its value is never undefined. It does not currently check to
 
67
ensure that private and protected methods are used only in their appropriate
 
68
contexts, but may do so in a future release.
 
69
 
 
70
=head2 Class Attributes
 
71
 
 
72
If the C<context> attribute of the attribute object for which accessors are to
 
73
be built is C<Class::Meta::CLASS>, Class::Meta::AccessorBuilder will build
 
74
accessors for a class attribute instead of an object attribute. Of course,
 
75
this means that if you change the value of the class attribute in any
 
76
context--whether via a an object, the class name, or an an inherited class
 
77
name or object, the value will be changed everywhere.
 
78
 
 
79
For example, for a class attribute "count", you can expect the following to
 
80
work:
 
81
 
 
82
  MyApp::Custom->set_count(10);
 
83
  my $count = MyApp::Custom->count; # Returns 10.
 
84
  my $obj = MyApp::Custom->new;
 
85
  $count = $obj->count;             # Returns 10.
 
86
 
 
87
  $obj->set_count(22);
 
88
  $count = $obj->count;             # Returns 22.
 
89
  my $count = MyApp::Custom->count; # Returns 22.
 
90
 
 
91
  MyApp::Custom->set_count(35);
 
92
  $count = $obj->count;             # Returns 35.
 
93
  my $count = MyApp::Custom->count; # Returns 35.
 
94
 
 
95
Currently, class attribute accessors are not designed to be inheritable in the
 
96
way designed by Class::Data::Inheritable, although this might be changed in a
 
97
future release. For now, I expect that the current simple approach will cover
 
98
the vast majority of circumstances.
 
99
 
 
100
B<Note:> Class attribute accessors will not work accurately in multiprocess
 
101
environments such as mod_perl. If you change a class attribute's value in one
 
102
process, it will not be changed in any of the others. Furthermore, class
 
103
attributes are not currently shared across threads. So if you're using
 
104
Class::Meta class attributes in a multi-threaded environment (such as iThreads
 
105
in Perl 5.8.0 and later) the changes to a class attribute in one thread will
 
106
not be reflected in other threads.
 
107
 
 
108
=head1 Private and Protected Attributes
 
109
 
 
110
Any attributes that have their C<view> attribute set to Class::Meta::Private
 
111
or Class::Meta::Protected get additional validation installed to ensure that
 
112
they're truly private and protected. This includes when they are set via
 
113
parameters to constructors generated by Class::Meta. The validation is
 
114
performed by checking the caller of the accessors, and throwing an exception
 
115
when the caller isn't the class that owns the attribute (for private
 
116
attributes) or when it doesn't inherit from the class that owns the attribute
 
117
(for protected attributes).
 
118
 
 
119
As an implementation note, this validation is performed for parameters passed
 
120
to constructors created by Class::Meta by ignoring looking for the first
 
121
caller that isn't Class::Meta::Constructor:
 
122
 
 
123
  my $caller = caller;
 
124
  # Circumvent generated constructors.
 
125
  for (my $i = 1; $caller eq 'Class::Meta::Constructor'; $i++) {
 
126
      $caller = caller($i);
 
127
  }
 
128
 
 
129
This works because Class::Meta::Constructor installs the closures that become
 
130
constructors, and thus, when those closures call accessors to set new values
 
131
for attributes, the caller is Class::Meta::Constructor. By going up the stack
 
132
until we find another package, we correctly check to see what context is
 
133
setting attribute values via a constructor, rather than the constructor method
 
134
itself being the context.
 
135
 
 
136
This is a bit of a hack, but since Perl uses call stacks for checking security
 
137
in this way, it's the best I could come up with. Other suggestions welcome. Or
 
138
see L<Class::Meta::Type|Class::Meta::Type/"Custom Accessor Building"> to
 
139
create your own accessor generation code
 
140
 
 
141
=head1 INTERFACE
 
142
 
 
143
The following functions must be implemented by any Class::Meta accessor
 
144
generation module.
 
145
 
 
146
=head2 Functions
 
147
 
 
148
=head3 build_attr_get
 
149
 
 
150
  my $code = Class::Meta::AccessorBuilder::SemiAffordance::build_attr_get();
 
151
 
 
152
This function is called by C<Class::Meta::Type::make_attr_get()> and returns a
 
153
code reference that can be used by the C<get()> method of
 
154
Class::Meta::Attribute to return the value stored for that attribute for the
 
155
object passed to the code reference.
 
156
 
 
157
=head3 build_attr_set
 
158
 
 
159
  my $code = Class::Meta::AccessorBuilder::SemiAffordance::build_attr_set();
 
160
 
 
161
This function is called by C<Class::Meta::Type::make_attr_set()> and returns a
 
162
code reference that can be used by the C<set()> method of
 
163
Class::Meta::Attribute to set the value stored for that attribute for the
 
164
object passed to the code reference.
 
165
 
 
166
=head3 build
 
167
 
 
168
  Class::Meta::AccessorBuilder::SemiAffordance::build(
 
169
    $pkg, $attribute, $create, @checks
 
170
  );
 
171
 
 
172
This method is called by the C<build()> method of Class::Meta::Type, and does
 
173
the work of actually generating the accessors for an attribute object. The
 
174
arguments passed to it are:
 
175
 
 
176
=over 4
 
177
 
 
178
=item $pkg
 
179
 
 
180
The name of the class to which the accessors will be added.
 
181
 
 
182
=item $attribute
 
183
 
 
184
The Class::Meta::Attribute object that specifies the attribute for which the
 
185
accessors will be created.
 
186
 
 
187
=item $create
 
188
 
 
189
The value of the C<create> attribute of the Class::Meta::Attribute object,
 
190
which determines what accessors, if any, are to be created.
 
191
 
 
192
=item @checks
 
193
 
 
194
A list of code references that validate the value of an attribute. These will
 
195
be used in the set acccessor (mutator) to validate new attribute values.
 
196
 
 
197
=back
 
198
 
 
199
=cut
 
200
 
 
201
use strict;
 
202
use Class::Meta;
 
203
use base 'Class::Meta::AccessorBuilder::Affordance';
 
204
our $VERSION = "0.52";
 
205
 
 
206
sub build_attr_get {
 
207
    UNIVERSAL::can($_[0]->package, $_[0]->name);
 
208
}
 
209
 
 
210
sub build {
 
211
    my ($pkg, $attr, $name, $get, $set) = __PACKAGE__->_build(@_);
 
212
    # Install the accessors.
 
213
    no strict 'refs';
 
214
    *{"${pkg}::$name"} = $get if $get;
 
215
    *{"${pkg}::set_$name"} = $set if $set;
 
216
}
 
217
 
 
218
1;
 
219
__END__
 
220
 
 
221
=head1 BUGS
 
222
 
 
223
Please send bug reports to <bug-class-meta@rt.cpan.org> or report them via the
 
224
CPAN Request Tracker at L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=Class-Meta>.
 
225
 
 
226
=head1 AUTHOR
 
227
 
 
228
David Wheeler <david@kineticode.com>
 
229
 
 
230
=head1 SEE ALSO
 
231
 
 
232
=over 4
 
233
 
 
234
=item L<Class::Meta|Class::Meta>
 
235
 
 
236
This class contains most of the documentation you need to get started with
 
237
Class::Meta.
 
238
 
 
239
=item L<Class::Meta::AccessorBuilder|Class::Meta::AccessorBuilder>
 
240
 
 
241
This module generates Perl style accessors.
 
242
 
 
243
=item L<Class::Meta::Type|Class::Meta::Type>
 
244
 
 
245
This class manages the creation of data types.
 
246
 
 
247
=item L<Class::Meta::Attribute|Class::Meta::Attribute>
 
248
 
 
249
This class manages Class::Meta class attributes, most of which will have
 
250
generated accessors.
 
251
 
 
252
=back
 
253
 
 
254
=head1 COPYRIGHT AND LICENSE
 
255
 
 
256
Copyright (c) 2002-2005, David Wheeler. All Rights Reserved.
 
257
 
 
258
This module is free software; you can redistribute it and/or modify it under
 
259
the same terms as Perl itself.
 
260
 
 
261
=cut