From: Stevan Little Date: Sun, 3 Sep 2006 04:56:57 +0000 (+0000) Subject: FAQ and WTF added to cookbook X-Git-Tag: 0_14~15 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=e67a0fca94990eac69dc5e8f8f189162f760c7e6;p=gitmo%2FMoose.git FAQ and WTF added to cookbook --- diff --git a/lib/Moose.pm b/lib/Moose.pm index 6fc288f..89b5bab 100644 --- a/lib/Moose.pm +++ b/lib/Moose.pm @@ -588,6 +588,8 @@ ideas/feature-requests/encouragement =item The #moose channel on irc.perl.org +=item The Moose mailing list - moose@perl.org + =item L =item L diff --git a/lib/Moose/Cookbook/FAQ.pod b/lib/Moose/Cookbook/FAQ.pod new file mode 100644 index 0000000..51218bf --- /dev/null +++ b/lib/Moose/Cookbook/FAQ.pod @@ -0,0 +1,234 @@ + +=pod + +=head1 NAME + +Moose::Cookbook::FAQ - Frequenty asked questions about Moose + +=head1 FREQUENTLY ASKED QUESTIONS + +=head2 Constructors + +=head3 How do I write custom constructors with Moose? + +Ideally, you should never write your own C method, and should +use Moose's other features to handle your specific object construction +needs. Here are a few scenarios, and the Moose way to solve them; + +If you need to call initializtion code post instance construction, +then use the C method. This feature is taken directly from +Perl 6. Every C method in your inheritence chain is called +(in the correct order) immediately after the instance is constructed. +This allows you to ensure that all your superclasses are initialized +properly as well. This is the best approach to take (when possible) +because it makes subclassing your class much easier. + +If you need to affect the constructor's parameters prior to the +instance actually being constructed, you have a number of options. + +First, there are I (See the L +for a complete example and explaination of coercions). With +coercions it is possible to morph argument values into the correct +expected types. This approach is the most flexible and robust, but +does have a slightly higher learning curve. + +Second, using an C method modifier on C can be an +effective way to affect the contents of C<@_> prior to letting +Moose deal with it. This carries with it the extra burden for +your subclasses, in that they have to be sure to explicitly +call your C and/or work around your C to get to the +version from L. + +The last approach is to use the standard Perl technique of calling +the C within your own custom version of C. This +of course brings with it all the issues of the C solution +along with any issues C might add as well. + +In short, try to use C and coercions, they are your best +bets. + +=head3 How do I make non-Moose constuctors work with Moose? + +Moose provides it's own constructor, but it does it by making all +Moose-based classes inherit from L. When inheriting +from a non-Moose class, the inheritence chain to L +is broken. The simplest way to fix this is to simply explicitly +inherit from L yourself. However, this does not +always fix the issue of a constructor. Here is a basic example of +how this can be worked around: + + package My::HTML::Template; + use Moose; + + # explict inheritence + extends 'HTML::Template', 'Moose::Object'; + + # explicit constructor + sub new { + my $class = shift; + # call HTML::Template's constructor + my $obj = $class->SUPER::new(@_); + return $class->meta->new_object( + # pass in the constructed object + # using the special key __INSTANCE__ + __INSTANCE__ => $obj, @_ + ); + } + +Of course this only works if both your Moose class, and the +inherited non-Moose class use the same instance type (typically +HASH refs). + +Other techniques can be used as well, such as creating the object +using C, but calling the inherited non-Moose +class's initializtion methods (if available). + +It is also entirely possible to just rely on HASH autovivification +to create the slot's needed for Moose based attributes. Although +this does somewhat restrict use of construction time attribute +features. + +In short, there are several ways to go about this, it is best to +evaluate each case based on the class you wish to extend, and the +features you wish to employ. As always, both IRC and the mailing +list are great ways to get help finding the best approach. + +=head2 Accessors + +=head3 How do I tell Moose to use get/set accessors? + +The easiest way to accomplish this is to use the C and +C attribute options. Here is some example code: + + has 'bar' => ( + isa => 'Baz', + reader => 'get_bar', + writer => 'set_bar', + ); + +Moose will still take advantage of type constraints, triggers, etc. +when creating these methods. + +If you do not like this much typing, and wish it to be a default for +your class. Please see L, and more specifically the +L. This will allow you to write this: + + has 'bar' => ( + isa => 'Baz', + is => 'rw', + ); + +And have Moose create C and C instead of the usual +C. + +NOTE: This B be set globally in Moose, as this would break +other classes which are built with Moose. + +=head3 How can I get Moose to inflate/deflate values in the accessor? + +Well, the first question to ask is if you actually need both inflate +and deflate. + +If you only need to inflate, then I suggest using coercions. Here is +some basic sample code for inflating a L object. + + subtype 'DateTime' + => as 'Object' + => where { $_->isa('DateTime') }; + + coerce 'DateTime' + => from 'Str' + => via { DateTime::Format::MySQL->parse_datetime($_) }; + + has 'timestamp' => (is => 'rw', isa => 'DateTime', coerce => 1); + +This creates a custom subtype for L objects, then attaches +a coercion to that subtype. The C attribute is then told +to expect a C type, and to try and coerce it. When a C +type is given to the C accessor, it will attempt to +coerce the value into a C object using the code in found +in the C block. + +For a more detailed and complete example of coercions, see the +L. + +If you need to deflate your attribute, the current best practice is to +add an C modifier to your accessor. Here is some example code: + + # a timestamp which stores as + # seconds from the epoch + has 'timestamp' => (is => 'rw', isa => 'Int'); + + around 'timestamp' => sub { + my $next = shift; + my ($self, $timestamp) = @_; + # assume we get a DateTime object ... + $next->($self, $timestamp->epoch); + }; + +It is also possible to do deflation using coercion, but this tends +to get quite complex and require many subtypes. An example of this +is outside the scope of this document, ask on #moose or send a mail +to the list. + +Still another option is to write a custom attribute metaclass, which +is also outside the scope of this document, but I would be happy to +explain it on #moose or the mailing list. + +=head2 Method Modfiers + +=head3 How can I affect the values in C<@_> using C? + +You can't actually, C only runs before the main method, +and it cannot easily affect the execution of it. What you want is +an C method. + +=head3 Can I use C to stop execution of a method? + +Yes, but only if you throw an exception. If this is too drastic a +measure then I suggest using C instead. The C method +modifier is the only modifier which can actually stop the execution +of the main method. Here is an example: + + around 'baz' => sub { + my $next = shift; + my ($self, %options) = @_; + if ($options{bar} eq 'foo') { + $next->($self, %options); + } + else { + return 'bar'; + } + }; + +By choosing not to call the C<$next> method, you can stop the +execution of the main method. + +=head2 Type Constraints + +=head3 How can I have a custom error message for a type constraint? + +Use the C option when building the subtype. Like so: + + subtype 'NaturalLessThanTen' + => as 'Natural' + => where { $_ < 10 } + => message { "This number ($_) is not less than ten!" }; + +This will be called when a value fails to pass the C +constraint check. + +=head1 AUTHOR + +Stevan Little Estevan@iinteractive.comE + +=head1 COPYRIGHT AND LICENSE + +Copyright 2006 by Infinity Interactive, Inc. + +L + +This library is free software; you can redistribute it and/or modify +it under the same terms as Perl itself. + +=cut \ No newline at end of file diff --git a/lib/Moose/Cookbook/WTF.pod b/lib/Moose/Cookbook/WTF.pod new file mode 100644 index 0000000..0c0ccf2 --- /dev/null +++ b/lib/Moose/Cookbook/WTF.pod @@ -0,0 +1,82 @@ + +=pod + +=head1 NAME + +Moose::Cookbook::WTF - For when things go wrong with Moose + +=head1 COMMON PROBLEMS + +=head2 Constructors + +=head2 Accessors + +=head3 I created an attribute, where are my accessors? + +Accessors are B created implicitly, you B ask Moose +to create them for you. My guess is that you have this: + + has 'foo' => (isa => 'Bar'); + +when what you really want to say is: + + has 'foo' => (isa => 'Bar', is => 'rw'); + +The reason this is so, is because it is a perfectly valid use +case to I have an accessor. The simplest one is that you +want to write your own. If Moose created on automatically, then +because of the order in which classes are constructed, Moose +would overwrite your custom accessor. You wouldn't want that +would you? + +=head2 Method Modfiers + +=head3 How come I can't change C<@_> in a C modifier? + +The C modifier simply is called I the main method. +Its return values are simply ignored, and are B passed onto +the main method body. + +There are a number of reasons for this, but those arguments are +too lengthy for this document. Instead, I suggest using an C +modifier instead. Here is some sample code: + + around 'foo' => sub { + my $next = shift; + my ($self, @args) = @_; + # do something silly here to @args + $next->($self, reverse(@args)); + }; + +=head3 How come I can't see return values in an C modifier? + +As with the C modifier, the C modifier is simply +called I the main method. It is passed the original contents +of C<@_> and B the return values of the main method. + +Again, the arguments are too lengthy as to why this has to be. And +as with C I recommend using an C modifier instead. +Here is some sample code: + + around 'foo' => sub { + my $next = shift; + my ($self, @args) = @_; + my @rv = $next->($self, @args); + # do something silly with the return values + return reverse @rv; + }; + +=head1 AUTHOR + +Stevan Little Estevan@iinteractive.comE + +=head1 COPYRIGHT AND LICENSE + +Copyright 2006 by Infinity Interactive, Inc. + +L + +This library is free software; you can redistribute it and/or modify +it under the same terms as Perl itself. + +=cut \ No newline at end of file diff --git a/t/202_example_Moose_POOP.t b/t/202_example_Moose_POOP.t index 4c6e3cc..6e87c47 100644 --- a/t/202_example_Moose_POOP.t +++ b/t/202_example_Moose_POOP.t @@ -114,7 +114,7 @@ BEGIN { } sub weaken_slot_value { - confess "Not sure how well DBM::Deep plays with weak refs, Rob says 'Writer a test'"; + confess "Not sure how well DBM::Deep plays with weak refs, Rob says 'Write a test'"; } sub inline_slot_access {