Some notes and changed examples for using Moose in MyApp. There is more stuff to...
[catagits/Catalyst-Manual.git] / lib / Catalyst / Manual / ExtendingCatalyst.pod
index 2602cef..dc88b52 100644 (file)
@@ -46,11 +46,17 @@ forward to L</Namespaces>.
 
 =item Use the C<CatalystX::*> namespace if you can!
 
-Excluding plugins and of course your C<MyApp> code. B<Mind the X!>
+If your extension isn't a Model, View, Controller, Plugin, Engine,
+or Log, it's best to leave it out of the C<Catalyst::> namespace.
+Use <CatalystX::> instead.
 
 =item Don't make it a plugin unless you have to!
 
-A plugin should be careful as it declares in global namespace.
+A plugin should be careful since it's overriding Catalyst internals.
+If your plugin doesn't really need to muck with the internals, make it a
+base Controller or Model.
+
+If you need to hook (but not alter) the internals, then make it a L<Moose::Role>
 
 =item There's a community. Use it!
 
@@ -89,12 +95,37 @@ putting it in your C<MyApp::*> namespace. Just don't put it in
 C<Model>, C<Controller> or C<View>, because that would make Catalyst
 try to load them as components.
 
+Writing a generic component that only works with Catalyst is wasteful
+of your time.  Try writing a plain perl module, and then a small bit
+of glue that integrates it with Catalyst.  See
+L<Catalyst::Model::DBIC::Schema|Catalyst::Model::DBIC::Schema> for a
+module that takes the approach.  The advantage here is that your
+"Catalyst" DBIC schema works perfectly outside of Catalyst, making
+testing (and command-line scripts) a breeze.  The actual Catalyst
+Model is just a few lines of glue that makes working with the schema
+convenient.
+
+If you want the thinnest interface possible, take a look at
+L<Catalyst::Model::Adaptor|Catalyst::Model::Adaptor>.
+
+=head2 Using Moose roles to apply method modifiers
+
+Rather than having a complex set of base classes which you have to mixin
+via multiple inheritence, if your functionality is well structured, then
+it's possible to use the composability of L<Moose> roles, and method modifiers
+to hook onto to provide functionality. 
+
+For a simple example of this, see L<CatalystX::REPL>.
+
+B<Note:> Currently, controllers with attributes will not function correctly
+in conjunction with Moose roles.
+
 =head2 Inheritance and overriding methods
 
 While Catalyst itself is still based on L<NEXT> (for multiple
 inheritance), extension developers are encouraged to use L<Class::C3>,
-which is what Catalyst will be switching to in some point in the
-future.
+via L<MRO::Compat>, which is what Catalyst will be switching to in the 
+5.80 release.
 
 When overriding a method, keep in mind that some day additionally
 arguments may be provided to the method, if the last parameter is not
@@ -102,7 +133,7 @@ a flat list. It is thus better to override a method by shifting the
 invocant off of C<@_> and assign the rest of the used arguments, so
 you can pass your complete arguments to the original method via C<@_>:
 
