1MooseX::Extended::ManuaUls:e:rOvCeornvtireiwb(u3t)ed PerMlooDsoecXu:m:eEnxttaetnidoend::Manual::Overview(3)
2
3
4

NAME

6       MooseX::Extended::Manual::Overview - Work-in-progress overview for
7       MooseX::Extended
8

VERSION

10       version 0.35
11

CONVERTING FROM MOOSE

13       For most sane codebases, converting from Moose to MooseX::Extended is
14       as simple as "s/Moose/MooseX::Extended/". We try to be backwards-
15       compatible, but some issues are glaring enough that they can't be
16       fixed. Run your tests, folks.
17
18       From there, convert your various "has" attributes to "field" or "param"
19       (and run your tests), and you can also delete the annoying
20       "__PACKAGE__->meta->make_immutable" at the end of every package (run
21       your tests, folks).
22
23       From there, if you're not using signatures, convert your methods to
24       using signatures. You'll almost definitely get test failures there as
25       many functions handle arguments poorly.
26
27       For roles, just "s/Moose::Role/MooseX::Extended::Roles/" and repeat the
28       process (and run your tests, folks).
29
30       Along the way, you can probably delete your references to
31       namespace::autoclean and friends because we provide that for you.
32

RATIONALE

34       You can skip this section if you like.
35
36       MooseX::Extended is built on years of experience hacking on Moose and
37       being the lead designer of the Corinna <https://github.com/Ovid/Cor>
38       project to bring modern OO to the Perl language. We love Moose, but
39       over the years, it's become clear that there are some problematic
40       design choices. Plus, Corinna is not yet in core as We write this
41       (though the Perl Steering Committee has accepted it), so for now, let's
42       see how far we can push the envelope.
43

BOILERPLATE

45       This:
46
47           package My::Class {
48               use MooseX::Extended;
49
50               ... your code here
51           }
52
53       Is sort of the equivalent to:
54
55           package My::Class {
56               use v5.20.0;
57               use Moose;
58               use MooseX::StrictConstructor;
59               use feature 'signatures';
60               no warnings 'experimental::signatures';
61               use namespace::autoclean;
62               use Carp;
63               use mro 'c3';
64
65               ... your code here
66
67               __PACKAGE__->meta->make_immutable;
68           }
69
70           1;
71
72       We get tired of typing a lot of boilerplate, so "MooseX::Extended" does
73       away with it.
74

CONSTRUCTOR

76       The constructor behavior for Moose could use some love.
77

What's allowed in the constructor?

