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

Revision 24563, 5.2 kB (checked in by kazuho, 5 years ago)

mv NanoA::mobile_agent to plugin

  • Property svn:keywords set to Id
Line 
1package NanoA;
2
3use strict;
4use warnings;
5use utf8;
6
7our $VERSION = '0.08';
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    $status ||= 302;
124    print 'Status: ', $status, "\nLocation: " . $uri . "\n\n";
125    CGI::ExceptionManager::detach();
126}
127
128sub render {
129    my ($self, $path, $c) = @_;
130    return NanoA::Dispatch->dispatch_as($path, $self, $c);
131}
132
133sub escape_html {
134    my $str = shift;
135    $str =~ s/&/&amp;/g;
136    $str =~ s/>/&gt;/g;
137    $str =~ s/</&lt;/g;
138    $str =~ s/"/&quot;/g;
139    $str =~ s/'/&#39;/g;
140    return $str;
141}
142
143sub nanoa_uri {
144    $ENV{SCRIPT_NAME} || '/nanoa.cgi';
145}
146
147sub root_uri {
148    my $p = nanoa_uri();
149    $p =~ s|/[^/]+$||;
150    $p;
151}
152
153sub app_dir {
154    'app';
155}
156
157sub config {
158    my $self = shift;
159    return $self->{config}->{$_[0]}
160        if @_ == 1;
161    my %args = @_;
162    $self->{config}->{$_} = $args{$_}
163        for keys %args;
164    $self->{config};
165}
166
167sub print_header {
168    my $self = shift;
169    my $headers = $self->{headers};
170    my $ct = delete $headers->{-type};
171    if ($ct =~ /;\s*charset=/) {
172        delete $headers->{-charset};
173    } else {
174        $ct .= "; charset=" . delete $headers->{-charset};
175    }
176    print 'Content-Type: ', $ct, "\n";
177    foreach my $n (sort keys %$headers) {
178        my $v = $headers->{$n};
179        $n =~ s/^-//;
180        $n =~ tr/_/-/;
181        if (ref $v eq 'ARRAY') {
182            foreach my $vv (@$v) {
183                print ucfirst($n), ': ', $vv, "\n";
184            }
185        } else {
186            print ucfirst($n), ': ', $v, "\n";
187        }
188    }
189    print "\n";
190}
191
192sub require_once {
193    my $path = shift;
194    return if $REQUIRED{$path};
195    require $path;
196    $REQUIRED{$path} = 1;
197}
198
199sub load_once {
200    my ($path, $mark_path) = @_;
201    $mark_path ||= $path;
202    return if $LOADED{$mark_path};
203    local $@;
204    if (do $path) {
205        $LOADED{$mark_path} = 1;
206        return 1;
207    }
208    die $@
209        if $@;
210    undef;
211}
212
213sub loaded {
214    my $path = shift;
215    $LOADED{$path} = shift
216        if @_;
217    $LOADED{$path};
218}
219
220sub db {
221    my $self = shift;
222    unless ($self->{db}) {
223        require_once('DBI.pm');
224        my $db_uri = $self->config->db_uri;
225        $self->{db} = DBI->connect($db_uri)
226            or die DBI->errstr;
227        $self->{db}->{unicode} = 1
228            if $db_uri =~ /^dbi:sqlite:/i;
229    }
230    $self->{db};
231}
232
233sub read_file {
234    my $fname = shift;
235    open my $fh, '<:utf8', $fname or die 'cannot read ' . $fname. ":$!";
236    my $s = do { local $/; join '', <$fh> };
237    close $fh;
238    $s;
239}
240
241sub __insert_methods {
242    my $module = shift;
243    no strict 'refs';
244    *{$module . '::' . $_} = \&{$_}
245        for qw(escape_html);
246}
247
248"ENDOFMODULE";
Note: See TracBrowser for help on using the browser.