1MooseX::AttributeShortcUustesr(3C)ontributed Perl DocumeMnotoasteiXo:n:AttributeShortcuts(3)
2
3
4
6 MooseX::AttributeShortcuts - Shorthand for common attribute options
7
9 This document describes version 0.037 of MooseX::AttributeShortcuts -
10 released November 20, 2017 as part of MooseX-AttributeShortcuts.
11
13 package Some::Class;
14
15 use Moose;
16 use MooseX::AttributeShortcuts;
17
18 # same as:
19 # is => 'ro', lazy => 1, builder => '_build_foo'
20 has foo => (is => 'lazy');
21
22 # same as: is => 'ro', writer => '_set_foo'
23 has foo => (is => 'rwp');
24
25 # same as: is => 'ro', builder => '_build_bar'
26 has bar => (is => 'ro', builder => 1);
27
28 # same as: is => 'ro', clearer => 'clear_bar'
29 has bar => (is => 'ro', clearer => 1);
30
31 # same as: is => 'ro', predicate => 'has_bar'
32 has bar => (is => 'ro', predicate => 1);
33
34 # works as you'd expect for "private": predicate => '_has_bar'
35 has _bar => (is => 'ro', predicate => 1);
36
37 # extending? Use the "Shortcuts" trait alias
38 extends 'Some::OtherClass';
39 has '+bar' => (traits => [Shortcuts], builder => 1, ...);
40
42 Ever find yourself repeatedly specifying writers and builders, because
43 there's no good shortcut to specifying them? Sometimes you want an
44 attribute to have a read-only public interface, but a private writer.
45 And wouldn't it be easier to just say "builder => 1" and have the
46 attribute construct the canonical "_build_$name" builder name for you?
47
48 This package causes an attribute trait to be applied to all attributes
49 defined to the using class. This trait extends the attribute option
50 processing to handle the above variations. All attribute options as
51 described in Moose or Class::MOP::Attribute remain usable, just as when
52 this trait is not applied.
53
54 Some Notes On History
55 Moose has long had a lazy_build attribute option. It was once
56 considered a best practice, but that has, ah, changed. This trait
57 began as a desire to still leverage bits of "lazy_build" (and a tacit
58 acknowledgment that fat-finger bugs rank among the most embarrassing,
59 right up there with "the TV was unplugged the entire time").
60
61 This author does not recommend you use "lazy_build", unless you know
62 exactly what you're doing (probably) and that it's a good idea
63 (probably not).
64
65 Nonetheless, this "lazy_build" option is why we set certain options the
66 way we do below; while "lazy_build" in its entirety is not optimal, it
67 had the right idea: regular, predictable accessor names for regular,
68 predictable attribute options.
69
70 As an example, just looking at the below it doesn't seem logical that:
71
72 has _foo => (is => 'ro', clearer => 1);
73
74 ...becomes:
75
76 has _foo => (is => 'ro', clearer => '_clear_foo');
77
78 After reading the lazy_build attribute option, however, we see that the
79 choice had already been made for us.
80
82 This package automatically applies an attribute metaclass trait.
83 Simply using this package causes the trait to be applied by default to
84 your attribute's metaclasses.
85
87 If you're extending a class and trying to extend its attributes as
88 well, you'll find out that the trait is only applied to attributes
89 defined locally in the class. This package exports a trait shortcut
90 function "Shortcuts" that will help you apply this to the extended
91 attribute:
92
93 has '+something' => (traits => [Shortcuts], ...);
94
96 Unless specified here, all options defined by Moose::Meta::Attribute
97 and Class::MOP::Attribute remain unchanged.
98
99 Want to see additional options? Ask, or better yet, fork on GitHub and
100 send a pull request. If the shortcuts you're asking for already exist
101 in Moo or Mouse or elsewhere, please note that as it will carry
102 significant weight.
103
104 For the following, $name should be read as the attribute name; and the
105 various prefixes should be read using the defaults.
106
107 is => 'rwp'
108 Specifying "is => 'rwp'" will cause the following options to be set:
109
110 is => 'ro'
111 writer => "_set_$name"
112
113 rwp can be read as "read + write private".
114
115 is => 'lazy'
116 Specifying "is => 'lazy'" will cause the following options to be set:
117
118 is => 'ro'
119 builder => "_build_$name"
120 lazy => 1
121
122 NOTE: Since 0.009 we no longer set "init_arg => undef" if no "init_arg"
123 is explicitly provided. This is a change made in parallel with Moo,
124 based on a large number of people surprised that lazy also made one's
125 "init_def" undefined.
126
127 is => 'lazy', default => ...
128 Specifying "is => 'lazy'" and a default will cause the following
129 options to be set:
130
131 is => 'ro'
132 lazy => 1
133 default => ... # as provided
134
135 That is, if you specify "is => 'lazy'" and also provide a "default",
136 then we won't try to set a builder, as well.
137
138 builder => 1
139 Specifying "builder => 1" will cause the following options to be set:
140
141 builder => "_build_$name"
142
143 builder => sub { ... }
144 Passing a coderef to builder will cause that coderef to be installed in
145 the class this attribute is associated with the name you'd expect, and
146 "builder => 1" to be set.
147
148 e.g., in your class (or role),
149
150 has foo => (is => 'ro', builder => sub { 'bar!' });
151
152 ...is effectively the same as...
153
154 has foo => (is => 'ro', builder => '_build_foo');
155 sub _build_foo { 'bar!' }
156
157 The behaviour of this option in roles changed in 0.030, and the builder
158 methods will be installed in the role itself. This means you can
159 alias/exclude/etc builder methods in roles, just as you can with any
160 other method.
161
162 clearer => 1
163 Specifying "clearer => 1" will cause the following options to be set:
164
165 clearer => "clear_$name"
166
167 or, if your attribute name begins with an underscore:
168
169 clearer => "_clear$name"
170
171 (that is, an attribute named "_foo" would get "_clear_foo")
172
173 predicate => 1
174 Specifying "predicate => 1" will cause the following options to be set:
175
176 predicate => "has_$name"
177
178 or, if your attribute name begins with an underscore:
179
180 predicate => "_has$name"
181
182 (that is, an attribute named "_foo" would get "_has_foo")
183
184 init_arg => 1 / -1
185 This is a somewhat esoteric shortcut; you probably don't want to use
186 this (or even read this section).
187
188 Specifying "init_arg => 1" will cause the following options to be set:
189
190 # attribute: "name"
191 init_arg => 'name'
192
193 # or, attribute: "_name"
194 init_arg => '_name'
195
196 ...while "init_arg => -1" will cause the following options to be set:
197
198 # attribute: "name"
199 init_arg => '_name'
200
201 # or, attribute: "_name"
202 init_arg => 'name'
203
204 trigger => 1
205 Specifying "trigger => 1" will cause the attribute to be created with a
206 trigger that calls a named method in the class with the options passed
207 to the trigger. By default, the method name the trigger calls is the
208 name of the attribute prefixed with "_trigger_".
209
210 e.g., for an attribute named "foo" this would be equivalent to:
211
212 trigger => sub { shift->_trigger_foo(@_) }
213
214 For an attribute named "_foo":
215
216 trigger => sub { shift->_trigger__foo(@_) }
217
218 This naming scheme, in which the trigger is always private, is the same
219 as the builder naming scheme (just with a different prefix).
220
221 handles => { foo => sub { ... }, ... }
222 Creating a delegation with a coderef will now create a new, "custom
223 accessor" for the attribute. These coderefs will be installed and
224 called as methods on the associated class (just as readers, writers,
225 and other accessors are), and will have the attribute metaclass
226 available in $_. Anything the accessor is called with it will have
227 access to in @_, just as you'd expect of a method.
228
229 e.g., the following example creates an attribute named "bar" with a
230 standard reader accessor named "bar" and two custom accessors named
231 "foo" and "foo_too".
232
233 has bar => (
234
235 is => 'ro',
236 isa => 'Int',
237 handles => {
238
239 foo => sub {
240 my $self = shift @_;
241
242 return $_->get_value($self) + 1;
243 },
244
245 foo_too => sub {
246 my $self = shift @_;
247
248 return $self->bar + 1;
249 },
250
251 # ...as you'd expect.
252 bar => 'bar',
253 },
254 );
255
256 ...and later,
257
258 Note that in this example both foo() and foo_too() do effectively the
259 same thing: return the attribute's current value plus 1. However,
260 foo() accesses the attribute value directly through the metaclass, the
261 pros and cons of which this author leaves as an exercise for the reader
262 to determine.
263
264 You may choose to use the installed accessors to get at the attribute's
265 value, or use the direct metaclass access, your choice.
266
268 "Abusus non tollit usum."
269
270 Note that we create new, anonymous subtypes whenever the constraint or
271 coercion options are specified in such a way that the Shortcuts trait
272 (this one) is invoked. It's fully supported to use both constraint and
273 coerce options at the same time.
274
275 This facility is intended to assist with the creation of one-off type
276 constraints and coercions. It is not possible to deliberately reuse
277 the subtypes we create, and if you find yourself using a particular isa
278 / constraint / coerce option triplet in more than one place you should
279 really think about creating a type that you can reuse. MooseX::Types
280 provides the facilities to easily do this, or even a simple constant
281 definition at the package level with an anonymous type stashed away for
282 local use.
283
284 isa => sub { ... }
285 has foo => (
286 is => 'rw',
287 # $_ == $_[0] == the value to be validated
288 isa => sub { die unless $_[0] == 1 },
289 );
290
291 # passes constraint
292 $thing->foo(1);
293
294 # fails constraint
295 $thing->foo(5);
296
297 Given a coderef, create a type constraint for the attribute. This
298 constraint will fail if the coderef dies, and pass otherwise.
299
300 Astute users will note that this is the same way Moo constraints work;
301 we use MooseX::Meta::TypeConstraint::Mooish to implement the
302 constraint.
303
304 isa_instance_of => ...
305 Given a package name, this option will create an "isa" type constraint
306 that requires the value of the attribute be an instance of the class
307 (or a descendant class) given. That is,
308
309 has foo => (is => 'ro', isa_instance_of => 'SomeThing');
310
311 ...is effectively the same as:
312
313 use Moose::TypeConstraints 'class_type';
314 has foo => (
315 is => 'ro',
316 isa => class_type('SomeThing'),
317 );
318
319 ...but a touch less awkward.
320
321 isa => ..., constraint => sub { ... }
322 Specifying the constraint option with a coderef will cause a new
323 subtype constraint to be created, with the parent type being the type
324 specified in the "isa" option and the constraint being the coderef
325 supplied here.
326
327 For example, only integers greater than 10 will pass this attribute's
328 type constraint:
329
330 # value must be an integer greater than 10 to pass the constraint
331 has thinger => (
332 isa => 'Int',
333 constraint => sub { $_ > 10 },
334 # ...
335 );
336
337 Note that if you supply a constraint, you must also provide an "isa".
338
339 isa => ..., constraint => sub { ... }, coerce => 1
340 Supplying a constraint and asking for coercion will "Just Work", that
341 is, any coercions that the "isa" type has will still work.
342
343 For example, let's say that you're using the "File" type constraint
344 from MooseX::Types::Path::Class, and you want an additional constraint
345 that the file must exist:
346
347 has thinger => (
348 is => 'ro',
349 isa => File,
350 constraint => sub { !! $_->stat },
351 coerce => 1,
352 );
353
354 "thinger" will correctly coerce the string "/etc/passwd" to a
355 "Path::Class:File", and will only accept the coerced result as a value
356 if the file exists.
357
358 coerce => [ Type => sub { ...coerce... }, ... ]
359 Specifying the coerce option with a hashref will cause a new subtype to
360 be created and used (just as with the constraint option, above), with
361 the specified coercions added to the list. In the passed hashref, the
362 keys are Moose types (well, strings resolvable to Moose types), and the
363 values are coderefs that will coerce a given type to our type.
364
365 has bar => (
366 is => 'ro',
367 isa => 'Str',
368 coerce => [
369 Int => sub { "$_" },
370 Object => sub { 'An instance of ' . ref $_ },
371 ],
372 );
373
375 Sometimes attribute traits interact in surprising ways. This trait is
376 well behaved; if you have discovered any interactions with other traits
377 (good, bad, indifferent, etc), please report this
378 <https://github.com/RsrchBoy/moosex-attributeshortcuts/issues/new> so
379 that it can be worked around, fixed, or documented, as appropriate.
380
381 MooseX::SemiAffordanceAccessor
382 MooseX::SemiAffordanceAccessor changes how the "is => 'rw'" and
383 "accessor => ..." attribute options work. If our trait detects that an
384 attribute has had the MooseX::SemiAffordanceAccessor attribute trait
385 applied, then we change our behaviour to conform to its expectations:
386
387 • "is => 'rwp'"
388
389 This:
390
391 has foo => (is => 'rwp');
392 has _bar => (is => 'rwp');
393
394 ...is now effectively equivalent to:
395
396 has foo => (is => 'ro', writer => '_set_foo');
397 has _bar => (is => 'ro', writer => '_set_bar')
398
399 • "-writer_prefix" is ignored
400
401 ...as MooseX::SemiAffordanceAccessor has its own specific ideas as
402 to how writers should look.
403
405 Please see those modules/websites for more information related to this
406 module.
407
408 • Moo
409
410 • MooseX::Types
411
412 • MooseX::SemiAffordanceAccessor
413
415 Please report any bugs or feature requests on the bugtracker website
416 <https://github.com/RsrchBoy/moosex-attributeshortcuts/issues>
417
418 When submitting a bug or request, please include a test-file or a patch
419 to an existing test-file that illustrates the bug or desired feature.
420
422 Chris Weyl <cweyl@alumni.drew.edu>
423
425 • David Steinbrunner <dsteinbrunner@pobox.com>
426
427 • Graham Knop <haarg@haarg.org>
428
429 • Karen Etheridge <ether@cpan.org>
430
431 • Olaf Alders <olaf@wundersolutions.com>
432
434 This software is Copyright (c) 2017, 2015, 2014, 2013, 2012, 2011 by
435 Chris Weyl.
436
437 This is free software, licensed under:
438
439 The GNU Lesser General Public License, Version 2.1, February 1999
440
441
442
443perl v5.34.0 2021-07-22 MooseX::AttributeShortcuts(3)