/[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.7 - (hide annotations) (download)
Fri Jan 16 08:04:59 2004 UTC (22 years, 7 months ago) by wakaba
Branch: MAIN
Changes since 1.6: +27 -8 lines
Plugin.pm (text_formatter): New

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.24