NAME¶
Jifty::Manual::Continuations - There And Back Again
DESCRIPTION¶
Continuations are a powerful concept in computer science -- in a nutshell, they
  allow you to store away the state of of the interpreter at any given point.
  More importantly, they allow you to return to that state at any later time, by
  calling the continuation with, and evaluation of that interpreter state will
  resume. They are a concept that first arose in LISP, but have implementations
  these days in Ruby, Scheme, Haskell, and Smalltalk, to name a few.
Thus, continuations allow you to preserve context, and return to it later. This
  is amazingly useful in web programming, which is limited to "HTTP",
  which is an inherently stateless protocol. By passing around continuations, we
  can keep track of the context that got us to the current page.
While we can't construct 
full continuations at the interpreter level --
  because Perl does not support them -- we can implement them at the level of
  HTTP requests. In technical terms, because they capture the control stack up
  from the beginning of a user's session, they are called 
delimited
  continuations.
Continuations are more useful than sessions. Sessions store information across
  browser windows. Sessions may also break in the presence of the back button,
  as the information displayed on the screen, and the information stored in the
  session may differ. Since continuations are immutable, and a new one is
  produced every time a change is made, the information displayed in the browser
  cannot get out of sync with the information contained in any associated
  continuation.
USING CONTINUATIONS¶
As simple links in templates¶
The simplest form of continuation use is in a template, using
  "tangent" in Jifty::Web, as follows:
    <% Jifty->web->tangent( url   => "/someplace",
                            label => "Go someplace") %>
This will create a link, which, when clicked, will store the current request
  into a continuation, and jump to the url "/someplace". In the
  "/someplace" template, you can display information, and possibly
  have the user navigate between multiple pages before returning to the previous
  page:
    <% Jifty->web->return( label => "Back to whence you came" ) %>
Because this "return" does not carry a result value, you can think of
  it as a form of "gosub". In comparison, ordinary hyperlinks are akin
  to "goto" statements.
Sometimes, it may be possible for the user to get to a location without having a
  continuation set. In that case, clicking on the "Back to whence you
  came" link will appear to do nothing -- which may be slightly confusing
  to the user. To remedy this, Jifty provides a way to specify a default
  location to return to:
    <% Jifty->web->return( to => "/default", label => "Go back" ) %>
Using return values¶
All of the above examples generate links, which means that they don't interact
  at all with actions. However, continuations can also be useful in creating
  complex multi-page actions.
Continuations are saved -- and the browser is redirected to the new URL -- just
  after all actions have been checked for validation but before any of them are
  run. This means that the new request has access to the full validation state
  of its parent's actions.
When a continuation is called, it first checks that all actions in the request
  were successful; if any failed, then the continuation is 
not called. If
  the request's actions were all successful, it merges together the
  Jifty::Results of current Jifty::Response with those in the Jifty::Response
  stored in the continuation. In doing so, parameters are mapped using
  Jifty::Request::Mapper. This makes it possible to return values from
  continuations into arbitrary places. For example:
    % my $action = Jifty->web->new_action(class => 'AddTwoNumbers');
    <% Jifty->web->form->start %>
    <% $action->form_field( 'first_number' ) %>
    <% $action->form_field( 'second_number',
           default_value => {
               request_argument => "number",
           }
       ) %>
    <% Jifty->web->tangent(
            url    => '/pagetwo',
            label  => 'Enter a second number',
            submit => $action
       ) %>
    <% Jifty->web->form->end %>
..and in "/pagetwo":
    <% Jifty->web->form->start %>
    <input type="text" name="number" />
    %# We use as_button to tell Jifty that we want a button, not a link
    <% Jifty->web->return( label => 'Pick', as_button => 1 ) %>
    <% Jifty->web->form->end %>
..and assuming that "AddTwoNumbers"'s "take_action"
  resembles:
    sub take_action {
        my $self = shift;
        my $one = $self->argument_value("first_number");
        my $two = $self->argument_value("second_number");
        $self->result->message("Got " . ($one + $two));
    }
The first page renders the entry box for the first number; the second input is
  hidden because Jifty notices that it is based on a mapped value: i.e., its
  default is set to "{request_argument => "number"}"
  instead of a plain scalar value.
Pressing the button validates the action but does not complete running it. At
  this point, the "second_number" argument to the
  "AddTwoNumbers" action has no real value -- however, it knows that
  it will, at the earliest possible opportunity, fill in its value from the
  "number" request parameter.
Jifty tangents to "/pagetwo", where we enter and submit a
  "number" argument. Control then returns to the original page, where
  the request mapper maps the "number" value into the
  "second_number" argument of the "AddTwoNumbers" action,
  which then runs because it has received all arguments it requires.
