/[pub]/suikawiki/script/lib/SuikaWiki/Implementation.pm
Suika

Contents of /suikawiki/script/lib/SuikaWiki/Implementation.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.6 - (hide annotations) (download)
Fri Dec 26 06:41:48 2003 UTC (21 years, 6 months ago) by wakaba
Branch: MAIN
Changes since 1.5: +89 -2 lines
(uri_reference, uri_is_part_of_wiki): New functions

1 wakaba 1.1
2     =head1 NAME
3    
4     SuikaWiki::Implementation --- SuikaWiki : Wiki Core Implementation
5    
6     =cut
7    
8     package SuikaWiki::Implementation;
9     use strict;
10 wakaba 1.6 our $VERSION = do{my @r=(q$Revision: 1.5 $=~/\d+/g);sprintf "%d."."%02d" x $#r,@r};
11 wakaba 1.2
12 wakaba 1.4 our $INTERFACE_VERSION = '2.9.1';
13 wakaba 1.1
14     =head1 METHODS
15    
16     =over 4
17    
18     =item $wiki = SuikaWiki::Implementation->new ()
19    
20     Constructs new instance of wiki implementation
21    
22     =cut
23    
24     sub new ($;%) {
25 wakaba 1.2 my $self = bless {
26     implementation_name => 'SuikaWiki',
27     implementation_version => 'impl'.$VERSION,
28     interface_version => $INTERFACE_VERSION,
29     }, shift;
30 wakaba 1.1
31     $self;
32     }
33    
34 wakaba 1.2 =item $wiki->init_variables
35    
36     Initialize per-access variables. This method should be called
37     before other init_* methods are to be called.
38    
39     =cut
40    
41     sub init_variables ($) {
42     my $self = shift;
43     $self->{var} = {};
44     $self->__raise_event (name => 'setting_initial_variables');
45     }
46    
47 wakaba 1.1 =item $wiki->init_plugin
48    
49     Prepares to use wiki plugins
50    
51     =cut
52    
53     sub init_plugin ($) {
54     my $self = shift;
55     require SuikaWiki::Plugin;
56 wakaba 1.5 $self->{plugin} = SuikaWiki::Plugin->new (wiki => $self);
57 wakaba 1.1
58     $self->__raise_event (name => 'plugin_manager_loaded');
59     }
60    
61     =item $wiki->init_view
62    
63     Prepares to use wikiview
64    
65     =cut
66    
67     sub init_view ($) {
68     my $self = shift;
69     require SuikaWiki::View::Implementation;
70     $self->{view} = SuikaWiki::View::Implementation->new (wiki => $self);
71    
72     $self->__raise_event (name => 'view_implementation_loaded');
73     }
74    
75     =item $wiki->init_db
76    
77     Prepares to use wiki database
78    
79     =cut
80    
81     sub init_db ($) {
82     my $self = shift;
83 wakaba 1.3 return if ref $self->{db}; ## Already initialized
84 wakaba 1.1 $self->{config}->{lock}
85     = {-directory => $self->{config}->{path_to}->{db__lock__dir},
86     -retry => 20,
87     -error_handler => sub {
88     my ($self, %o) = @_;
89     if ($self->{config}->{path_to}->{db__content__error_log}) {
90     open LOG, '>>', $self->{config}->{path_to}
91     ->{db__content__error_log};
92     print LOG scalar (gmtime),
93     "\@@{[time]} @{[$$]} {$o{level}}: LOCK: ",
94     $o{msg}, "\n";
95     close LOG;
96     }
97     if ($o{level} eq 'fatal') {
98     die $o{msg};
99     }
100     },
101     };
102     $self->{var}->{db}->{lock_prop} = sub {
103     my $prop = shift;
104     my %lock = %{$self->{config}->{lock}};
105     $lock{-name} = $prop;
106     $lock{-share} = defined $self->{var}->{db}->{read_only}->{$prop}
107     ? $self->{var}->{db}->{read_only}->{$prop}
108     : $self->{var}->{db}->{read_only}->{'#default'};
109     \%lock;
110     };
111    
112     require SuikaWiki::DB::Logical;
113     $self->{db} = new SuikaWiki::DB::Logical;
114    
115     $self->__raise_event (name => 'database_loaded');
116     }
117    
118 wakaba 1.3 =item $wiki->view_in_mode (%opt)
119    
120     Doing main process in accordance to the mode.
121    
122     Actually, this method only raises an event of 'view_in_mode'.
123     So that "doing main process" code should be registered as an event procedure
124     of 'view_in_mode'.
125    
126     =cut
127    
128     sub view_in_mode ($%) {
129     my ($self, %opt) = @_;
130     $self->__raise_event (name => 'view_in_mode', argv => [\%opt]);
131     }
132    
133 wakaba 1.1 sub __raise_event ($%) {
134     my ($self, %o) = @_;
135     for (@{$self->{event}->{$o{name}}||[]}) {
136 wakaba 1.2 &{$_} ($self, @{$o{argv}||[]});
137 wakaba 1.1 ## TODO: canceling
138     }
139     1;
140     }
141    
142 wakaba 1.5 sub ___raise_event ($$$) {
143     my ($self, $name, $argv) = @_;
144     my $event = {cancel => 0, name => $name, $name => $argv};
145     for (@{$self->{event}->{$name}}) {
146     $_->($self, $event);
147     return 0 if $event->{cancel};
148     }
149     return 1;
150     }
151    
152 wakaba 1.2 =item $string = $wiki->version
153    
154     Returns version string of the WikiEngine implementation.
155     This value is combination of the SuikaWiki Interface version and
156     implementation's version.
157    
158     =cut
159    
160     sub version ($) {
161     my ($self) = @_;
162 wakaba 1.4 $self->{interface_version} . '-' . $self->{implementation_version};
163 wakaba 1.2 }
164    
165 wakaba 1.6 sub uri_reference ($;%) {
166     my ($self, %opt) = @_;
167     my $uri = $self->___get_wiki_uri;
168    
169     ## SuikaWiki 3.0 format
170     my $query_param = qr/[^0-9A-Za-z_.-]/;
171     my @param = map {$self->___uri_escape_encode ($_, $query_param).'='.
172     $self->___uri_escape_encode ($opt{param}->{$_}, $query_param)}
173     keys %{$opt{param}};
174     push @param, 'mode='.$self->___uri_escape_encode ($opt{mode}, $query_param)
175     if $opt{mode};
176     push @param, 'x-d='.time if $opt{up_to_date};
177     if ($opt{page}) {
178     if ($opt{with_lm} and ref $self->{db}) {
179     push @param, 'x-lm='
180     . $self->___uri_escape_encode
181     ($self->{db}->get (lastmodified => $opt{page}),
182     $query_param);
183     }
184     ## TODO: Common WikiName interface
185     my $page = join '//', @{$opt{page}};
186     if (@param) {
187     ## TODO: Encode by $wiki->{config}->{charset}->{uri_param_encode}
188     unshift @param, 'mypage='.$self->___uri_escape_encode
189     ($page, $query_param);
190     push @param, '_charset_='.$self->{config}->{charset}->{uri_param_encode};
191     ## TODO: downgrade to &
192     $uri->query (join ';', @param);
193     } else {
194     ## TODO: Encode by $wiki->{config}->{charset}->{uri_query_encode}
195     $uri->query ($self->___uri_escape_encode ($page, $query_param));
196     }
197     } elsif (@param) {
198     push @param, '_charset_='.$self->{config}->{charset}->{uri_param_encode};
199     $uri->query (join ';', @param);
200     }
201    
202     if ($opt{anchor_no}) {
203     $uri->fragment ('anchor-'.$opt{anchor_no});
204     } elsif ($opt{fragment}) {
205     $uri->fragment ($opt{fragment});
206     }
207     ## TODO: wikiform
208    
209     if (defined $opt{base}) {
210     $opt{base} = $self->{input}->request_uri
211     if ref $self->{input} and not ref $opt{base} and $opt{base} eq '1';
212     return wantarray ? ($uri->rel ($opt{base}), $uri) : $uri->rel ($opt{base});
213     } else {
214     return ($uri, $uri);
215     }
216     }
217    
218     sub uri_is_part_of_wiki ($$) {
219     my ($self, $uri) = @_;
220     my $wiki_uri = ''.$self->___get_wiki_uri;
221     substr ($uri, 0, length ($wiki_uri)) eq $wiki_uri ? 1 : 0;
222     }
223    
224     sub ___get_wiki_uri ($) {
225     my ($self) = shift;
226     my $uri;
227     if (ref $self->{___uri}) {
228     $uri = $self->{___uri}->clone;
229     } elsif (ref $self->{input}) {
230     $uri = $self->{input}->request_uri (no_path_info => 1, no_query => 1);
231     $self->{___uri} = $uri->clone;
232     } else {
233     $uri = URI->new;
234     }
235     $uri;
236     }
237    
238     sub ___uri_escape_encode ($$;$) {
239     my ($self, $s, $char) = @_;
240     $char ||= qr([^0-9A-Za-z_.!~*'();/?:\@&=+\$,-]);
241     ## TODO:
242     # require Encode;
243     # $s = Encode::decode ('utf8', $s);
244     $s =~ s/($char)/sprintf '%%%02X', ord $1/ge;
245     $s;
246     }
247    
248 wakaba 1.5 sub close_db ($) {
249     my $self = shift;
250     $self->{db}->close if ref $self->{db};
251     delete $self->{db};
252     }
253    
254     sub close_view ($) {
255     my $self = shift;
256     $self->{view}->exit if ref $self->{view};
257     delete $self->{view};
258     }
259    
260     sub close_plugin ($) {
261     my $self = shift;
262     $self->{plugin}->exit if ref $self->{plugin};
263     delete $self->{plugin};
264     }
265    
266     sub close_input ($) {
267     my $self = shift;
268     $self->{input}->exit if ref $self->{input};
269     delete $self->{input};
270     }
271    
272 wakaba 1.1 =item $wiki->exit
273    
274     Exits wiki
275    
276     =cut
277    
278     sub exit ($) {
279     my $self = shift;
280 wakaba 1.5 return 0 unless $self->___raise_event (name => 'close');
281     $self->close_db;
282     $self->close_view;
283     $self->close_input;
284     $self->close_plugin;
285     $self->{exited} = 1;
286     1;
287 wakaba 1.1 }
288    
289     sub DESTROY ($) {
290     my $self = shift;
291 wakaba 1.5 $self->exit unless $self->{exited};
292 wakaba 1.1 }
293    
294     =back
295    
296     =head1 PUBLIC PROPERTIES
297    
298     =over 4
299    
300 wakaba 1.2 =item $wiki->{config}
301    
302     Persistent wiki configureation parameters
303     (that is not changed with the situation when is who accessing in what way)
304    
305     =over 4
306    
307     =item ->{charset}->{internal} = <IANA charset name (in lower case)>
308    
309     Character encoding scheme used in wiki implementation
310    
311     =item ->{charset}->{output} = <IANA charset name (in lower case)>
312    
313     Default character encoding scheme used to output content
314    
315 wakaba 1.5 =item ->{debug}->{$category} = 1/0 (Default 0)
316    
317     Debug mode
318    
319     Categories:
320    
321     =over 4
322    
323     =item db
324    
325     WikiDatabase related features
326    
327     =back
328    
329 wakaba 1.2 =item ->{entity}->{expires}->{$rulename} = {delta => $seconds}
330    
331     How long outputed entity will be fresh.
332    
333     =item ->{lock}
334 wakaba 1.1
335     Default (prototype) properties to give SuikaWiki::DB::Util::Lock
336    
337 wakaba 1.2 =item ->{page}->{ $name }
338    
339     WikiPage which has feature of $name
340    
341     =item ->{path_to}->{ $name }
342 wakaba 1.1
343     Filesystem path (or path fragment) to $name
344    
345 wakaba 1.2 =back
346    
347 wakaba 1.1 =item $wiki->{db}
348    
349     Wiki main database
350    
351     =item @{$wiki->{event}->{ $event_name }}
352    
353     Event handling procedures
354    
355 wakaba 1.2 Standarized event names:
356    
357     =over 4
358    
359     =item database_loaded
360    
361     When WikiDatabase manager is loaded. This event handler is typically
362     used to set database property module for SuikaWiki::DB::Logical.
363    
364     =item plugin_manager_loaded
365    
366     When WikiPlugin manager is loaded. Note that plugins themselves are not
367     loaded yet.
368    
369     =item setting_initial_variables
370    
371     On the process to set per-access variables.
372     This event is raised before other core modules such as WikiDatabase
373     or WikiPlugin are loaded.
374    
375     =back
376    
377     =item $wiki->{implementation_name} (default 'SuikaWiki')
378    
379     Product name of the WikiEngine.
380    
381     For interoperability, only alphanumeric characters and limited symbols
382     (those allowed in RFC 2616 token) should be used as parts of product name.
383    
384     =item $wiki->{implementation_version} (default "impl$VERSION")
385    
386     WikiEngine implementation's version in string.
387    
388     For interoperability, only alphanumeric characters and limited symbols
389     (those allowed in RFC 2616 token) should be used as parts of product name.
390    
391     =item $wiki->{interface_version} (Read only)
392    
393     SuikaWiki Interface version implemented by this wiki implementation
394    
395     =item $wiki->{var}
396    
397     Non-persistent wiki variable options
398     (that might vary with context such as caller's argument values)
399    
400     =over 4
401    
402 wakaba 1.6 =item ->{client}->{downgrade}->{ $feature } = $parameter
403    
404     Whether downgrade is required. See C<Downgrade> plugin module.
405    
406 wakaba 1.2 =item ->{client}->{used_for_negotiation} = [<HTTP field name>s]
407    
408     HTTP (request) header field names used to select variable content.
409     This value will be used to generate HTTP Vary header field.
410    
411     =item ->{client}->{user_agent_name} = <HTTP User-Agent field body value>
412    
413     User agent name provided by such ways as User-Agent field (in HTTP)
414     or HTTP_USER_AGENT meta variable (in HTTP-CGI).
415    
416     =item ->{db}->{lock_prop} = sub ($prop)
417    
418     Function returning hash reference of lock options
419     (that will be passed to SuikaWiki::DB::Util::Lock->new).
420    
421     $prop, an argument to the function, is a database property name.
422    
423     =item ->{db}->{read_only}->{ $prop } = 1/0
424    
425     Whether the database property named as $prop is opened in read only
426     mode or not. Special property name of '#default' is used to set
427     the default value referred when {read_only}->{$prop} is not specified
428     explicily.
429    
430     Note that this value must be set before the instance of database property
431     is loaded.
432    
433 wakaba 1.5 =item ->{error} = [{description => Error 1}, {description => Error 2},...]
434    
435     Trapped errors.
436    
437 wakaba 1.2 =item ->{input}
438    
439     Instance of input parameter interface (such as SuikaWiki::Input::HTTP)
440    
441     =item ->{mode} = mode name
442    
443     Wiki mode name
444    
445     =item ->{page} = [page]
446    
447     WikiPage being referred
448    
449     =back
450    
451     =item $wiki->{view}
452    
453     WikiView implementation (an instance of SuikaWiki::View::Implementation)
454    
455 wakaba 1.1 =cut
456    
457     =head1 LICENSE
458    
459     Copyright 2003 Wakaba <w@suika.fam.cx>
460    
461     This program is free software; you can redistribute it and/or
462     modify it under the same terms as Perl itself.
463    
464     =cut
465    
466 wakaba 1.6 1; # $Date: 2003/12/06 05:43:55 $

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24