79       We've regularly face the following problem:
80
81           package Some::Class;
82
83           use Moose;
84
85           has name     => (...);
86           has uuid     => (...);
87           has id       => (...);
88           has backlog  => (...);
89           has auth     => (...);
90           has username => (...);
91           has password => (...);
92           has cache    => (...);
93           has this     => (...);
94           has that     => (...);
95
96       Which of those should be passed to the constructor and which should
97       not? Just because you can pass something to the constructor doesn't
98       mean you should. Unfortunately, Moose defaults to "opt-out" rather than
99       "opt-in" for constructor arguments. This makes it really easy to build
100       objects, but means that you can pass things to the constructor and it
101       won't always work the way you want it to.
102
103       There's an arcane "init_arg => undef" pair to pass to each to say "this
104       cannot be set via the constructor," but many developers are either
105       unaware of this is simply forget about it. "MooseX::Extended" solves
106       with by separating "has" into "param" (allowed in the constructor, but
107       you can also use "default" or "builder") and "field", which is
108       forbidden in the constructor.  We can rewrite the above as this:
109
110           package Some::Class;
111
112           use MooseX::Extended;
113
114           param name     => (...);
115           param backlog  => (...);
116           param auth     => (...);
117           param username => (...);
118           param password => (...);
119
120           field cache    => (...);
121           field this     => (...);
122           field that     => (...);
123           field uuid     => (...);
124           field id       => (...);
125
126       And now you can instantly see what is and is not intended to be allowed
127       in the constructor.
128
129       Note that in our experience, "field" attributes often depend on "param"
130       attributes, so they're lazy by default (a nice performance win if you
131       don't call them), but you can still pass "lazy => 0" to override this.
132
133   Unknown arguments to the constructor
134       Here's another fun bug:
135
136           my $object = Some::Class->new(
137               name   => $name,
138               seriel => $serial,
139           );
140
141           # later in your code
142
143           if ( $object->serial ) {
144               # unreachable code
145           }
146
147       This is because Moose, by default, ignores any unknown arguments to the
148       constructor and in the above example, we misspelled "serial" as
149       "seriel".
150
151       "MooseX::Extended" applies "MooseX::StrictConstructor" to your class so
152       you never have to face this problem again.
153
154       WARNING: Be careful when using this in existing class hierarchies.
155       While "MooseX::Extended" is compatible with Moose (Moose classes can
156       always use "MooseX::Extended" classes and roles), the reverse isn't
157       always true. We've found, for example, that trying to use
158       "MooseX::StrictConstructor" with DBIx::Class does not work.
159
160   Method Resolution Order (mro)
161       If you don't use multiple inheritance, you won't need to worry about
162       this.  However, by now, it's generally agreed that the C3 method
163       resolution order (breadth-first, for Perl) is superior to the depth-
164       first default. You can read about the diamond inheritance problem
165       <https://en.wikipedia.org/wiki/Multiple_inheritance> if you'd like to
166       learn more.
167
168       Rather than remembering to include "use mro 'c3'" in your code,
169       MooseX::Extended does it for you.
170
171       If you have existing code that breaks under this, you should
172       investigate carefully. You probably have a bug in your code.
173
174   Making Your Class Immutable
175       It's recommended that you end your Moose classes with this:
176
177           __PACKAGE__->meta->make_immutable;
178
179       That causes a lot of things to happen under the hood. It makes your
180       class much harder to debug as you're in a twisty maze of "eval"ed
181       methods, but it makes your class run much faster. The performance gain
182       is often significant and you almost always want to use this, but it's
183       easy to forget, so we add it for you.
184
185       To do this, we use the "after_runtime" function from
186       "B::Hooks::AtRuntime".  However, that doesn't work under the debugger.
187       So if you're running under the debugger, we disable this. Please keep
188       that in mind. As a convenience, when running under the debugger, we
189       issue a series of warnings for every class that is impacted. For a
190       large codebase, that could be a considerable number of classes if they
191       use "MooseX::Extended":
192
193           We are running under the debugger. My::Name is not immutable
194           We are running under the debugger. My::Product is not immutable
195           We are running under the debugger. My::Order is not immutable
196

IMMUTABLE OBJECTS

198       The subject of immutable objects has been done to death. If We set the
199       value of an attribute but another section of the code has already
200       fetched that value, you might have two sections of the code operating
201       under completely different assumptions of what they're allowed to do.
202       So by default, all attributes are "read-only":
203
204           param name  => ( isa => NonEmptyStr );
205           field cache => ( isa => HashRef );
206
207       You can change this if you need to:
208
209           param name  => ( is => 'rw', isa => NonEmptyStr );
210           field cache => ( is => 'rw', isa => HashRef );
211
212       However, what's going on with that "cache" attribute? It returns a
213       reference.  If your code mutates that reference, every bit of code
214       holding a reference to that object silently has its state changed. So
215       we fixed that, too:
216
217           field cache => ( isa => HashRef, clone => 1 );
218
219       Now, every time you get or set that data, it's cloned, ensuring that
220       you can do this:
221
222           # assumes that the original ->cache has a SeKreT key.
223           my $hash1 = $object->cache;
224           delete $hash1->{SeKreT};
225           my $hash2 = $object->cache;
226           my $SeKreT = $hash2->{SeKreT}; # you get the original value
227
228       Internally, we use Storable's "dclone" method for this. Be aware that
229       many things cannot be safely cloned (e.g., database handles).
230
231       The "clone => 1" feature is safest when you don't have objects that
232       you're trying to clone. As a result, this feature is EXPERIMENTAL.
233

ATTRIBUTES

