/[suikacvs]/webroot/swe/lib/SWE/Object/Document.pm
Suika

Contents of /webroot/swe/lib/SWE/Object/Document.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.15 - (hide annotations) (download)
Wed Sep 23 14:16:24 2009 UTC (16 years, 7 months ago) by wakaba
Branch: MAIN
CVS Tags: HEAD
Changes since 1.14: +8 -2 lines
++ swe/lib/SWE/Object/ChangeLog	23 Sep 2009 14:15:25 -0000
	* Document.pm (name): Separated from |title|.

2009-09-23  Wakaba  <wakaba@suika.fam.cx>

++ swe/lib/suikawiki/ChangeLog	23 Sep 2009 14:16:10 -0000
	* main.pl: Use |name| method instead of |title| method for the
	|neighbors| view, otherwise JS can't construct the URL for the
	linked page.

2009-09-23  Wakaba  <wakaba@suika.fam.cx>

1 wakaba 1.1 package SWE::Object::Document;
2     use strict;
3     use warnings;
4 wakaba 1.7 use SWE::Lang qw/%ContentMediaType/;
5     use UNIVERSAL::require;
6 wakaba 1.1
7     sub new ($%) {
8     my $class = shift;
9     my $self = bless {@_}, $class;
10    
11     return $self;
12     }
13    
14 wakaba 1.3 sub new_id ($%) {
15     my $self = shift->new (@_);
16    
17 wakaba 1.4 ## NOTE: MUST be executed in names_lock.
18    
19 wakaba 1.3 my $idgen = $self->db->id;
20     my $id = $idgen->get_next_id;
21     $self->{id} = $id;
22    
23     return $self;
24     } # new_id
25    
26 wakaba 1.12 sub db ($) { $_[0]->{db} }
27 wakaba 1.1
28 wakaba 1.12 sub repo ($) { $_[0]->{repo} }
29    
30     sub id ($) { $_[0]->{id} }
31 wakaba 1.1
32 wakaba 1.7 sub reblessed : lvalue { $_[0]->{reblessed} }
33    
34     sub rebless ($) {
35     my $self = shift;
36     return if $self->reblessed;
37    
38 wakaba 1.9 my $id = $self->id;
39     my $module;
40     if (defined $id) {
41     my $ct = $self->content_media_type;
42     $module = $ContentMediaType{$ct}->{module} || $ContentMediaType{'text/x-suikawiki'}->{module};
43     } else {
44     $module = 'SWE::Object::Document::NotYet';
45     }
46 wakaba 1.7 $module->require or die $@;
47     bless $self, $module;
48    
49     $self->reblessed = 1;
50     }
51    
52 wakaba 1.10 ## ------ Metadata ------
53    
54 wakaba 1.8 sub prop ($) {
55     my $self = shift;
56 wakaba 1.12 return $self->{prop} ||= do {
57     $self->prop_untainted = 0 unless $self->locked;
58     $self->db->id_prop->get_data ($self->id);
59     };
60 wakaba 1.8 } # prop
61    
62 wakaba 1.13 sub prop_untainted ($) : lvalue { $_[0]->{prop_untainted} }
63 wakaba 1.12
64     sub untainted_prop ($) {
65     my $self = shift;
66     delete $self->{prop} unless $self->prop_untainted;
67 wakaba 1.13 $self->prop_untainted = 1;
68 wakaba 1.12 return $self->prop;
69     } # untainted_prop
70    
71     sub save_prop ($) {
72     my $self = shift;
73    
74     $self->lock;
75    
76     unless ($self->prop_untainted) {
77 wakaba 1.14 require Carp;
78     die "Can't save a tainted prop object" . Carp::longmess ();
79 wakaba 1.12 }
80    
81     my $prop = $self->prop or die "Can't save an uncreated prop object";
82     $self->db->id_prop->set_data ($self->id => $prop);
83    
84     $self->unlock;
85     } # save_prop
86    
87 wakaba 1.7 sub content_media_type ($) {
88 wakaba 1.8 my $self = shift;
89     return $self->prop->{'content-type'} // 'text/x-suikawiki';
90     } # content_media_type
91 wakaba 1.7
92 wakaba 1.1 sub associate_names ($$%) {
93     my ($self, $names, %args) = @_;
94    
95     ## NOTE: names_lock MUST be executed before the invocation.
96    
97     my $id = $self->id;
98     my $time = $args{time} || time;
99     my $sw3_pages = $self->{sw3_pages}; ## TODO: ...
100    
101     my $vc = $self->db->vc;
102    
103     my $name_prop_db = $self->{name_prop_db}; ## TODO: ...
104     local $name_prop_db->{version_control} = $vc;
105    
106     my $name_history_db = $self->db->name_history;
107     local $name_history_db->{version_control} = $vc;
108    
109     for my $name (keys %$names) {
110     my $name_props = $name_prop_db->get_data ($name);
111     unless (defined $name_props) {
112     my $sw3id = $sw3_pages->get_data ($name);
113     main::convert_sw3_page ($sw3id => $name); ## TODO: ...
114    
115     $name_props = $name_prop_db->get_data ($name);
116     unless (defined $name_props) {
117     $name_history_db->append_data ($name => [$time, 'c']);
118     }
119     }
120    
121     push @{$name_props->{id} ||= []}, $id;
122     $name_props->{name} = $name;
123     $name_prop_db->set_data ($name => $name_props);
124    
125     $name_history_db->append_data ($name => [$time, 'a', $id]);
126     }
127    
128     my $user = $args{user} || '(anon)';
129     $vc->commit_changes ("id=$id created by $user");
130     } # associate_names
131    
132 wakaba 1.10 sub title ($) {
133     my $self = shift;
134    
135     my $prop = $self->prop;
136    
137     my $title = $prop->{title};
138     return $title if defined $title and length $title;
139    
140 wakaba 1.15 return $self->name;
141 wakaba 1.10 } # title
142 wakaba 1.15
143     sub name ($) {
144     my $self = shift;
145    
146     my $prop = $self->prop;
147     return [keys %{$prop->{name}}]->[0] // ''; ## XXXTODO: title-type
148     } # name
149 wakaba 1.10
150     ## ------ Indexing and Graph ------
151    
152 wakaba 1.2 sub update_tfidf ($$) {
153     my ($self, $doc) = @_; ## TODO: $doc should not be an argument
154    
155     ## It is REQUIRED to lock the $id before the invocation of this
156     ## method to keep the consistency of tfidf data for the $id.
157    
158     my $id = $self->id;
159    
160     my $tfidf_db = $self->db->id_tfidf;
161    
162     require SWE::Data::FeatureVector;
163    
164     my $deleted_terms = SWE::Data::FeatureVector->parse_stringref
165     ($tfidf_db->get_data ($id))->as_key_hashref;
166    
167     my $tc = $doc->document_element->text_content;
168    
169     ## TODO: use element semantics...
170    
171     my $orig_tfs = {};
172     my $all_terms = 0;
173     main::for_unique_words ($tc => sub {
174     $orig_tfs->{$_[0]} = $_[1];
175     $all_terms += $_[1];
176     }); ## TODO: XXX
177    
178     my $names_index_db = $self->db->name_inverted_index;
179     $names_index_db->lock;
180    
181     my $idgen = $self->db->id;
182     my $doc_number = $idgen->get_last_id;
183    
184     my $terms = SWE::Data::FeatureVector->new;
185     for my $term (keys %$orig_tfs) {
186     my $n_tf = $orig_tfs->{$term} / $all_terms;
187    
188     my $df = $names_index_db->get_count ($term);
189     my $idf = log ($doc_number / ($df + 1));
190    
191     my $tfidf = $n_tf * $idf;
192    
193     $terms->set_tfidf ($term, $tfidf);
194     $names_index_db->add_data ($term => $id => $tfidf);
195    
196     delete $deleted_terms->{$term};
197     }
198    
199     for my $term (keys %$deleted_terms) {
200     $names_index_db->delete_data ($term, $id);
201     }
202    
203     $tfidf_db->set_data ($id => \( $terms->stringify ));
204     } # update_tfidf
205    
206 wakaba 1.10 sub get_or_create_graph_node ($) {
207     my $self = shift;
208    
209 wakaba 1.12 $self->lock;
210 wakaba 1.10
211 wakaba 1.12 my $id_prop = $self->untainted_prop or do {
212     $self->unlock;
213 wakaba 1.14 die "Can't obtain untainted prop object";
214 wakaba 1.12 };
215 wakaba 1.10
216 wakaba 1.12 my $graph = $self->repo->graph;
217 wakaba 1.10 my $node;
218     my $node_id = $id_prop->{node_id};
219     if (defined $node_id) {
220     $node = $graph->get_node_by_id ($node_id);
221     } else {
222 wakaba 1.12 $node = $graph->create_node ($self->id);
223 wakaba 1.10 $node_id = $node->id;
224    
225     $id_prop->{node_id} = $node_id;
226 wakaba 1.12 $self->save_prop;
227 wakaba 1.10 }
228    
229 wakaba 1.12 $self->unlock;
230    
231 wakaba 1.10 return $node;
232     } # get_or_create_graph_node
233    
234     # ------ Locking ------
235    
236 wakaba 1.5 sub lock ($) {
237     my $self = shift;
238 wakaba 1.11 my $lock = $self->{lock} ||= $self->db->id_lock->get_lock ($self->id);
239 wakaba 1.14 $self->{lock_n}++ or $lock->lock;
240 wakaba 1.5 } # lock
241    
242     sub unlock ($) {
243     my $self = shift;
244     my $lock = $self->{lock};
245     $self->{lock_n}--;
246     if ($lock and $self->{lock_n} <= 0) {
247     $lock->unlock;
248     delete $self->{lock};
249     delete $self->{lock_n};
250 wakaba 1.12 delete $self->{prop_untainted};
251 wakaba 1.5 }
252     } # unlock
253 wakaba 1.12
254     sub locked ($) {
255 wakaba 1.14 return (($_[0]->{lock_n} // 0) > 0);
256 wakaba 1.12 } # locked
257 wakaba 1.10
258     # ------ Format Convertion ------
259 wakaba 1.5
260 wakaba 1.8 sub to_text ($) {
261     my $self = shift;
262    
263     return $self->{content_db}->get_data ($self->id); # XXX
264     } # to_text
265    
266     sub to_text_media_type ($) {
267     my $self = shift;
268     return $self->content_media_type;
269     } # to_text_media_type
270    
271     sub to_xml_media_type ($) {
272     return undef;
273     } # to_xml_media_type
274    
275     sub to_xml ($) {
276     return undef;
277     } # to_xml
278    
279     sub to_html_fragment ($) {
280     return (undef, undef);
281     } # to_html_fragment
282 wakaba 1.6
283 wakaba 1.1 1;

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24