Note that in the example above, the "number" argument is a plain
  request argument, not part of another action. More complex mappings are
  possible, including grabbing the results of or arguments to actions. This
  would make it possible, for instance, to use an action on the second page to
  validate the number before returning. This is slightly different from placing
  a validator on the "AddTwoNumbers" action, as that validator only
  gets called 
after control has already returned to the first page.
As dispatcher rules¶
The "tangent" in Jifty::Web function is context-aware -- if it is
  called in void context, it immediately saves the continuation and redirects to
  the new url. This is particularly useful, say, for authentication protection
  in "before" blocks:
    before '/protected' => sub {
        # shorthand for: Jifty->web->tangent( url => '/login' )
        tangent('/login') unless Jifty->web->current_user->id;
    };
And in the "/login" template:
    % my $action = Jifty->web->new_action(class   => 'Login',
    %                                     moniker => 'loginbox' );
    <% Jifty->web->form->start %>
    <% $action->form_field('username') %>
    <% $action->form_field('password') %>
    <% Jifty->web->return( to     => "/protected",
                           label  => 'Login',
                           submit =>  $action) %>
    <% Jifty->web->form->end %>
This establishes a button, which, if the "Login" action is successful,
  calls the stored continuation, or, lacking one, redirects to
  "/protected".
As currently implemented, these redirect-from-dispatcher tangents works exactly
  like rendered-as-links tangents, in that when they return, 
all rules in
  the dispatcher are still executed from the start. Therefore the
  "unless" guard in the "before '/protected'" rule above is
  necessary to prevent recursion.
GORY DETAILS¶
Jifty's continuations are implemented in Jifty::Continuation, which is very
  little more than a place to store a Jifty::Request and its associated
  Jifty::Response.
The following diagram diagrams the stages of continuation handling, and their
  interaction with the dispatcher. For clarity, the page region handling code is
  included, but page regions do not currently interact with continuation
  processing.
                                /--------------\
          +---------------------v-+            |
          |........Request........|            |
          +-|-------------------|-+            |
            |                   |  RETURN  +---|---------------------+
    /----\  |                   \----------> Replace request with    |
    |  +-|--|-+ +==============+           | request in continuation |
    |  |.v..v.---> SETUP rules |           +-------------------------+
    |  |......| +==============+
    |  |..D...|
    |  |..I...| +~~~~~~~~~~~~~~~~~~~+      +-------------------------+
    |  |..S...---> Validate actions |      | Store current request   |
    |  |..P...| +~~~~~|~~~~~~~~~|~~~+ SAVE | and response, redirect  |
    |  |..A...|       |         \----------> to new scope and URL    |
    |  |..T...|       |                    +-------------------------+
    |  |..C...| +~~~~~v~~~~~~~~~~~~~+
    |  |..E...| |  Run actions      |      +-------------------------+
    |  |..R...| +~~~~~~~~~~~~~~~|~~~+ CALL | Merge results into the  |
    |  |......|                 \----------> continuation's results; |
    |  |......|                            | redirect to return URL  |
    |  |......| +==============+           +-------------------------+
    |  |......---> RUN rules   |
    |  |......| +=====|========+
    |  |......|       |
    |  |......|    +--v---------------+
    |  |......|    | Show templates   |
    |  |......|    +-------|----------+
    |  |......|            |
    |  |......|    +-------v----------+
    |  |......|    | Show page region ---------------------\
    |  |......|    +------------------+                    |
    |  |......|                                            |
    |  |......| +==============+                           |
    |  |......---> AFTER rules |                           |
    |  +------+ +==============+                           |
    |                                                      |
    \------------------------------------------------------/
As shown in the diagram above, there are three different operations that
  continuations use. The first is "SAVE", which is triggered by the
  query parameter <J:CREATE>. Continuations are saved after validating
  actions; the continuation itself is attached to the user's session object.
The current saved continuation is automatically preserved across requests. When
  the time comes to call the continuation, the "CALL" operation is
  performed; this is usually triggered by the presence of the <J:CALL>
  query parameter. This causes the stored request to be query-mapped using
  Jifty::Request::Mapper, but using the 
current request and response (
  
not the continuation!) as the sources for mapping values. Then, the
  result objects are merged, with results from the stored response taking
  precedence. This new mapped request and new merged response are formed into a
  new continuation.
In order to ensure that the browser's URL matches the URL of the request in the
  continuation, Jifty then does a redirect to the URL of the request stored in
  the continuation, starting the last continuation operation, the
  "RETURN". When Jifty detects the "RETURN" operation, most
  often by the presence of "J:RETURN", it loads the continuation and
  reads the stored request and response into the current request and
  response.