package Dancer2::Manual::Migration;
# ABSTRACT: Migrating from Dancer to Dancer2
$Dancer2::Manual::Migration::VERSION = '0.155002';
use strict;
use warnings;

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Dancer2::Manual::Migration - Migrating from Dancer to Dancer2

=head1 VERSION

version 0.155002

=head1 Migration from Dancer 1 to Dancer2

This document covers some changes that users will need to be aware of
while upgrading from L<Dancer> (version 1) to L<Dancer2>.

=head2 Apps

1. In L<Dancer2>, each module is a B<separate application> with its own
namespace and variables. You can set the application name in each of your
L<Dancer2> application modules. Different modules can be tied into the same
app by setting the application name to the same value.

For example, to set the appname directive explicitly:

C<MyApp>:

    package MyApp;
    use Dancer2;
    use MyApp::Admin

    hook before => sub {
        var db => 'Users';
    };

    get '/' => sub {...};

    1;

C<MyApp::Admin>:

    package MyApp::Admin;
    use Dancer2 appname => 'MyApp';

    # use a lexical prefix so we don't override it globally
    prefix '/admin' => sub {
        get '/' => sub {...};
    };

    1;

Without the appname directive, C<MyApp::Admin> would not have access
to variable C<db>. In fact, when accessing C</admin>, the before hook would
not be executed.

See L<Dancer2::Cookbook|https://metacpan.org/pod/Dancer2::Cookbook#Using-the-prefix-feature-to-split-your-application>
for details.

2. The following modules can be used to speed up an app in Dancer2:

=over 4

=item * L<URL::Encode::XS>

=item * L<CGI::Deurl::XS>

=item * L<HTTP::Parser::XS>

=back

They would need to be installed separately. This is because L<Dancer2> does
not incorporate any C code, but it can get C-code compiled as a module.
Thus, these modules can be used for speed improvement provided:

=over 4

=item * You have access to a C interpreter

=item * You don't need to fatpack your application

=back

=head2 Plugins: plugin_setting

C<plugin_setting> returns the configuration of the plugin. It can only be
called in C<register> or C<on_plugin_import>.

=head2 Routes

L<Dancer2> requires all routes defined via a string to begin with a leading
slash C</>.

For example:

    get '0' => sub {
        return "not gonna fly";
    };

would return an error. The correct way to write this would be to use
C<get '/0'>

=head2 Tests

Dancer2 recommends the use of L<Plack::Test>.

For example:

    use strict;
    use warnings;

    use Test::More tests => 2;
    use Plack::Test;
    use HTTP::Request::Common;

    {
        package App::Test; # or whatever you want to call it
        get '/' => sub { template 'index' };
    }

    my $test = Plack::Test->create( App::Test->to_app );
    my $res  = $test->request( GET '/' );

    ok( $res->is_success, '[GET /] Successful' );
    like( $res->content, qr{<title>Test2</title>}, 'Correct title' );

Other modules that could be used for testing are:

=over 4

=item * L<Test::TCP>

=item * L<Test::WWW::Mechanize::PSGI>

=back

=head3 Logs

The C<logger_format> in the Logger role (L<Dancer2::Core::Role::Logger>)
is now C<log_format>.

C<read_logs> can no longer be used, as with L<Dancer2::Test>. Instead,
L<Dancer2::Logger::Capture> could be used for testing, to capture all
logs to an object.

For example:

    use strict;
    use warnings;
    use Test::More import => ['!pass'];
    use Plack::Test;
    use HTTP::Request::Common;

    {
        package App;
        use Dancer2;

        set log       => 'debug';
        set logger    => 'capture';

        get '/' => sub {
            debug 'this is my debug message';
            return 1;
        };
    }

    my $app = Dancer2->psgi_app;
    is( ref $app, 'CODE', 'Got app' );

    test_psgi $app, sub {
        my $cb = shift;

        my $res = $cb->( GET '/' );
        is $res->code, 200;

        my $trap = App->dancer_app->logger_engine->trapper;

        is_deeply $trap->read, [
            { level => 'debug', message => 'this is my debug message' }
        ];
    };

=head2 Exports: Tags

The following tags are not needed in L<Dancer2>:

 use Dancer2 qw(:syntax);
 use Dancer2 qw(:tests);
 use Dancer2 qw(:script);

The C<plackup> command should be used instead. It provides a development
server and reads the configuration options in your command line utilities.

=head2 Engines

Engines now receive a logger that consumes L<Dancer2::Core::Role::Logger> in
order to log errors. The attribute is called C<logger>.

The logger engine doesn't have the attribute since it is the logger itself.

=head3 Serializers

You no longer need to implement the C<loaded> method. It is simply
unnecessary.

=head2 Configuration

=head3 server_tokens

The configuration C<server_tokens> has been introduced in the reverse (but
more sensible, and Plack-compatible) form as C<no_server_tokens>.

C<DANCER_SERVER_TOKENS> changed to C<DANCER_NO_SERVER_TOKENS>.

=head2 Keywords

=head3 load

This keyword is no longer required. Dancer2 loads the environment
automatically and will not reload any other environment when called with
L<load>. (It's a good thing.)

=head3 param_array

This keyword doesn't exist in Dancer2.

=head3 session

The session keyword has multiple states:

=over 4

=item * No arguments

Without any arguments, the session keyword returns a L<Dancer2::Core::Session>
object, which has methods for L<read>, L<write>, and L<delete>. 

    my $session = session;
    $session->read($key);
    $session->write( $key => $value );
    $session->delete($key);

=item * Single argument (key)

If a single argument is provided, it is treated as the key, and it will retrieve
the value for it.

    my $value = session $key;

=item * Two arguments (key, value)

If two arguments are provided, they are treated as a key and a value, in which
case the session will assign the value to the key.

    session $key => $value;

=item * Two arguments (key, undef)

If two arguments are provided, but the second is B<undef>, the key will be
deleted from the session.

    session $key => undef;

=back

In Dancer 1 it wasn't possible to delete a key, but in Dancer2 we can finally
delete:

    # these two are equivalent
    session $key => undef;

    my $session = session;
    $session->delete($key);

=head1 AUTHOR

Dancer Core Developers

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2014 by Alexis Sukrieh.

This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.

=cut
