Squatting

 view release on metacpan or  search on metacpan

lib/Squatting.pm  view on Meta::CPAN

            : "$_=".uri_escape($input->{$_})
        } keys %$input);
    }
    $path;
  };

  # ($controller, \@regex_captures) = D($path)  # Return controller and captures for a path
  *{$p."::D"} = sub {
    my $url = uri_unescape($_[0]);
    my $C = \@{$p.'::Controllers::C'};
    my ($c, @regex_captures);
    for $c (@$C) {
      for (@{$c->urls}) {
        if (@regex_captures = ($url =~ qr{^$_$})) {
          pop @regex_captures if ($#+ == 0);
          return ($c, \@regex_captures);
        }
      }
    }
    ($Squatting::Controller::r404, []);
  };

  *{$p."::Controllers::C"} = sub {
    Squatting::Controller->new(@_, app => $p)
  };
  *{$p."::Views::V"} = sub {
    Squatting::View->new(@_)
  };

}

# Squatting plugins may be anywhere in Squatting::*::* but by convention
# (and for fun) you should use poetic diction in your package names.
#
# Squatting::On::Continuity
# Squatting::On::Catalyst
# Squatting::On::CGI
# Squatting::On::Jifty 
#
# (ALL YOUR FRAMEWORK ARE BELONG TO US)
#
# Squatting::With::Impunity (What could we do w/ this name?)
# Squatting::With::Log4Perl (which is how we could add logging support)
#
# (etc)
sub component_base_class { __PACKAGE__ }

# 1
# App->mount($AnotherApp, $prefix)  # Map another app on to a URL $prefix.
sub mount {
  my ($app, $other, $prefix) = @_;
  push @{$app."::O"}, $other;
  push @{$app."::Controllers::C"}, map {
    my $urls = $_->urls;
    $_->urls = [ map { $prefix.$_ } @$urls ];
    $_;
  } @{$other."::Controllers::C"}
}

# 2
# App->relocate($prefix)  # Map main app to a URL $prefix
sub relocate {
  my ($app, $prefix) = @_;
  for (@{$app."::Controllers::C"}) {
    my $urls = $_->urls;
    $_->urls = [ map { $prefix.$_ } @$urls ];
  }
  ${$app."::CONFIG"}{relocated} = $prefix;
}

# 3
# App->init  # Initialize $app
sub init {
  $_->init for (@{$_[0]."::O"});
  %{$_[0]."::Controllers::C"} = map { $_->name => $_ } @{$_[0]."::Controllers::C"};
  %{$_[0]."::Views::V"}       = map { $_->name => $_ } @{$_[0]."::Views::V"};
}

# App->service($controller, @args)  # Handle an HTTP request
sub service {
  my ($app, $c, @args) = grep { defined } @_;
  my $method = lc $c->env->{REQUEST_METHOD};
  my $content;

  eval { $content = $c->$method(@args) };
  die $@ if (ref($@) =~ /^HTTP::Exception/); # Pass HTTP::Exceptions on up
  warn "EXCEPTION: $@" if ($@);

  my $cookies = $c->cookies;
  $c->headers->{'Set-Cookie'} = join("; ",
    map { CGI::Cookie->new( -name => $_, %{$cookies->{$_}} ) }
      grep { ref $cookies->{$_} eq 'HASH' }
        keys %$cookies) if (%$cookies);

  $content;
}

1;

=head1 NAME

Squatting - A Camping-inspired Web Microframework for Perl

=head1 SYNOPSIS

Running an App:

  $ squatting App
  Please contact me at: http://localhost:4234/

Check out our ASCII art logo:

  $ squatting --logo

What a basic App looks like:

  # STEP 1 => Use Squatting for your App
  {
    package App;  # <-- I hope it's obvious that this name can whatever you want.
    use Squatting;
    our %CONFIG;  # <-- standard app config goes here
  }

  # STEP 2 => Define the App's Controllers
  {
    package App::Controllers;

    # Setup a list of controller objects in @C using the C() function.

lib/Squatting.pm  view on Meta::CPAN


=back

B<*> RESTless controllers currently only work when you're L<Squatting::On::Continuity>.

=head1 API

=head2 Use as a Base Class for Squatting Applications

  package App;
  use Squatting;
  our %CONFIG = ();
  1;

Just C<use>ing Squatting makes a lot of magic happen.  In the example above:

=over 4

=item App becomes a subclass of Squatting.

=item App::Controllers is given this app's R() and C() functions.

=item App::Views is given this app's R() and V() functions.

=back

=head3 App->service($controller, @args)

Every time an HTTP request comes in, this method is called with a controller
object and a list of arguments.  The controller will then be invoked with the
HTTP method that was requested (like GET or POST), and it will return the
content of the response as a string.

B<NOTE>:  If you want to do anything before, after, or around an HTTP request,
this is the method you should override in your subclass.

=head3 App->init

This method takes no parameters and initializes some internal variables.

B<NOTE>:  You can override this method if you want to do more things when
the App is initialized.

=head3 App->mount($AnotherApp => $prefix)

XXX - The C<mount()> has been moved out of the core and into 
L<Squatting::With::Mount>.  Furthermore, Squatting::With::Mount has
been implemented using L<Squatting::On::Squatting>.

This method will mount another Squatting app at the specified prefix.

  App->mount('My::Blog'   => '/my/ridiculous/rantings');
  App->mount('Forum'      => '/forum');
  App->mount('ChatterBox' => '/chat');

B<NOTE>:  You can only mount an app once.  Don't try to mount it again
at some other prefix, because it won't work.  This is a consequence
of storing so much information in package variables and a strong argument
for going all objects all the time.

=head3 App->relocate($prefix)

This method will relocate a Squatting app to the specified prefix.  It's useful
for embedding a Squatting app into apps written in other frameworks.

This also has a side-effect of setting C<$CONFIG{relocated}> to C<$prefix>.

=head2 Use as a Helper for Controllers

In this package, you will define a list of L<Squatting::Controller> objects in C<@C>.

  package App::Controllers;
  use Squatting ':controllers';
  our @C = (
    C(...),
    C(...),
    C(...),
  );

=head3 C($name => \@urls, %methods)

This is a shortcut for:

  Squatting::Controller->new(
    $name => \@urls, 
    app   => $App, 
    %methods
  );

=head3 R($name, @args, [ \%params ])

R() is a URL generation function that takes a controller name and a list of
arguments.  You may also pass in a hashref representing CGI variables as the
very last parameter to this function.

B<Example>:  Given the following controllers, R() would respond like this.

  # Example Controllers
  C(Home    => [ '/' ]);
  C(Profile => [ '/~(\w+)', '/~(\w+)\.(\w+)' ]);

  # Generated URLs
  R('Home')                             # "/"
  R('Home', { foo => 1, bar => 2})      # "/?foo=1&bar=2"
  R('Profile', 'larry')                 # "/~larry"
  R('Profile', 'larry', 'json')         # "/~larry.json"
                                                             
As you can see, C<@args> represents the regexp captures, and C<\%params>
represents the CGI query parameters.

=head2 Use as a Helper for Views

In this package, you will define a list of L<Squatting::View> objects in C<@V>.

  package App::Views;
  use Squatting ':views';
  our @V = (
    V(
      'html',
      home => sub { "<h1>Home</h1>" },
    ),
  );

=head3 V($name, %methods)

This is a shortcut for:



( run in 0.817 second using v1.01-cache-2.11-cpan-71847e10f99 )