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