235       By now, you know that "is => 'ro'" is the default for all "param" and
236       "field" attributes. You can still use "has", but you will still need to
237       use "is => ..." with that:
238
239           has name => ( is => 'ro, ... );
240
241       However, I hate typing out something like "predicate => 'is_assigned'".
242       Or should it be "predicate => 'has_assigned'"? For a variety of
243       attributes, we've made this simpler.
244
245       When using "field" or "param", we have some attribute shortcuts:
246
247           param name => (
248               isa       => NonEmptyStr,
249               writer    => 1,   # set_name
250               reader    => 1,   # get_name
251               predicate => 1,   # has_name
252               clearer   => 1,   # clear_name
253               builder   => 1,   # _build_name
254           );
255
256           sub _build_name ($self) {
257               ...
258           }
259
260       These can also be used when you pass an array reference to the
261       function:
262
263           package Point {
264               use MooseX::Extended types => 'Int';
265
266               param [ 'x', 'y' ] => (
267                   isa     => Int,
268                   clearer => 1,     # clear_x and clear_y available
269                   default => 0,
270               ) :;
271           }
272
273       Note that these are shortcuts and they make attributes easier to write
274       and more consistent.  However, you can still use full names:
275
276           field authz_delegate => (
277               builder => '_build_my_darned_authz_delegate',
278           );
279
280   "writer"
281       If an attribute has "writer" is set to 1 (the number one), a method
282       named "set_$attribute_name" is created.
283
284       This:
285
286           param title => (
287               isa       => Undef | NonEmptyStr,
288               default   => undef,
289               writer => 1,
290           );
291
292       Is the same as this:
293
294           has title => (
295               is      => 'rw',                  # we change this from 'ro'
296               isa     => Undef | NonEmptyStr,
297               default => undef,
298               writer  => 'set_title',
299           );
300
301   "reader"
302       By default, the reader (accessor) for the attribute is the same as the
303       name.  You can always change this:
304
305           has payload => ( is => 'ro', reader => 'the_payload' );
306
307       However, if you want to change the reader name
308
309       If an attribute has "reader" is set to 1 (the number one), a method
310       named "get_$attribute_name" is created.
311
312       This:
313
314           param title => (
315               isa       => Undef | NonEmptyStr,
316               default   => undef,
317               reader => 1,
318           );
319
320       Is the same as this:
321
322           has title => (
323               is      => 'rw',                  # we change this from 'ro'
324               isa     => Undef | NonEmptyStr,
325               default => undef,
326               reader  => 'get_title',
327           );
328
329   "predicate"
330       If an attribute has "predicate" is set to 1 (the number one), a method
331       named "has_$attribute_name" is created.
332
333       This:
334
335           param title => (
336               isa       => Undef | NonEmptyStr,
337               default   => undef,
338               predicate => 1,
339           );
340
341       Is the same as this:
342
343           has title => (
344               is        => 'ro',
345               isa       => Undef | NonEmptyStr,
346               default   => undef,
347               predicate => 'has_title',
348           );
349
350   "clearer"
351       If an attribute has "clearer" is set to 1 (the number one), a method
352       named "clear_$attribute_name" is created.
353
354       This:
355
356           param title => (
357               isa     => Undef | NonEmptyStr,
358               default => undef,
359               clearer => 1,
360           );
361
362       Is the same as this:
363
364           has title => (
365               is      => 'ro',
366               isa     => Undef | NonEmptyStr,
367               default => undef,
368               clearer => 'clear_title',
369           );
370
371   "builder"
372       If an attribute has "builder" is set to 1 (the number one), a method
373       named "_build_$attribute_name".
374
375       This:
376
377           param title => (
378               isa     =>  NonEmptyStr,
379               builder => 1,
380           );
381
382       Is the same as this:
383
384           has title => (
385               is      => 'ro',
386               isa     => NonEmptyStr,
387               builder => '_build_title',
388           );
389
390       Obviously, a "private" attribute, such as "_auth_token" would get a
391       build named "_build__auth_token" (note the two underscores between
392       "build" and "auth_token").
393

AUTHOR

395       Curtis "Ovid" Poe <curtis.poe@gmail.com>
396
398       This software is Copyright (c) 2022 by Curtis "Ovid" Poe.
399
400       This is free software, licensed under:
401
402         The Artistic License 2.0 (GPL Compatible)
403
404
405
406perl v5.38.0                      2023-06-M2o6oseX::Extended::Manual::Overview(3)
Impressum