From: Matt S Trout Date: Tue, 8 Feb 2011 19:32:44 +0000 (+0000) Subject: start of SubList filter code X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=ebd4c292961866999b4502948936e1da7338357c;p=scpubgit%2FSCS.git start of SubList filter code --- diff --git a/lib/SCSite.pm b/lib/SCSite.pm index d0a9627..ffa9cb2 100644 --- a/lib/SCSite.pm +++ b/lib/SCSite.pm @@ -4,27 +4,10 @@ use IO::All; use SCSite::PageSet; use Web::Simple; -{ - package SCSite::Link; use Moo; has $_ => (is => 'ro') for qw(title to); -} - -has _topbar => (is => 'ro', default => sub { [ - map SCSite::Link->new(title => $_->[0], to => $_->[1] ), - map [ /^(.*?)\s+(\S+)$/ ], - split("\n", <<'ENDBAR') -Home / -About /about -News /news -Catalyst /catalyst -Servers /servers -Professional Services /services -Blogs /blog -ENDBAR - ] } -); - has pages => (is => 'lazy'); +has filters => (is => 'lazy'); + has _layout_zoom => (is => 'lazy'); sub default_config { @@ -36,7 +19,13 @@ sub default_config { sub _build_pages { my ($self) = @_; - SCSite::PageSet->new(base_dir => $self->config->{pages_dir}) + SCSite::PageSet->new(base_dir => io->dir($self->config->{pages_dir})) +} + +sub _build_filters { + my ($self) = @_; + require SCSite::SubListFilter; + +{ SubList => SCSite::SubListFilter->new } } sub dispatch_request { @@ -84,13 +73,11 @@ sub _render_page { $zoom->select('.title')->replace_content($page->title) ->select('meta[name=description]')->replace_content($page->description) ->select('meta[name=keywords]')->replace_content($page->keywords) - ->select('.topbar_entries')->repeat_content([ - map { my $e = $_; sub { - $_->select('.entry')->replace_content($e->title) - ->then->set_attribute(href => $e->to) - } } @{$self->_topbar} - ]) ->select('.main')->replace_content(\$page->body) + ->select('.SubList')->collect({ + filter => $self->filters->{SubList}->callback_for($page), + passthrough => 1, + }) ->to_fh } diff --git a/lib/SCSite/Filter.pm b/lib/SCSite/Filter.pm new file mode 100644 index 0000000..bbf442a --- /dev/null +++ b/lib/SCSite/Filter.pm @@ -0,0 +1,26 @@ +package SCSite::Filter; + +use Moo::Role; + +requires '_filter_stream'; + +sub callback_for { + my ($self, @args) = @_; + sub { + my ($stream) = @_; + my $config = $self->_parse_config($stream->peek); + $self->_filter_stream($stream, $config, @args) + } +} + +sub _parse_config { + my ($self, $evt) = @_; + my %config = ( # adapted from CSS::Tiny, extracts -scs- prefix. + map /^\s*-scs-([\w._-]+)\s*:\s*(.*?)\s*$/, + grep { /\S/ } split /\;/, ($evt->{attrs}{style}||'') + ); + s/^'(.*)'$/$1/ for values %config; + \%config; +} + +1; diff --git a/lib/SCSite/LatestPageSet.pm b/lib/SCSite/LatestPageSet.pm new file mode 100644 index 0000000..327fb2c --- /dev/null +++ b/lib/SCSite/LatestPageSet.pm @@ -0,0 +1,21 @@ +package SCSite::LatestPageSet; + +use Moo; + +has _parent => (is => 'ro', required => 1, init_arg => 'parent'); +has _max_entries => (is => 'ro', required => 1, init_arg => 'max_entries'); + +sub flatten { + my ($self) = @_; + my @sorted = sort { + $a->created cmp $b->created + } $self->_parent->flatten; + $self->_max_entries ? @sorted[0..$self->_max_entries-1] : @sorted; +} + +sub map { + my ($self, $mapper) = @_; + [ map $mapper->($_), $self->flatten ] +} + +1; diff --git a/lib/SCSite/Page.pm b/lib/SCSite/Page.pm new file mode 100644 index 0000000..223b92b --- /dev/null +++ b/lib/SCSite/Page.pm @@ -0,0 +1,19 @@ +package SCSite::Page; + +use IO::All; +use Moo; + +has $_ => (is => 'ro') for qw(title description keywords body created); + +has "_$_" => (is => 'ro', init_arg => $_) for qw(page_set path); + +sub children { + my ($self) = @_; + my $ps = $self->_page_set; + (ref $ps)->new( + base_dir => io->dir($ps->base_dir)->catdir($self->_path), + max_depth => 1 + ); +} + +1; diff --git a/lib/SCSite/PageSet.pm b/lib/SCSite/PageSet.pm index 559038b..f9db60d 100644 --- a/lib/SCSite/PageSet.pm +++ b/lib/SCSite/PageSet.pm @@ -1,15 +1,15 @@ package SCSite::PageSet; -{ package SCSite::Page; use Moo; - has $_ => (is => 'ro') for qw(title description keywords body); -} - use IO::All; use Text::MultiMarkdown 'markdown'; use HTML::Zoom; +use Sub::Quote; +use Syntax::Keyword::Gather; +use SCSite::Page; use Moo; has base_dir => (is => 'ro', required => 1); +has max_depth => (is => 'ro', default => quote_sub q{ 0 }); sub get { my ($self, $spec) = @_; @@ -19,20 +19,52 @@ sub get { my @poss = io->dir($self->base_dir)->${\sub { my $io = shift; defined($dir) ? $io->catdir($dir) : $io - }}->filter(sub { $_->filename =~ /\Q${file}\E\.(html|md)/ and $type = $1 }) + }}->filter(sub { + $_->filename =~ /^\Q${file}\E${\$self->_types_re}$/ and $type = $1 + }) ->all_files; die "multiple files found for ${\$spec->{path}}:\n".join "\n", @poss if @poss > 1; - $self->${\"_inflate_${type}"}($poss[0]->all); + return undef unless @poss; + $self->${\"_inflate_${type}"}($spec->{path}, $poss[0]->all); +} + +sub map { + my ($self, $mapper) = @_; + [ map $mapper->($_), $self->flatten ] +} + +sub flatten { + my ($self) = @_; + my %seen; + map { + my ($path, $type) = $_->name =~ /^(.*)${\$self->_types_re}$/; + $self->${\"_inflate_${type}"}( + File::Spec->abs2rel($path, $self->base_dir->name), $_->all + ); + } io->dir($self->base_dir) + ->filter(sub { $_->filename =~ /${\$self->_types_re}$/ }) + ->all_files($self->max_depth) +} + +sub latest { + my ($self, $max) = @_; + require SCSite::LatestPageSet; + SCSite::LatestPageSet->new( + parent => $self, + max_entries => $max, + ); } sub _new_page { - SCSite::Page->new($_[1]) + SCSite::Page->new({ path => $_[1], page_set => $_[0], %{$_[2]} }) } +sub _types_re { qw/\.(html|md)/ } + sub _inflate_html { - my ($self, $html) = @_; - $self->_new_page($self->_extract_from_html($html)); + my ($self, $path, $html) = @_; + $self->_new_page($path, $self->_extract_from_html($html)); } sub _extract_from_html { @@ -41,19 +73,21 @@ sub _extract_from_html { ->select('title')->collect_content({ into => \my @title }) ->select('meta[name=description]')->collect({ into => \my @description }) ->select('meta[name=keywords]')->collect({ into => \my @keywords }) + ->select('meta[name=created]')->collect({ into => \my @created }) ->select('body')->collect_content({ into => \my @body }) ->run; +{ - title => $title[0]->{raw}, - description => $description[0]->{attrs}{content}, - keywords => $keywords[0]->{attrs}{content}, - body => HTML::Zoom->from_events(\@body)->to_html, + title => $title[0]->{raw}||'', + description => $description[0]->{attrs}{content}||'', + keywords => $keywords[0]->{attrs}{content}||'', + created => $created[0]->{attrs}{content}||'', + body => HTML::Zoom->from_events(\@body)->to_html||'', } } sub _inflate_md { - my ($self, $md) = @_; - $self->_new_page($self->_extract_from_md($md)); + my ($self, $path, $md) = @_; + $self->_new_page($path, $self->_extract_from_md($md)); } sub _extract_from_md { diff --git a/lib/SCSite/SubListFilter.pm b/lib/SCSite/SubListFilter.pm new file mode 100644 index 0000000..8b6f99e --- /dev/null +++ b/lib/SCSite/SubListFilter.pm @@ -0,0 +1,21 @@ +package SCSite::SubListFilter; + +use Moo; + +with 'SCSite::Filter'; + +sub _filter_stream { + my ($self, $stream, $config, $page) = @_; + my $max = $config->{max_entries}||undef; # explicit undef (not 0) + $stream->select('.SubList') + ->repeat_content($page->children->latest($max)->map(sub { + my $o = shift; + sub { + $_->select('.entry.title')->replace_content($o->title) + ->select('.entry.description')->replace_content($o->description) + ->select('.entry.created')->replace_content($o->created) + } + })); +} + +1; diff --git a/share/skin/layout.html b/share/skin/layout.html index e85c0de..e459fb3 100644 --- a/share/skin/layout.html +++ b/share/skin/layout.html @@ -8,10 +8,15 @@
page title
-
+