make it less easy to want moose stringy types
[catagits/Catalyst-Runtime.git] / lib / Catalyst / RouteMatching.pod
index fb86ca0..e91b560 100644 (file)
@@ -23,7 +23,7 @@ is a simple example:
 
     extends 'Catalyst::Controller';
 
-    sub find :Path('') Args(Int) {
+    sub find :Path('') Args('Int') {
       my ($self, $c, $int) = @_;
     }
 
@@ -31,26 +31,35 @@ is a simple example:
 
 In this case the incoming request "http://localhost:/user/100" would match the action
 C<find> but "http://localhost:/user/not_a_number" would not. You may find declaring
-constraints in this manner aids with debuggin, automatic generation of documentation
-and reduces the amount of manual checking you might need to do in your actions.  For
-example if the argument in the example action was going to be used to lookup a row
-in a database, if the matching field expected an integer a string might cause a database
+constraints in this manner aids with debugging, automatic generation of documentation
+and reducing the amount of manual checking you might need to do in your actions.  For
+example if the argument in the given action was going to be used to lookup a row
+in a database, if the matching field expected an integer, a string might cause a database
 exception, prompting you to add additional checking of the argument prior to using it.
+In general it is hoped this feature can lead to reduced validation boilerplate and more
+easily understood and declarative actions.
 
 More than one argument may be added by comma separating your type constraint names, for
 example:
 
+    use Types::Standard qw/Int Str/;
+
     sub find :Path('') Args(Int,Int,Str) {
       my ($self, $c, $int1, $int2, $str) = @_;
     }
 
-Would require three arguments, an integer, integer and a string.
+Would require three arguments, an integer, integer and a string.  Note in this example we
+constrained the args using imported types via L<Types::Standard>.  Although you may use
+stringy Moose types, we recommend imported types since this is less ambiguous to your readers.
+If you want to use Moose stringy types. you must quote them (either "Int" or 'Int' is fine).
+
+Conversely, you should not quote types that are imported!
 
 =head3 Using type constraints in a controller
 
 By default L<Catalyst> allows all the standard, built-in, named type constraints that come
 bundled with L<Moose>.  However it is trivial to create your own Type constraint libraries
-and export them to controller that wish to use them.  We recommend using L<Type::Tiny> or
+and export them to a controller that wishes to use them.  We recommend using L<Type::Tiny> or
 L<MooseX::Types> for this.  Here is an example using some extended type constraints via
 the L<Types::Standard> library that is packaged with L<Type::Tiny>:
 
@@ -58,7 +67,7 @@ the L<Types::Standard> library that is packaged with L<Type::Tiny>:
 
     use Moose;
     use MooseX::MethodAttributes;
-    use Types::Standard qw/StrMatch/;
+    use Types::Standard qw/StrMatch Int/;
     
     extends 'Catalyst::Controller';
 
@@ -98,18 +107,22 @@ action NEVER gets hit.  You would need to reverse the order:
     sub an_int :Path(user) Args(Int) {
     }
 
-Now requests that match this path would first hit the 'an_int' action, and then the 'an_any'
-action, which it likely what you are looking for!
+Now requests that match this path would first hit the 'an_int' action and will check to see if
+the argument is an integer.  If it is, then the action will execute, otherwise it will pass and
+the dispatcher will check the next matching action (in this case we fall thru to the 'an_any'
+action).
 
 =head3 Type Constraints and Chained Actions
 
 Using type constraints in Chained actions works the same as it does for Path and Local or Global
-actions.  The only difference is that you maybe declare type constraints on CaptureArgs as
+actions.  The only difference is that you may declare type constraints on CaptureArgs as
 well as Args.  For Example:
 
+  use Types::Standard qw/Int Tuple/;
+  
   sub chain_base :Chained(/) CaptureArgs(1) { }
 
-    sub any_priority_chain :Chained(chain_base) PathPart('') Args(1) {  }
+    sub any_priority_chain :GET Chained(chain_base) PathPart('') Args(1) {  }
 
     sub int_priority_chain :Chained(chain_base) PathPart('') Args(Int) {  }
 
@@ -117,37 +130,69 @@ well as Args.  For Example:
 
       sub any_priority_link_any :Chained(link_any) PathPart('') Args(1) {  }
 
-      sub int_priority_link_any :Chained(link_any) PathPart('') Args(Int) { }
+      sub int_priority_link_any :Chained(link_any) PathPart('') Args(Int) {  }
     
     sub link_int :Chained(chain_base) PathPart('') CaptureArgs(Int) { }
 
-      sub any_priority_link :Chained(link_int) PathPart('') Args(1) { }
+      sub any_priority_link :Chained(link_int) PathPart('') Args(1) {  }
+
+      sub int_priority_link :Chained(link_int) PathPart('') Args(Int) {  }
+
+    sub link_int_int :Chained(chain_base) PathPart('') CaptureArgs(Int,Int) { }
+
+      sub any_priority_link2 :Chained(link_int_int) PathPart('') Args(1) {  }
 
-      sub int_priority_link :Chained(link_int) PathPart('') Args(Int) { }
+      sub int_priority_link2 :Chained(link_int_int) PathPart('') Args(Int) {  }
+
+    sub link_tuple :Chained(chain_base) PathPart('') CaptureArgs(Tuple[Int,Int,Int]) { }
+
+      sub any_priority_link3 :Chained(link_tuple) PathPart('') Args(1) {  }
+
+      sub int_priority_link3 :Chained(link_tuple) PathPart('') Args(Int) {  }
 
 These chained actions migth create match tables like the following:
 
     [debug] Loaded Chained actions:
-    .----------------------------------------------+----------------------------------------------.
-    | Path Spec                                    | Private                                      |
-    +----------------------------------------------+----------------------------------------------+
-    | /chain_base/*/*                              | /chain_base (1)                              |
-    |                                              | => /any_priority_chain                       |
-    | /chain_base/*/*/*                            | /chain_base (1)                              |
-    |                                              | -> /link_int (1)                             |
-    |                                              | => /any_priority_link                        |
-    | /chain_base/*/*/*                            | /chain_base (1)                              |
-    |                                              | -> /link_any (1)                             |
-    |                                              | => /any_priority_link_any                    |
-    | /chain_base/*/*                              | /chain_base (1)                              |
-    |                                              | => /int_priority_chain                       |
-    | /chain_base/*/*/*                            | /chain_base (1)                              |
-    |                                              | -> /link_int (1)                             |
-    |                                              | => /int_priority_link                        |
-    | /chain_base/*/*/*                            | /chain_base (1)                              |
-    |                                              | -> /link_any (1)                             |
-    |                                              | => /int_priority_link_any                    |
-    '----------------------------------------------+----------------------------------------------'
+    .-------------------------------------+--------------------------------------.
+    | Path Spec                           | Private                              |
+    +-------------------------------------+--------------------------------------+
+    | /chain_base/*/*                     | /chain_base (1)                      |
+    |                                     | => GET /any_priority_chain (1)       |
+    | /chain_base/*/*/*                   | /chain_base (1)                      |
+    |                                     | -> /link_int (Int)                   |
+    |                                     | => /any_priority_link (1)            |
+    | /chain_base/*/*/*/*                 | /chain_base (1)                      |
+    |                                     | -> /link_int_int (Int,Int)           |
+    |                                     | => /any_priority_link2 (1)           |
+    | /chain_base/*/*/*/*/*               | /chain_base (1)                      |
+    |                                     | -> /link_tuple (Tuple[Int,Int,Int])  |
+    |                                     | => /any_priority_link3 (1)           |
+    | /chain_base/*/*/*                   | /chain_base (1)                      |
+    |                                     | -> /link_any (1)                     |
+    |                                     | => /any_priority_link_any (1)        |
+    | /chain_base/*/*/*/*/*/*             | /chain_base (1)                      |
+    |                                     | -> /link_tuple (Tuple[Int,Int,Int])  |
+    |                                     | -> /link2_int (UserId)               |
+    |                                     | => GET /finally (Int)                |
+    | /chain_base/*/*/*/*/*/...           | /chain_base (1)                      |
+    |                                     | -> /link_tuple (Tuple[Int,Int,Int])  |
+    |                                     | -> /link2_int (UserId)               |
+    |                                     | => GET /finally2 (...)               |
+    | /chain_base/*/*                     | /chain_base (1)                      |
+    |                                     | => /int_priority_chain (Int)         |
+    | /chain_base/*/*/*                   | /chain_base (1)                      |
+    |                                     | -> /link_int (Int)                   |
+    |                                     | => /int_priority_link (Int)          |
+    | /chain_base/*/*/*/*                 | /chain_base (1)                      |
+    |                                     | -> /link_int_int (Int,Int)           |
+    |                                     | => /int_priority_link2 (Int)         |
+    | /chain_base/*/*/*/*/*               | /chain_base (1)                      |
+    |                                     | -> /link_tuple (Tuple[Int,Int,Int])  |
+    |                                     | => /int_priority_link3 (Int)         |
+    | /chain_base/*/*/*                   | /chain_base (1)                      |
+    |                                     | -> /link_any (1)                     |
+    |                                     | => /int_priority_link_any (Int)      |
+    '-------------------------------------+--------------------------------------'
 
 As you can see the same general path could be matched by various action chains.  In this case
 the rule described in the previous section should be followed, which is that L<Catalyst>
@@ -161,6 +206,8 @@ Although this reverse order checking may seen counter intuitive it does have the
 when inheriting controllers any new actions added would take check precedence over those in your
 parent controller or consumed role.
 
+Please note that your declared type constraint names will now appear in the debug console.
+
 =head1 Conclusion
 
     TBD