1Class::Tiny(3) User Contributed Perl Documentation Class::Tiny(3)
2
3
4
6 Class::Tiny - Minimalist class construction
7
9 version 1.008
10
12 In Person.pm:
13
14 package Person;
15
16 use Class::Tiny qw( name );
17
18 1;
19
20 In Employee.pm:
21
22 package Employee;
23 use parent 'Person';
24
25 use Class::Tiny qw( ssn ), {
26 timestamp => sub { time } # attribute with default
27 };
28
29 1;
30
31 In example.pl:
32
33 use Employee;
34
35 my $obj = Employee->new( name => "Larry", ssn => "111-22-3333" );
36
37 # unknown attributes are ignored
38 my $obj = Employee->new( name => "Larry", OS => "Linux" );
39 # $obj->{OS} does not exist
40
42 This module offers a minimalist class construction kit in around 120
43 lines of code. Here is a list of features:
44
45 • defines attributes via import arguments
46
47 • generates read-write accessors
48
49 • supports lazy attribute defaults
50
51 • supports custom accessors
52
53 • superclass provides a standard "new" constructor
54
55 • "new" takes a hash reference or list of key/value pairs
56
57 • "new" supports providing "BUILDARGS" to customize constructor
58 options
59
60 • "new" calls "BUILD" for each class from parent to child
61
62 • superclass provides a "DESTROY" method
63
64 • "DESTROY" calls "DEMOLISH" for each class from child to parent
65
66 Multiple-inheritance is possible, with superclass order determined via
67 mro::get_linear_isa.
68
69 It uses no non-core modules for any recent Perl. On Perls older than
70 v5.10 it requires MRO::Compat. On Perls older than v5.14, it requires
71 Devel::GlobalDestruction.
72
74 Defining attributes
75 Define attributes as a list of import arguments:
76
77 package Foo::Bar;
78
79 use Class::Tiny qw(
80 name
81 id
82 height
83 weight
84 );
85
86 For each attribute, a read-write accessor is created unless a
87 subroutine of that name already exists:
88
89 $obj->name; # getter
90 $obj->name( "John Doe" ); # setter
91
92 Attribute names must be valid subroutine identifiers or an exception
93 will be thrown.
94
95 You can specify lazy defaults by defining attributes with a hash
96 reference. Keys define attribute names and values are constants or
97 code references that will be evaluated when the attribute is first
98 accessed if no value has been set. The object is passed as an argument
99 to a code reference.
100
101 package Foo::WithDefaults;
102
103 use Class::Tiny qw/name id/, {
104 title => 'Peon',
105 skills => sub { [] },
106 hire_date => sub { $_[0]->_build_hire_date },
107 };
108
109 When subclassing, if multiple accessors of the same name exist in
110 different classes, any default (or lack of default) is determined by
111 standard method resolution order.
112
113 To make your own custom accessors, just pre-declare the method name
114 before loading Class::Tiny:
115
116 package Foo::Bar;
117
118 use subs 'id';
119
120 use Class::Tiny qw( name id );
121
122 sub id { ... }
123
124 Even if you pre-declare a method name, you must include it in the
125 attribute list for Class::Tiny to register it as a valid attribute.
126
127 If you set a default for a custom accessor, your accessor will need to
128 retrieve the default and do something with it:
129
130 package Foo::Bar;
131
132 use subs 'id';
133
134 use Class::Tiny qw( name ), { id => sub { int(rand(2*31)) } };
135
136 sub id {
137 my $self = shift;
138 if (@_) {
139 return $self->{id} = shift;
140 }
141 elsif ( exists $self->{id} ) {
142 return $self->{id};
143 }
144 else {
145 my $defaults =
146 Class::Tiny->get_all_attribute_defaults_for( ref $self );
147 return $self->{id} = $defaults->{id}->();
148 }
149 }
150
151 Class::Tiny::Object is your base class
152 If your class does not already inherit from some class, then
153 Class::Tiny::Object will be added to your @ISA to provide "new" and
154 "DESTROY".
155
156 If your class does inherit from something, then no additional
157 inheritance is set up. If the parent subclasses Class::Tiny::Object,
158 then all is well. If not, then you'll get accessors set up but no
159 constructor or destructor. Don't do that unless you really have a
160 special need for it.
161
162 Define subclasses as normal. It's best to define them with base,
163 parent or superclass before defining attributes with Class::Tiny so the
164 @ISA array is already populated at compile-time:
165
166 package Foo::Bar::More;
167
168 use parent 'Foo::Bar';
169
170 use Class::Tiny qw( shoe_size );
171
172 Object construction
173 If your class inherits from Class::Tiny::Object (as it should if you
174 followed the advice above), it provides the "new" constructor for you.
175
176 Objects can be created with attributes given as a hash reference or as
177 a list of key/value pairs:
178
179 $obj = Foo::Bar->new( name => "David" );
180
181 $obj = Foo::Bar->new( { name => "David" } );
182
183 If a reference is passed as a single argument, it must be able to be
184 dereferenced as a hash or an exception is thrown.
185
186 Unknown attributes in the constructor arguments will be ignored. Prior
187 to version 1.000, unknown attributes were an error, but this made it
188 harder for people to cleanly subclass Class::Tiny classes so this
189 feature was removed.
190
191 You can define a "BUILDARGS" method to change how arguments to new are
192 handled. It will receive the constructor arguments as they were
193 provided and must return a hash reference of key/value pairs (or else
194 throw an exception).
195
196 sub BUILDARGS {
197 my $class = shift;
198 my $name = shift || "John Doe";
199 return { name => $name };
200 };
201
202 Foo::Bar->new( "David" );
203 Foo::Bar->new(); # "John Doe"
204
205 Unknown attributes returned from "BUILDARGS" will be ignored.
206
207 BUILD
208 If your class or any superclass defines a "BUILD" method, it will be
209 called by the constructor from the furthest parent class down to the
210 child class after the object has been created.
211
212 It is passed the constructor arguments as a hash reference. The return
213 value is ignored. Use "BUILD" for validation, checking required
214 attributes or setting default values that depend on other attributes.
215
216 sub BUILD {
217 my ($self, $args) = @_;
218
219 for my $req ( qw/name age/ ) {
220 croak "$req attribute required" unless defined $self->$req;
221 }
222
223 croak "Age must be non-negative" if $self->age < 0;
224
225 $self->msg( "Hello " . $self->name );
226 }
227
228 The argument reference is a copy, so deleting elements won't affect
229 data in the original (but changes will be passed to other BUILD methods
230 in @ISA).
231
232 DEMOLISH
233 Class::Tiny provides a "DESTROY" method. If your class or any
234 superclass defines a "DEMOLISH" method, they will be called from the
235 child class to the furthest parent class during object destruction. It
236 is provided a single boolean argument indicating whether Perl is in
237 global destruction. Return values are ignored. Errors are caught and
238 rethrown.
239
240 sub DEMOLISH {
241 my ($self, $global_destruct) = @_;
242 $self->cleanup();
243 }
244
245 Introspection and internals
246 You can retrieve an unsorted list of valid attributes known to
247 Class::Tiny for a class and its superclasses with the
248 "get_all_attributes_for" class method.
249
250 my @attrs = Class::Tiny->get_all_attributes_for("Employee");
251 # returns qw/name ssn timestamp/
252
253 Likewise, a hash reference of all valid attributes and default values
254 (or code references) may be retrieved with the
255 "get_all_attribute_defaults_for" class method. Any attributes without
256 a default will be "undef".
257
258 my $def = Class::Tiny->get_all_attribute_defaults_for("Employee");
259 # returns {
260 # name => undef,
261 # ssn => undef
262 # timestamp => $coderef
263 # }
264
265 The "import" method uses two class methods, "prepare_class" and
266 "create_attributes" to set up the @ISA array and attributes. Anyone
267 attempting to extend Class::Tiny itself should use these instead of
268 mocking up a call to "import".
269
270 When the first object is created, linearized @ISA, the valid attribute
271 list and various subroutine references are cached for speed. Ensure
272 that all inheritance and methods are in place before creating objects.
273 (You don't want to be changing that once you create objects anyway,
274 right?)
275
277 Why this instead of Object::Tiny or Class::Accessor or something else?
278 I wanted something so simple that it could potentially be used by core
279 Perl modules I help maintain (or hope to write), most of which either
280 use Class::Struct or roll-their-own OO framework each time.
281
282 Object::Tiny and Object::Tiny::RW were close to what I wanted, but
283 lacking some features I deemed necessary, and their maintainers have an
284 even more strict philosophy against feature creep than I have.
285
286 I also considered Class::Accessor, which has been around a long time
287 and is heavily used, but it, too, lacked features I wanted and did
288 things in ways I considered poor design.
289
290 I looked for something else on CPAN, but after checking a dozen class
291 creators I realized I could implement exactly what I wanted faster than
292 I could search CPAN for something merely sufficient.
293
294 In general, compared to most things on CPAN (other than Object::Tiny),
295 Class::Tiny is smaller in implementation and simpler in API.
296
297 Specifically, here is how Class::Tiny ("C::T") compares to Object::Tiny
298 ("O::T") and Class::Accessor ("C::A"):
299
300 FEATURE C::T O::T C::A
301 --------------------------------------------------------------
302 attributes defined via import yes yes no
303 read/write accessors yes no yes
304 lazy attribute defaults yes no no
305 provides new yes yes yes
306 provides DESTROY yes no no
307 new takes either hashref or list yes no (list) no (hash)
308 Moo(se)-like BUILD/DEMOLISH yes no no
309 Moo(se)-like BUILDARGS yes no no
310 no extraneous methods via @ISA yes yes no
311
312 Why this instead of Moose or Moo?
313 Moose and Moo are both excellent OO frameworks. Moose offers a
314 powerful meta-object protocol (MOP), but is slow to start up and has
315 about 30 non-core dependencies including XS modules. Moo is faster to
316 start up and has about 10 pure Perl dependencies but provides no true
317 MOP, relying instead on its ability to transparently upgrade Moo to
318 Moose when Moose's full feature set is required.
319
320 By contrast, Class::Tiny has no MOP and has zero non-core dependencies
321 for Perls in the support window. It has far less code, less complexity
322 and no learning curve. If you don't need or can't afford what Moo or
323 Moose offer, this is intended to be a reasonable fallback.
324
325 That said, Class::Tiny offers Moose-like conventions for things like
326 "BUILD" and "DEMOLISH" for some minimal interoperability and an easier
327 upgrade path.
328
330 David Golden <dagolden@cpan.org>
331
333 • Dagfinn Ilmari Mannsåker <ilmari@ilmari.org>
334
335 • David Golden <xdg@xdg.me>
336
337 • Gelu Lupas <gelu@devnull.ro>
338
339 • Karen Etheridge <ether@cpan.org>
340
341 • Matt S Trout <mstrout@cpan.org>
342
343 • Olivier Mengué <dolmen@cpan.org>
344
345 • Toby Inkster <tobyink@cpan.org>
346
348 This software is Copyright (c) 2013 by David Golden.
349
350 This is free software, licensed under:
351
352 The Apache License, Version 2.0, January 2004
353
354
355
356perl v5.36.0 2023-01-20 Class::Tiny(3)