/[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.8 - (hide annotations) (download)
Sun Feb 1 12:24:05 2004 UTC (21 years, 3 months ago) by wakaba
Branch: MAIN
Changes since 1.7: +154 -41 lines
Version properties are refined

1 wakaba 1.1
2     =head1 NAME
3    
4 wakaba 1.8 SuikaWiki::Implementation - SuikaWiki: WikiEngine Core
5    
6     =head1 DESCRIPTION
7    
8     This module implements core part of the SuikaWiki WikiEngine.
9     All implemented features of WikiEngine can be called directly
10     or indirectly from instance of this module (with some exception
11     such as functions provided by WikiPlugin modules).
12    
13     This module is part of SuikaWiki.
14    
15     =head1 SYNOPSIS
16    
17     require SuikaWiki::Implementation;
18     my $WIKI = new SuikaWiki::Implementation;
19     ...
20     $WIKI->exit;
21    
22     C<lib/suikawiki.pl> might be a good example for instanciating WikiEngine.
23 wakaba 1.1
24     =cut
25    
26     package SuikaWiki::Implementation;
27     use strict;
28 wakaba 1.8 our $VERSION = do{my @r=(q$Revision: 1.7 $=~/\d+/g);sprintf "%d."."%02d" x $#r,@r};
29 wakaba 1.1
30     =head1 METHODS
31    
32     =over 4
33    
34     =item $wiki = SuikaWiki::Implementation->new ()
35    
36     Constructs new instance of wiki implementation
37    
38     =cut
39    
40     sub new ($;%) {
41 wakaba 1.2 my $self = bless {
42 wakaba 1.8 driver_name => 'WikiImplementation',
43     driver_version => '0.0',
44     driver_uri_reference => q<about:>,
45     engine_name => 'SuikaWiki',
46     engine_version => '2.9.2',
47     engine_uri_reference => q<http://suika.fam.cx/~wakaba/-temp/wiki/wiki?SuikaWiki>,
48 wakaba 1.2 }, shift;
49 wakaba 1.1
50     $self;
51     }
52    
53 wakaba 1.2 =item $wiki->init_variables
54    
55     Initialize per-access variables. This method should be called
56     before other init_* methods are to be called.
57    
58     =cut
59    
60     sub init_variables ($) {
61     my $self = shift;
62 wakaba 1.7 $self->close_input;
63 wakaba 1.2 $self->{var} = {};
64     $self->__raise_event (name => 'setting_initial_variables');
65     }
66    
67 wakaba 1.1 =item $wiki->init_plugin
68    
69     Prepares to use wiki plugins
70    
71     =cut
72    
73     sub init_plugin ($) {
74     my $self = shift;
75     require SuikaWiki::Plugin;
76 wakaba 1.5 $self->{plugin} = SuikaWiki::Plugin->new (wiki => $self);
77 wakaba 1.1
78     $self->__raise_event (name => 'plugin_manager_loaded');
79     }
80    
81     =item $wiki->init_view
82    
83     Prepares to use wikiview
84    
85     =cut
86    
87     sub init_view ($) {
88     my $self = shift;
89     require SuikaWiki::View::Implementation;
90     $self->{view} = SuikaWiki::View::Implementation->new (wiki => $self);
91    
92     $self->__raise_event (name => 'view_implementation_loaded');
93     }
94    
95     =item $wiki->init_db
96    
97     Prepares to use wiki database
98    
99     =cut
100    
101     sub init_db ($) {
102     my $self = shift;
103 wakaba 1.3 return if ref $self->{db}; ## Already initialized
104 wakaba 1.1 $self->{config}->{lock}
105     = {-directory => $self->{config}->{path_to}->{db__lock__dir},
106     -retry => 20,
107     -error_handler => sub {
108     my ($self, %o) = @_;
109     if ($self->{config}->{path_to}->{db__content__error_log}) {
110     open LOG, '>>', $self->{config}->{path_to}
111     ->{db__content__error_log};
112     print LOG scalar (gmtime),
113     "\@@{[time]} @{[$$]} {$o{level}}: LOCK: ",
114     $o{msg}, "\n";
115     close LOG;
116     }
117     if ($o{level} eq 'fatal') {
118     die $o{msg};
119     }
120     },
121     };
122     $self->{var}->{db}->{lock_prop} = sub {
123     my $prop = shift;
124     my %lock = %{$self->{config}->{lock}};
125     $lock{-name} = $prop;
126     $lock{-share} = defined $self->{var}->{db}->{read_only}->{$prop}
127     ? $self->{var}->{db}->{read_only}->{$prop}
128     : $self->{var}->{db}->{read_only}->{'#default'};
129     \%lock;
130     };
131    
132     require SuikaWiki::DB::Logical;
133     $self->{db} = new SuikaWiki::DB::Logical;
134    
135     $self->__raise_event (name => 'database_loaded');
136     }
137    
138 wakaba 1.3 =item $wiki->view_in_mode (%opt)
139    
140     Doing main process in accordance to the mode.
141    
142     Actually, this method only raises an event of 'view_in_mode'.
143     So that "doing main process" code should be registered as an event procedure
144     of 'view_in_mode'.
145    
146     =cut
147    
148     sub view_in_mode ($%) {
149     my ($self, %opt) = @_;
150     $self->__raise_event (name => 'view_in_mode', argv => [\%opt]);
151     }
152    
153 wakaba 1.7 # obsolete
154 wakaba 1.1 sub __raise_event ($%) {
155     my ($self, %o) = @_;
156     for (@{$self->{event}->{$o{name}}||[]}) {
157 wakaba 1.2 &{$_} ($self, @{$o{argv}||[]});
158 wakaba 1.1 ## TODO: canceling
159     }
160     1;
161     }
162    
163 wakaba 1.7 sub ___raise_event ($$$;%) {
164     my ($self, $name, $argv, %opt) = @_;
165     my $event = {cancel => 0, name => $name, ($opt{argv_name}||$name) => $argv};
166 wakaba 1.5 for (@{$self->{event}->{$name}}) {
167     $_->($self, $event);
168     return 0 if $event->{cancel};
169     }
170     return 1;
171     }
172    
173 wakaba 1.8 =item $uri = $wiki->uri_reference (%option)
174    
175     Returning URI reference that refers the wiki or a WikiPage.
176    
177     Load {input} before calling this method or specify appropriate C<wiki_uri>
178     option to get proper result.
179    
180     One or two URI reference(s) is returned as C<URI> object.
181     See C<base> option.
182    
183     Available options:
184    
185     =over 4
186    
187     =item anchor_no => positive-integer (default: none)
188    
189     Numeral anchor index. With this option, C<fragment> option
190     is ignored.
191    
192     =item base => URI reference (default: none)
193    
194     Base URI reference. C<wantarray ? (relative, absolute) : relative> is
195     returned when C<base> is specified. Otherwise, C<(absolute, absolute)>
196     is returned.
197    
198     =item fragment => URI reference fragment (default: none)
199    
200     URI refernece fragment. This option value MUST be encoded
201     by URI escape encoding.
202    
203     =item mode => mode-name (default: "default")
204    
205     WikiView mode in which referred.
206 wakaba 1.2
207 wakaba 1.8 =item page => [WikiName] (default: none)
208    
209     WikiName to that WikiPage URI reference is referring.
210    
211     =item param => {name1 => value1, name2 => value2,...} (default: none)
212    
213     Additional query parameters. Names and values are automatically
214     encoded by URI escape encoding if necessary.
215    
216     =item up_to_date => 1/0 (default: 0)
217    
218     "Up-to-date" URI query parameter for cheating cache.
219    
220     =item wiki_uri => URI reference (default: auto)
221    
222     A base URI reference referring the wiki itself.
223    
224     =item with_lm => 1/0 (default: 0)
225    
226     "Last modified" URI query parameter for chating WWW browser history.
227    
228     =back
229 wakaba 1.2
230     =cut
231    
232 wakaba 1.6 sub uri_reference ($;%) {
233 wakaba 1.8 my ($self, %opt) = @_; ## Note: $opt{wiki_uri} must be a URI(.pm) if any.
234     my $uri = $opt{wiki_uri} || $self->___get_wiki_uri;
235 wakaba 1.6
236     ## SuikaWiki 3.0 format
237     my $query_param = qr/[^0-9A-Za-z_.-]/;
238 wakaba 1.7 my @param = map {my $n = $_; $n =~ tr/_/-/;
239     $self->___uri_escape_encode ($n, $query_param).'='.
240 wakaba 1.6 $self->___uri_escape_encode ($opt{param}->{$_}, $query_param)}
241     keys %{$opt{param}};
242     push @param, 'mode='.$self->___uri_escape_encode ($opt{mode}, $query_param)
243     if $opt{mode};
244     push @param, 'x-d='.time if $opt{up_to_date};
245     if ($opt{page}) {
246     if ($opt{with_lm} and ref $self->{db}) {
247     push @param, 'x-lm='
248     . $self->___uri_escape_encode
249     ($self->{db}->get (lastmodified => $opt{page}),
250     $query_param);
251     }
252     ## TODO: Common WikiName interface
253     my $page = join '//', @{$opt{page}};
254     if (@param) {
255     ## TODO: Encode by $wiki->{config}->{charset}->{uri_param_encode}
256     unshift @param, 'mypage='.$self->___uri_escape_encode
257     ($page, $query_param);
258     push @param, '_charset_='.$self->{config}->{charset}->{uri_param_encode};
259     ## TODO: downgrade to &
260     $uri->query (join ';', @param);
261     } else {
262     ## TODO: Encode by $wiki->{config}->{charset}->{uri_query_encode}
263     $uri->query ($self->___uri_escape_encode ($page, $query_param));
264     }
265     } elsif (@param) {
266     push @param, '_charset_='.$self->{config}->{charset}->{uri_param_encode};
267     $uri->query (join ';', @param);
268     }
269    
270     if ($opt{anchor_no}) {
271     $uri->fragment ('anchor-'.$opt{anchor_no});
272     } elsif ($opt{fragment}) {
273     $uri->fragment ($opt{fragment});
274     }
275    
276     if (defined $opt{base}) {
277     $opt{base} = $self->{input}->request_uri
278     if ref $self->{input} and not ref $opt{base} and $opt{base} eq '1';
279     return wantarray ? ($uri->rel ($opt{base}), $uri) : $uri->rel ($opt{base});
280     } else {
281     return ($uri, $uri);
282     }
283     }
284    
285 wakaba 1.8 =item 1/0 = $wiki->uri_is_part_of_wiki ($uri-reference)
286    
287     Check whether given URI reference is "part of" the wiki.
288    
289     =cut
290    
291 wakaba 1.6 sub uri_is_part_of_wiki ($$) {
292     my ($self, $uri) = @_;
293     my $wiki_uri = ''.$self->___get_wiki_uri;
294 wakaba 1.8 $uri = URI->new (substr ($uri, 0, length ($wiki_uri)));
295     $uri eq $wiki_uri ? 1 : 0;
296 wakaba 1.6 }
297    
298     sub ___get_wiki_uri ($) {
299     my ($self) = shift;
300     my $uri;
301     if (ref $self->{___uri}) {
302     $uri = $self->{___uri}->clone;
303     } elsif (ref $self->{input}) {
304     $uri = $self->{input}->request_uri (no_path_info => 1, no_query => 1);
305     $self->{___uri} = $uri->clone;
306     } else {
307     $uri = URI->new;
308     }
309     $uri;
310     }
311    
312     sub ___uri_escape_encode ($$;$) {
313     my ($self, $s, $char) = @_;
314     $char ||= qr([^0-9A-Za-z_.!~*'();/?:\@&=+\$,-]);
315     ## TODO:
316     # require Encode;
317     # $s = Encode::decode ('utf8', $s);
318     $s =~ s/($char)/sprintf '%%%02X', ord $1/ge;
319     $s;
320     }
321    
322 wakaba 1.8 =item $wiki->close_db
323    
324     Closing WikiDB (C<$wiki->{db}>).
325    
326     Although this method is automatically called by C<< $wiki->exit >>,
327     it is good practice to explicitly close something opened explicitly.
328    
329     =cut
330    
331 wakaba 1.5 sub close_db ($) {
332     my $self = shift;
333     $self->{db}->close if ref $self->{db};
334     delete $self->{db};
335     }
336    
337 wakaba 1.8 =item $wiki->close_view
338    
339     Closing WikiView manager (C<< $wiki->close_view >>).
340    
341     =cut
342    
343 wakaba 1.5 sub close_view ($) {
344     my $self = shift;
345     $self->{view}->exit if ref $self->{view};
346     delete $self->{view};
347     }
348    
349 wakaba 1.8 =item $wiki->close_plugin
350    
351     Closing WikiPlugin manager (C<< $wiki->{plugin} >>).
352     Note that this method does not unload WikiPlugin modules.
353     (They are "merged" to script namespace so that unloading them
354     is almost impossible.)
355    
356     =cut
357    
358 wakaba 1.5 sub close_plugin ($) {
359     my $self = shift;
360     $self->{plugin}->exit if ref $self->{plugin};
361     delete $self->{plugin};
362     }
363    
364 wakaba 1.8 =item $wiki->close_input
365    
366     Closing input manager (C<< $wiki->{input} >>).
367    
368     =cut
369    
370 wakaba 1.5 sub close_input ($) {
371     my $self = shift;
372     $self->{input}->exit if ref $self->{input};
373     delete $self->{input};
374     }
375    
376 wakaba 1.8 =item 1/0 = $wiki->exit
377 wakaba 1.1
378 wakaba 1.8 Exitign the wiki. This method closes input manager, WikiDB manager,
379     WikiView manager and WikiPlugin manager after C<close> event is raised.
380     Note that C<close> event handler can "cancel" exiting,
381     it makes this method return C<0>.
382    
383     This method is automatically called before C<$wiki> is destoroyed.
384 wakaba 1.1
385     =cut
386    
387     sub exit ($) {
388     my $self = shift;
389 wakaba 1.5 return 0 unless $self->___raise_event (name => 'close');
390 wakaba 1.7 $self->close_input;
391 wakaba 1.5 $self->close_db;
392     $self->close_view;
393     $self->close_plugin;
394     $self->{exited} = 1;
395     1;
396 wakaba 1.1 }
397    
398 wakaba 1.8 ## TODO: Provides "cancelable" to close event.
399    
400 wakaba 1.1 sub DESTROY ($) {
401     my $self = shift;
402 wakaba 1.5 $self->exit unless $self->{exited};
403 wakaba 1.1 }
404    
405     =back
406    
407     =head1 PUBLIC PROPERTIES
408    
409     =over 4
410    
411 wakaba 1.2 =item $wiki->{config}
412    
413     Persistent wiki configureation parameters
414     (that is not changed with the situation when is who accessing in what way)
415    
416     =over 4
417    
418     =item ->{charset}->{internal} = <IANA charset name (in lower case)>
419    
420     Character encoding scheme used in wiki implementation
421    
422     =item ->{charset}->{output} = <IANA charset name (in lower case)>
423    
424     Default character encoding scheme used to output content
425    
426 wakaba 1.5 =item ->{debug}->{$category} = 1/0 (Default 0)
427    
428     Debug mode
429    
430     Categories:
431    
432     =over 4
433    
434     =item db
435    
436     WikiDatabase related features
437    
438 wakaba 1.7 =item general
439    
440     Generic.
441    
442     =item view
443    
444     WikiView related.
445    
446 wakaba 1.5 =back
447    
448 wakaba 1.2 =item ->{entity}->{expires}->{$rulename} = {delta => $seconds}
449    
450     How long outputed entity will be fresh.
451    
452     =item ->{lock}
453 wakaba 1.1
454     Default (prototype) properties to give SuikaWiki::DB::Util::Lock
455    
456 wakaba 1.2 =item ->{page}->{ $name }
457    
458     WikiPage which has feature of $name
459    
460     =item ->{path_to}->{ $name }
461 wakaba 1.1
462     Filesystem path (or path fragment) to $name
463    
464 wakaba 1.2 =back
465    
466 wakaba 1.1 =item $wiki->{db}
467    
468     Wiki main database
469    
470 wakaba 1.8 =item $wiki->{driver_name}
471    
472     Product name of the WikiDriver.
473    
474     For interoperability, only alphanumeric characters and limited symbols
475     (those allowed in RFC 2616 token) should be used as parts of product name.
476    
477     =item $wiki->{driver_version}
478    
479     WikiDriver version in string.
480    
481     For interoperability, only alphanumeric characters and limited symbols
482     (those allowed in RFC 2616 token) should be used as parts of product name.
483    
484     =item $wiki->{engine_name} (Read only)
485    
486     SuikaWiki WikiEngine name
487    
488     =item $wiki->{engine_version} (Read only)
489    
490     SuikaWiki WikiEngine version
491    
492 wakaba 1.1 =item @{$wiki->{event}->{ $event_name }}
493    
494     Event handling procedures
495    
496 wakaba 1.2 Standarized event names:
497    
498     =over 4
499    
500     =item database_loaded
501    
502     When WikiDatabase manager is loaded. This event handler is typically
503     used to set database property module for SuikaWiki::DB::Logical.
504    
505     =item plugin_manager_loaded
506    
507     When WikiPlugin manager is loaded. Note that plugins themselves are not
508     loaded yet.
509    
510     =item setting_initial_variables
511    
512     On the process to set per-access variables.
513     This event is raised before other core modules such as WikiDatabase
514     or WikiPlugin are loaded.
515    
516 wakaba 1.7 =item view_error
517    
518     Something wrong with or something useful message is available from WikiView
519     manager.
520    
521     =item view_in_mode
522    
523     C<view_in_mode> method is called.
524    
525 wakaba 1.2 =back
526    
527     =item $wiki->{var}
528    
529     Non-persistent wiki variable options
530     (that might vary with context such as caller's argument values)
531    
532     =over 4
533    
534 wakaba 1.6 =item ->{client}->{downgrade}->{ $feature } = $parameter
535    
536     Whether downgrade is required. See C<Downgrade> plugin module.
537    
538 wakaba 1.2 =item ->{client}->{used_for_negotiation} = [<HTTP field name>s]
539    
540     HTTP (request) header field names used to select variable content.
541     This value will be used to generate HTTP Vary header field.
542    
543     =item ->{client}->{user_agent_name} = <HTTP User-Agent field body value>
544    
545     User agent name provided by such ways as User-Agent field (in HTTP)
546     or HTTP_USER_AGENT meta variable (in HTTP-CGI).
547    
548     =item ->{db}->{lock_prop} = sub ($prop)
549    
550     Function returning hash reference of lock options
551     (that will be passed to SuikaWiki::DB::Util::Lock->new).
552    
553     $prop, an argument to the function, is a database property name.
554    
555     =item ->{db}->{read_only}->{ $prop } = 1/0
556    
557     Whether the database property named as $prop is opened in read only
558     mode or not. Special property name of '#default' is used to set
559     the default value referred when {read_only}->{$prop} is not specified
560     explicily.
561    
562     Note that this value must be set before the instance of database property
563     is loaded.
564    
565 wakaba 1.5 =item ->{error} = [{description => Error 1}, {description => Error 2},...]
566    
567     Trapped errors.
568    
569 wakaba 1.2 =item ->{input}
570    
571     Instance of input parameter interface (such as SuikaWiki::Input::HTTP)
572    
573     =item ->{mode} = mode name
574    
575     Wiki mode name
576    
577     =item ->{page} = [page]
578    
579     WikiPage being referred
580    
581     =back
582    
583     =item $wiki->{view}
584    
585     WikiView implementation (an instance of SuikaWiki::View::Implementation)
586    
587 wakaba 1.1 =cut
588    
589     =head1 LICENSE
590    
591 wakaba 1.8 Copyright 2003-2004 Wakaba <w@suika.fam.cx>. All rights reserved.
592 wakaba 1.1
593     This program is free software; you can redistribute it and/or
594     modify it under the same terms as Perl itself.
595    
596     =cut
597    
598 wakaba 1.8 1; # $Date: 2004/01/16 08:04:59 $

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24  
Google Analytics is used in this page; Cookies are used. 忍者AdMax is used in this page; Cookies are used. Privacy policy.