root/lang/perl/NanoA/trunk/lib/NanoA.pm @ 25129

Revision 25129, 5.7 kB (checked in by kazuho, 4 years ago)

fix package_to_path

  • Property svn:keywords set to Id
Line 
1package NanoA;
2
3use strict;
4use warnings;
5use utf8;
6
7our $VERSION = '0.11';
8
9my %REQUIRED;
10my %LOADED;
11my %HOOKS;
12
13BEGIN {
14    %REQUIRED = ();
15    %LOADED = ();
16    %HOOKS = (
17        prerun  => {},
18        postrun => {},
19    );
20};
21
22sub new {
23    my ($klass, $config) = @_;
24    my $self;
25    $self = bless {
26        config        => $config,
27        query         => sub {
28            require_once('CGI/Simple.pm');
29            no warnings "all"; # suppress 'used only once'
30            $CGI::Simple::PARAM_UTF8 = 1;
31            CGI::Simple->new();
32        },
33        headers       => { # prefined headers are unique (only set once)
34            -type    => 'text/html',
35            -charset => 'utf-8',
36        },
37        stash         => {},
38    }, $klass;
39    $self;
40}
41
42sub run_hooks {
43    my $self = shift;
44    my $mode = shift;
45    my $klass = ref $self;
46    my @hooks;
47    if (my $h = $HOOKS{$mode}->{$klass}) {
48        push @hooks, @$h;
49    }
50    if ($klass =~ /^([^:]+)/) {
51        if (my $h = $HOOKS{$mode}->{$1 . '::config'}) {
52            push @hooks, @$h;
53        }
54    }
55    return
56        unless @hooks;
57    $_->[0]->($self, @_)
58        for sort { $a->[1] <=> $b->[1] } @hooks;
59}
60
61sub register_hook {
62    my ($klass, $mode, $func, $prio) = @_;
63    $prio ||= 50;
64    die 'unknown hook: ' . $mode. "\n"
65        unless $HOOKS{$mode};
66    my $hooks = $HOOKS{$mode}->{ref $klass || $klass} ||= [];
67    unless (grep { $_->[0] == $func } @$hooks) {
68        push @$hooks, [
69            $func,
70            $prio,
71        ];
72    }
73}
74
75sub query {
76    my $self = shift;
77    return $self->{query} = shift
78        if @_;
79    $self->{query} = $self->{query}->($self)
80        if ref $self->{query} eq 'CODE';
81    $self->{query};
82}
83
84sub header {
85    my $self = shift;
86    my $h = $self->{headers};
87    if (@_ == 0) {
88        return $h;
89    } elsif (@_ == 1) {
90        my $name = lc shift;
91        my $v = $h->{$name}
92            or return;
93        return wantarray ? @$v : $v->[0]
94            if ref $v eq 'ARRAY';
95        return $v;
96    } else {
97        die "Usage error: \$app->header() or \$app->header(name) or \$app->header(n1 => v1, n2 => v2)\n"
98            if @_ % 2 != 0;
99        while (@_) {
100            my $n = lc shift;
101            $n =~ s/^([^-])/-$1/;
102            my $v = shift;
103            $v = [ $v ]
104                unless ref $v eq 'ARRAY';
105            if (exists $h->{$n}) {
106                if (ref $h->{$n} eq 'ARRAY') {
107                    # exists as an array, just add
108                    push @{$h->{$n}}, @$v;
109                } else {
110                    # exists as an scalar, just replace
111                    $h->{$n} = $v->[0];
112                }
113            } else {
114                $h->{$n} = [ @$v ];
115            }
116        }
117        return $h;
118    }
119}
120
121sub redirect {
122    my ($self, $uri, $status) = @_;
123    unless ($uri) {
124        $uri = nanoa_uri() . '/' . package_to_path(ref $self);
125    }
126    $status ||= 302;
127    print 'Status: ', $status, "\nLocation: " . $uri . "\n\n";
128    CGI::ExceptionManager::detach();
129}
130
131sub render {
132    my ($self, $path, $c) = @_;
133    return NanoA::Dispatch->dispatch_as($path, $self, $c);
134}
135
136sub package_to_path {
137    my $pkg = shift;
138    $pkg =~ s|::|/|g;
139    $pkg =~ s|/start$|/|;
140    $pkg;
141}
142
143sub escape_html {
144    my $str = shift;
145    return $$str
146        if ref $str eq 'MENTA::Template::raw_string';
147    $str =~ s/&/&amp;/g;
148    $str =~ s/>/&gt;/g;
149    $str =~ s/</&lt;/g;
150    $str =~ s/"/&quot;/g;
151    $str =~ s/'/&#39;/g;
152    return $str;
153}
154
155# create raw string (that does not need to be escaped)
156sub raw_string {
157    my $s = shift;
158    ref $s eq 'MENTA::Template::RawString'
159        ? $s
160            : bless \$s, 'MENTA::Template::RawString';
161}
162
163sub nanoa_uri {
164    $ENV{SCRIPT_NAME} || '/nanoa.cgi';
165}
166
167sub root_uri {
168    my $p = nanoa_uri();
169    $p =~ s|/[^/]+$||;
170    $p;
171}
172
173sub app_dir {
174    'app';
175}
176
177sub config {
178    my $self = shift;
179    return $self->{config}->{$_[0]}
180        if @_ == 1;
181    my %args = @_;
182    $self->{config}->{$_} = $args{$_}
183        for keys %args;
184    $self->{config};
185}
186
187sub print_header {
188    my $self = shift;
189    my $headers = $self->{headers};
190    my $ct = delete $headers->{-type};
191    if ($ct =~ /;\s*charset=/) {
192        delete $headers->{-charset};
193    } else {
194        $ct .= "; charset=" . delete $headers->{-charset};
195    }
196    print 'Content-Type: ', $ct, "\n";
197    foreach my $n (sort keys %$headers) {
198        my $v = $headers->{$n};
199        $n =~ s/^-//;
200        $n =~ tr/_/-/;
201        if (ref $v eq 'ARRAY') {
202            foreach my $vv (@$v) {
203                print ucfirst($n), ': ', $vv, "\n";
204            }
205        } else {
206            print ucfirst($n), ': ', $v, "\n";
207        }
208    }
209    print "\n";
210}
211
212sub require_once {
213    my $path = shift;
214    return if $REQUIRED{$path};
215    require $path;
216    $REQUIRED{$path} = 1;
217}
218
219sub load_once {
220    my ($path, $mark_path) = @_;
221    $mark_path ||= $path;
222    return if $LOADED{$mark_path};
223    local $@;
224    if (do $path) {
225        $LOADED{$mark_path} = 1;
226        return 1;
227    }
228    die $@
229        if $@;
230    undef;
231}
232
233sub loaded {
234    my $path = shift;
235    $LOADED{$path} = shift
236        if @_;
237    $LOADED{$path};
238}
239
240sub db {
241    my $self = shift;
242    unless ($self->{db}) {
243        require_once('DBI.pm');
244        my $db_uri = $self->config->db_uri;
245        $self->{db} = DBI->connect($db_uri)
246            or die DBI->errstr;
247        $self->{db}->{unicode} = 1
248            if $db_uri =~ /^dbi:sqlite:/i;
249    }
250    $self->{db};
251}
252
253sub read_file {
254    my $fname = shift;
255    open my $fh, '<:utf8', $fname or die 'cannot read ' . $fname. ":$!";
256    my $s = do { local $/; join '', <$fh> };
257    close $fh;
258    $s;
259}
260
261sub __insert_methods {
262    my $module = shift;
263    no strict 'refs';
264    *{$module . '::' . $_} = \&{$_}
265        for qw(raw_string escape_html);
266}
267
268"ENDOFMODULE";
Note: See TracBrowser for help on using the browser.