redispatch_to
[catagits/Web-Simple.git] / lib / Web / Simple / Application.pm
CommitLineData
5c33dda5 1package Web::Simple::Application;
2
3use strict;
4use warnings FATAL => 'all';
5
6sub new {
7 my ($class, $data) = @_;
8 my $config = { $class->_default_config, %{($data||{})->{config}||{}} };
9 bless({ config => $config }, $class);
10}
11
12sub config {
13 shift->{config};
14}
15
16sub _construct_response_filter {
17 bless($_[1], 'Web::Simple::ResponseFilter');
18}
19
20sub _is_response_filter {
21 # simple blessed() hack
22 "$_[1]" =~ /\w+=[A-Z]/
23 and $_[1]->isa('Web::Simple::ResponseFilter');
24}
25
39119082 26sub _construct_redispatch {
27 bless(\$_[1], 'Web::Simple::Redispatch');
28}
29
30sub _is_redispatch {
31 return unless
32 "$_[1]" =~ /\w+=[A-Z]/
33 and $_[1]->isa('Web::Simple::Redispatch');
34 return ${$_[1]};
35}
36
5c33dda5 37sub _dispatch_parser {
38 require Web::Simple::DispatchParser;
39 return Web::Simple::DispatchParser->new;
40}
41
42sub _setup_dispatchables {
43 my ($class, $dispatch_subs) = @_;
44 my $parser = $class->_dispatch_parser;
45 my @dispatchables;
46 foreach my $dispatch_sub (@$dispatch_subs) {
47 my $proto = prototype $dispatch_sub;
48 my $matcher = (
49 defined($proto)
50 ? $parser->parse_dispatch_specification($proto)
51 : sub { ({}) }
52 );
53 push @dispatchables, [ $matcher, $dispatch_sub ];
54 }
55 {
56 no strict 'refs';
57 *{"${class}::_dispatchables"} = sub { @dispatchables };
58 }
59}
60
61sub handle_request {
62 my ($self, $env) = @_;
63 $self->_run_dispatch_for($env, [ $self->_dispatchables ]);
64}
65
66sub _run_dispatch_for {
67 my ($self, $env, $dispatchables) = @_;
68 my @disp = @$dispatchables;
69 while (my $disp = shift @disp) {
70 my ($match, $run) = @{$disp};
71 if (my ($env_delta, @args) = $match->($env)) {
72 my $new_env = { %$env, %$env_delta };
73 if (my ($result) = $self->_run_with_self($run, @args)) {
74 if ($self->_is_response_filter($result)) {
75 return $self->_run_with_self(
76 $result,
77 $self->_run_dispatch_for($new_env, \@disp)
78 );
39119082 79 } elsif (my $path = $self->_is_redispatch($result)) {
80 $new_env->{PATH_INFO} = $path;
81 return $self->_run_dispatch_for($new_env, $dispatchables);
5c33dda5 82 }
83 return $result;
84 }
85 }
86 }
87 return [
88 500, [ 'Content-type', 'text/plain' ],
89 'The management apologises but we have no idea how to handle that'
90 ];
91}
92
93sub _run_with_self {
94 my ($self, $run, @args) = @_;
95 my $class = ref($self);
96 no strict 'refs';
97 local *{"${class}::self"} = \$self;
98 $self->$run(@args);
99}
100
101sub run_if_script {
102 return 1 if caller(1); # 1 so we can be the last thing in the file
103 my $class = shift;
104 my $self = $class->new;
105 $self->run(@_);
106}
107
108sub run {
109 my $self = shift;
110 unless ($ENV{GATEWAY_INTERFACE}) {
111 die "mst is an idiot and didn't fix non-CGI yet";
112 }
113 require Web::Simple::HackedPlack;
114 Plack::Server::CGI->run(sub { $self->handle_request(@_) });
115}
116
1171;