-  use Class::C3; ...
+  use MRO::Compat; ...
 
   sub foo { my $self = shift;
             my ($bar, $baz) = @_; # ...  return
@@ -126,6 +157,10 @@ module.  It also shows that you care for your users. If you would like
 your module to become a recommended addition, these things will prove
 invaluable.
 
+If you're just getting started, try using
+L<CatalystX::Starter|CatalystX::Starter> to generate some example
+tests for your module.
+
 =head2 Maintenance
 
 In planning to release a module to the community (Catalyst or CPAN and
@@ -256,9 +291,11 @@ method. The execute method of the action will naturally call the
 methods code. You can surround this by overriding the method in a
 subclass:
 
-  package Catalyst::Action::MyFoo; use strict;
+  package Catalyst::Action::MyFoo; 
+  use strict;
 
-  use Class::C3; use base 'Catalyst::Action';
+  use MRO::Compat; 
+  use base 'Catalyst::Action';
 
   sub execute {
       my $self = shift;
@@ -270,8 +307,10 @@ subclass:
   }
   1;
 
-We are using L<Class::C3> to re-dispatch to the original C<execute> method
-in the L<Catalyst::Action> class.
+We are using L<MRO::Compat> to ensure that you have the next::method
+call, from L<Class::C3> (in older perls), or natively (if you are using 
+perl 5.10) to re-dispatch to the original C<execute> method in the 
+L<Catalyst::Action> class.
 
 The Catalyst dispatcher handles an incoming request and, depending
 upon the dispatch type, will call the appropriate target or chain. 
@@ -283,9 +322,10 @@ the action will match and add new matching criteria.
 For example, the action class below will make the action only match on
 Mondays:
 
-  package Catalyst::Action::OnlyMondays; use strict;
+  package Catalyst::Action::OnlyMondays; 
+  use strict;
 
-  use Class::C3;
+  use MRO::Compat;
   use base 'Catalyst::Action';
 
   sub match {
@@ -502,9 +542,13 @@ object via L<Catalyst::Component/"ACCEPT_CONTEXT($c, @args)">.
 
 When is a plugin suited to your task? Your code needs to be a
 plugin to act upon or alter specific parts of Catalyst's request
-lifecycle. If your functionality needs to wrap some C<prepare_*> or
+lifecycle. If your functionality needs to change some C<prepare_*> or
 C<finalize_*> stages, you won't get around a plugin.
 
+Note, if you just want to hook into such a stage, and run code before,
+or after it, then it is recommended that you use L<Moose>s method modifiers
+to do this.
+
 Another valid target for a plugin architecture are things that
 B<really> have to be globally available, like sessions or
 authentication.
@@ -520,27 +564,45 @@ application's inheritance list, above Catalyst itself. You can by this
 alter Catalyst's request lifecycle behaviour. Every method you
 declare, every import in your package will be available as method on
 the application and the context object. As an example, let's say you
-want Catalyst to warn you every time uri_for returned an undefined
-value, for example because you specified the wrong number of captures
-for the targeted action chain. You could do this with this simple
+want Catalyst to warn you every time uri_for was called without an action
+object as the first parameter, for example to test that all your chained
+uris are generated from actions (a recommended best practice).
+You could do this with this simple
 implementation (excuse the lame class name, it's just an example):
 
   package Catalyst::Plugin::UriforUndefWarning;
   use strict;
-  use Class::C3;
+  use Scalar::Util qw/blessed/;
+  use MRO::Compat;
 
   sub uri_for {
       my $c = shift;
       my $uri = $c->next::method(@_);
-      $c->log->warn( 'uri_for returned undef for:', join(', ', @_), );
+      $c->log->warn( 'uri_for with non action: ', join(', ', @_), )
+        if (!blessed($_[0]) || !$_[0]->isa('Catalyst::Action'));
       return $uri;
   }
 
   1;
 
 This would override Catalyst's C<uri_for> method and emit a C<warn>
-log entry containing the arguments that led to the undefined return
-value.
+log entry containing the arguments to uri_for.
+
+Please note this is not a practical example, as string URLs are fine for
+static content etc.
+
+A simple example like this is actually better as a L<Moose> role, for example:
+
+  package CatalystX::UriforUndefWarning;
+  use Moose::Role;
+  use namespace::clean -except => 'meta';
+
+  after 'uri_for' => sub {
+    my ($c, $arg) = @_;
+    $c->log->warn( 'uri_for with non action: ', join(', ', @_), )
+      if (!blessed($_[0]) || !$_[0]->isa('Catalyst::Action'));
+    return $uri;
+  }; 
 
 =head2 Factory components with COMPONENT()
 
@@ -552,8 +614,9 @@ C<config>uration with the application wide overrides and call the
 class' C<new> method to return the component object.
 
 You can override this method and do and return whatever you want.
-However, you should use L<Class::C3> to forward to the original
-C<COMPONENT> method to merge the configuration of your component.
+However, you should use L<Class::C3> (via L<MRO::Compat>) to forward 
+to the original C<COMPONENT> method to merge the configuration of 
+your component.
 
 Here is a stub C<COMPONENT> method:
 
@@ -561,7 +624,7 @@ Here is a stub C<COMPONENT> method:
   use strict;
   use base 'Catalyst::Component';
 
-  use Class::C3;
+  use MRO::Compat;
 
   sub COMPONENT {
       my $class = shift;
@@ -589,7 +652,9 @@ L<Catalyst>, L<Catalyst::Manual::Actions>, L<Catalyst::Component>
 
 =head1 AUTHOR
 
-Robert Sedlacek C<rs@474.at>
+Robert Sedlacek C<< <rs@474.at> >>
+
+Jonathan Rockway C<< <jrockway@cpan.org> >>
 
 =head1 LICENSE AND COPYRIGHT