/[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.9 - (hide annotations) (download)
Sun Feb 8 08:56:45 2004 UTC (21 years, 5 months ago) by wakaba
Branch: MAIN
Changes since 1.8: +9 -4 lines
(name): New method

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.9 our $VERSION = do{my @r=(q$Revision: 1.8 $=~/\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 wakaba 1.9 my $page = $opt{page}->stringify (wiki => $self);
253 wakaba 1.6 if (@param) {
254     ## TODO: Encode by $wiki->{config}->{charset}->{uri_param_encode}
255     unshift @param, 'mypage='.$self->___uri_escape_encode
256     ($page, $query_param);
257     push @param, '_charset_='.$self->{config}->{charset}->{uri_param_encode};
258     ## TODO: downgrade to &
259     $uri->query (join ';', @param);
260     } else {
261     ## TODO: Encode by $wiki->{config}->{charset}->{uri_query_encode}
262     $uri->query ($self->___uri_escape_encode ($page, $query_param));
263     }
264     } elsif (@param) {
265     push @param, '_charset_='.$self->{config}->{charset}->{uri_param_encode};
266     $uri->query (join ';', @param);
267     }
268    
269     if ($opt{anchor_no}) {
270     $uri->fragment ('anchor-'.$opt{anchor_no});
271     } elsif ($opt{fragment}) {
272     $uri->fragment ($opt{fragment});
273     }
274    
275     if (defined $opt{base}) {
276     $opt{base} = $self->{input}->request_uri
277     if ref $self->{input} and not ref $opt{base} and $opt{base} eq '1';
278     return wantarray ? ($uri->rel ($opt{base}), $uri) : $uri->rel ($opt{base});
279     } else {
280     return ($uri, $uri);
281     }
282     }
283    
284 wakaba 1.8 =item 1/0 = $wiki->uri_is_part_of_wiki ($uri-reference)
285    
286     Check whether given URI reference is "part of" the wiki.
287    
288     =cut
289    
290 wakaba 1.6 sub uri_is_part_of_wiki ($$) {
291     my ($self, $uri) = @_;
292     my $wiki_uri = ''.$self->___get_wiki_uri;
293 wakaba 1.8 $uri = URI->new (substr ($uri, 0, length ($wiki_uri)));
294     $uri eq $wiki_uri ? 1 : 0;
295 wakaba 1.6 }
296    
297     sub ___get_wiki_uri ($) {
298     my ($self) = shift;
299     my $uri;
300     if (ref $self->{___uri}) {
301     $uri = $self->{___uri}->clone;
302     } elsif (ref $self->{input}) {
303     $uri = $self->{input}->request_uri (no_path_info => 1, no_query => 1);
304     $self->{___uri} = $uri->clone;
305     } else {
306     $uri = URI->new;
307     }
308     $uri;
309     }
310    
311     sub ___uri_escape_encode ($$;$) {
312     my ($self, $s, $char) = @_;
313     $char ||= qr([^0-9A-Za-z_.!~*'();/?:\@&=+\$,-]);
314     ## TODO:
315     # require Encode;
316     # $s = Encode::decode ('utf8', $s);
317     $s =~ s/($char)/sprintf '%%%02X', ord $1/ge;
318     $s;
319     }
320    
321 wakaba 1.9 sub name ($$%) {
322     require SuikaWiki::Name;
323     my ($wiki, $name, %opt) = @_;
324     SuikaWiki::Name->new ($name, wiki => $wiki, %opt);
325     }
326    
327 wakaba 1.8 =item $wiki->close_db
328    
329     Closing WikiDB (C<$wiki->{db}>).
330    
331     Although this method is automatically called by C<< $wiki->exit >>,
332     it is good practice to explicitly close something opened explicitly.
333    
334     =cut
335    
336 wakaba 1.5 sub close_db ($) {
337     my $self = shift;
338     $self->{db}->close if ref $self->{db};
339     delete $self->{db};
340     }
341    
342 wakaba 1.8 =item $wiki->close_view
343    
344     Closing WikiView manager (C<< $wiki->close_view >>).
345    
346     =cut
347    
348 wakaba 1.5 sub close_view ($) {
349     my $self = shift;
350     $self->{view}->exit if ref $self->{view};
351     delete $self->{view};
352     }
353    
354 wakaba 1.8 =item $wiki->close_plugin
355    
356     Closing WikiPlugin manager (C<< $wiki->{plugin} >>).
357     Note that this method does not unload WikiPlugin modules.
358     (They are "merged" to script namespace so that unloading them
359     is almost impossible.)
360    
361     =cut
362    
363 wakaba 1.5 sub close_plugin ($) {
364     my $self = shift;
365     $self->{plugin}->exit if ref $self->{plugin};
366     delete $self->{plugin};
367     }
368    
369 wakaba 1.8 =item $wiki->close_input
370    
371     Closing input manager (C<< $wiki->{input} >>).
372    
373     =cut
374    
375 wakaba 1.5 sub close_input ($) {
376     my $self = shift;
377     $self->{input}->exit if ref $self->{input};
378     delete $self->{input};
379     }
380    
381 wakaba 1.8 =item 1/0 = $wiki->exit
382 wakaba 1.1
383 wakaba 1.8 Exitign the wiki. This method closes input manager, WikiDB manager,
384     WikiView manager and WikiPlugin manager after C<close> event is raised.
385     Note that C<close> event handler can "cancel" exiting,
386     it makes this method return C<0>.
387    
388     This method is automatically called before C<$wiki> is destoroyed.
389 wakaba 1.1
390     =cut
391    
392     sub exit ($) {
393     my $self = shift;
394 wakaba 1.5 return 0 unless $self->___raise_event (name => 'close');
395 wakaba 1.7 $self->close_input;
396 wakaba 1.5 $self->close_db;
397     $self->close_view;
398     $self->close_plugin;
399     $self->{exited} = 1;
400     1;
401 wakaba 1.1 }
402    
403 wakaba 1.8 ## TODO: Provides "cancelable" to close event.
404    
405 wakaba 1.1 sub DESTROY ($) {
406     my $self = shift;
407 wakaba 1.5 $self->exit unless $self->{exited};
408 wakaba 1.1 }
409    
410     =back
411    
412     =head1 PUBLIC PROPERTIES
413    
414     =over 4
415    
416 wakaba 1.2 =item $wiki->{config}
417    
418     Persistent wiki configureation parameters
419     (that is not changed with the situation when is who accessing in what way)
420    
421     =over 4
422    
423     =item ->{charset}->{internal} = <IANA charset name (in lower case)>
424    
425     Character encoding scheme used in wiki implementation
426    
427     =item ->{charset}->{output} = <IANA charset name (in lower case)>
428    
429     Default character encoding scheme used to output content
430    
431 wakaba 1.5 =item ->{debug}->{$category} = 1/0 (Default 0)
432    
433     Debug mode
434    
435     Categories:
436    
437     =over 4
438    
439     =item db
440    
441     WikiDatabase related features
442    
443 wakaba 1.7 =item general
444    
445     Generic.
446    
447     =item view
448    
449     WikiView related.
450    
451 wakaba 1.5 =back
452    
453 wakaba 1.2 =item ->{entity}->{expires}->{$rulename} = {delta => $seconds}
454    
455     How long outputed entity will be fresh.
456    
457     =item ->{lock}
458 wakaba 1.1
459     Default (prototype) properties to give SuikaWiki::DB::Util::Lock
460    
461 wakaba 1.2 =item ->{page}->{ $name }
462    
463     WikiPage which has feature of $name
464    
465     =item ->{path_to}->{ $name }
466 wakaba 1.1
467     Filesystem path (or path fragment) to $name
468    
469 wakaba 1.2 =back
470    
471 wakaba 1.1 =item $wiki->{db}
472    
473     Wiki main database
474    
475 wakaba 1.8 =item $wiki->{driver_name}
476    
477     Product name of the WikiDriver.
478    
479     For interoperability, only alphanumeric characters and limited symbols
480     (those allowed in RFC 2616 token) should be used as parts of product name.
481    
482     =item $wiki->{driver_version}
483    
484     WikiDriver version in string.
485    
486     For interoperability, only alphanumeric characters and limited symbols
487     (those allowed in RFC 2616 token) should be used as parts of product name.
488    
489     =item $wiki->{engine_name} (Read only)
490    
491     SuikaWiki WikiEngine name
492    
493     =item $wiki->{engine_version} (Read only)
494    
495     SuikaWiki WikiEngine version
496    
497 wakaba 1.1 =item @{$wiki->{event}->{ $event_name }}
498    
499     Event handling procedures
500    
501 wakaba 1.2 Standarized event names:
502    
503     =over 4
504    
505     =item database_loaded
506    
507     When WikiDatabase manager is loaded. This event handler is typically
508     used to set database property module for SuikaWiki::DB::Logical.
509    
510     =item plugin_manager_loaded
511    
512     When WikiPlugin manager is loaded. Note that plugins themselves are not
513     loaded yet.
514    
515     =item setting_initial_variables
516    
517     On the process to set per-access variables.
518     This event is raised before other core modules such as WikiDatabase
519     or WikiPlugin are loaded.
520    
521 wakaba 1.7 =item view_error
522    
523     Something wrong with or something useful message is available from WikiView
524     manager.
525    
526     =item view_in_mode
527    
528     C<view_in_mode> method is called.
529    
530 wakaba 1.2 =back
531    
532     =item $wiki->{var}
533    
534     Non-persistent wiki variable options
535     (that might vary with context such as caller's argument values)
536    
537     =over 4
538    
539 wakaba 1.6 =item ->{client}->{downgrade}->{ $feature } = $parameter
540    
541     Whether downgrade is required. See C<Downgrade> plugin module.
542    
543 wakaba 1.2 =item ->{client}->{used_for_negotiation} = [<HTTP field name>s]
544    
545     HTTP (request) header field names used to select variable content.
546     This value will be used to generate HTTP Vary header field.
547    
548     =item ->{client}->{user_agent_name} = <HTTP User-Agent field body value>
549    
550     User agent name provided by such ways as User-Agent field (in HTTP)
551     or HTTP_USER_AGENT meta variable (in HTTP-CGI).
552    
553     =item ->{db}->{lock_prop} = sub ($prop)
554    
555     Function returning hash reference of lock options
556     (that will be passed to SuikaWiki::DB::Util::Lock->new).
557    
558     $prop, an argument to the function, is a database property name.
559    
560     =item ->{db}->{read_only}->{ $prop } = 1/0
561    
562     Whether the database property named as $prop is opened in read only
563     mode or not. Special property name of '#default' is used to set
564     the default value referred when {read_only}->{$prop} is not specified
565     explicily.
566    
567     Note that this value must be set before the instance of database property
568     is loaded.
569    
570 wakaba 1.5 =item ->{error} = [{description => Error 1}, {description => Error 2},...]
571    
572     Trapped errors.
573    
574 wakaba 1.2 =item ->{input}
575    
576     Instance of input parameter interface (such as SuikaWiki::Input::HTTP)
577    
578     =item ->{mode} = mode name
579    
580     Wiki mode name
581    
582     =item ->{page} = [page]
583    
584     WikiPage being referred
585    
586     =back
587    
588     =item $wiki->{view}
589    
590     WikiView implementation (an instance of SuikaWiki::View::Implementation)
591    
592 wakaba 1.1 =cut
593    
594     =head1 LICENSE
595    
596 wakaba 1.8 Copyright 2003-2004 Wakaba <w@suika.fam.cx>. All rights reserved.
597 wakaba 1.1
598     This program is free software; you can redistribute it and/or
599     modify it under the same terms as Perl itself.
600    
601     =cut
602    
603 wakaba 1.9 1; # $Date: 2004/02/01 12:24:05 $

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24