流れ †
検索/フォーマット、検索/ソートはプラグインで。いくつでも何種類でも組み合わせて。
渡るデータはテキスト形式。(そうでなければ中間形式が必要になるし、利用者にとってテキストであることは重要)
検索/フォーマット、検索/ソートは機能で。いくつでも何種類でも組み合わせて。
というわけで、検索/スコアリング、検索/フィルタリングまでが検索特有の処理。
それ以降(検索/フォーマットと検索/ソート)は汎用のプラグインで。
検索/フィルタリングが検索特有の処理。
検索/スコアリング、検索/フォーマット、検索/ソートは汎用の機能で。
ページ生成時 †
検索時 †
検索/クエリーのスコア算出処理にページ側のオブジェクトを渡す→検索/スコアリング
検索時(オプション) †
検索以外にも使えるプラグインで。
検索以外にも使える機能で。
順序も組み合わせも自由。
- 出力用データ生成
検索/フォーマットの機能で検索結果に含めるデータと、検索/ソートに渡すデータ生成。
ページ単位で結果を出すなら、ページごとにスコアを集計、ページごとにデータ生成。 - ソート
検索/ソートの機能で検索結果に含めるデータを並び替え。
検索/ソートの機能で検索結果に含めるデータを並び替え。
→検索/ソートは機能/表に移す。
で、検索結果生成。
HTML化。これはページ/責務。正確にはページの下位にある検索用WikiFormatの責務。
HTML化。これはページ/責務。正確にはページの下位にある検索用記法の責務。
※スコア加算、集計、ソートが分かれているのは繰り返しの単位や範囲が違うから。
※すべて検索/クエリーで作ったオブジェクトの機能で行う。
→プロトタイピング[?]
コード †
package main; use strict; use Smart::Comments; { my @elements; @elements = (Element::PlainText->new(' *** Sample sites ***'), Element::URI->new('http://1.com/3rd'), Element::URI->new('http://3.com/2nd/'), Element::URI->new('http://2.com/1st/')); { ### not sorted, not filtered: my $page = Page->new(@elements); print $page->out(); } print "\n--------\n"; { ### sorted: my $page = Page->new(Element::Container::Sort->new(@elements)); print $page->out(); } print "\n--------\n"; { ### link list: my $page = Page->new(Element::Container::Filter->new(@elements)); print $page->out(); } print "\n--------\n"; { ### link list sorted by label: my $page = Page->new(Element::Container::Sort->new(Element::Container::Filter->new(@elements))); print $page->out(); } print "\n--------\n"; } package Page; sub new { my $class = shift; bless { element => [@_] }, $class; } sub elements { my $self = shift; map { $_->elements() } @{$self->{element}}; } sub out { my $self = shift; join "\n", map { $_->out() } $self->elements(); } sub string { my $self = shift; join '', map { $_->string() } $self->elements(); } package Element::Container::Sort; sub new { my $class = shift; bless { element => [@_] }, $class; } sub elements { my $self = shift; my @r; foreach (@{$self->{element}}){ push @r, $_->elements(); } sort { $a->string() cmp $b->string() } @r; } sub out { my $self = shift; map { $_->out() } $self->elements(); } sub string { my $self = shift; join '', map { $_->string() } $self->elements(); } package Element::Container::Filter; sub new { my $class = shift; bless { element => [@_] }, $class; } sub elements { my $self = shift; my @r; foreach (@{$self->{element}}){ push @r, map { $_->fetch_by('label') =~ m%http://[^/]*/([^/]*)%; ref($_)->new($_->fetch_by('uri'), $1); } grep { $_->isa('Element::URI'); } $_->elements(); } @r; } sub out { my $self = shift; map { $_->out() } $self->elements(); } sub string { my $self = shift; join '', map { $_->string() } $self->elements(); } package Element::URI; sub new { my $class = shift; my($uri, $label) = @_; $label = $label ? $label : $uri; bless { uri => $uri, label => $label }, $class; } sub elements { $_[0]; } sub out { my $self = shift; '<a href="'.$self->{uri}.'">'.$self->{label}.'</a>'; } sub fetch_by { my $self = shift; my($request) = @_; my $r; if ($request eq 'label'){ $r = $self->_label(); } elsif ($request eq 'uri'){ $r = $self->_uri(); } else { $r = $self->string(); } $r; } sub string { my $self = shift; $self->{label}; } sub _uri { my $self = shift; $self->{uri}; } sub _label { my $self = shift; $self->{label}; } package Element::PlainText; sub new { my $class = shift; bless { text => $_[0] }, $class; } sub elements { $_[0]; } sub out { $_[0]->{text}; } sub fetch_by { my $self = shift; $self->string(); } sub string { $_[0]->{text}; }
- ---------------------------------------------
### not sorted, not filtered: *** Sample sites *** <a href="http://1.com/3rd">http://1.com/3rd</a> <a href="http://3.com/2nd/">http://3.com/2nd/</a> <a href="http://2.com/1st/">http://2.com/1st/</a> -------- ### sorted: *** Sample sites *** <a href="http://1.com/3rd">http://1.com/3rd</a> <a href="http://2.com/1st/">http://2.com/1st/</a> <a href="http://3.com/2nd/">http://3.com/2nd/</a> -------- ### link list: <a href="http://1.com/3rd">3rd</a> <a href="http://3.com/2nd/">2nd</a> <a href="http://2.com/1st/">1st</a> -------- ### link list sorted by label: <a href="http://2.com/1st/">1st</a> <a href="http://3.com/2nd/">2nd</a> <a href="http://1.com/3rd">3rd</a> --------