start of SubList filter code
Matt S Trout [Tue, 8 Feb 2011 19:32:44 +0000 (19:32 +0000)]
12 files changed:
lib/SCSite.pm
lib/SCSite/Filter.pm [new file with mode: 0644]
lib/SCSite/LatestPageSet.pm [new file with mode: 0644]
lib/SCSite/Page.pm [new file with mode: 0644]
lib/SCSite/PageSet.pm
lib/SCSite/SubListFilter.pm [new file with mode: 0644]
share/skin/layout.html
t/pages.t
t/pages/error_404.html [new file with mode: 0644]
t/pages/one/withkids.html [new file with mode: 0644]
t/pages/one/withkids/one.md [new file with mode: 0644]
t/pages/one/withkids/two.md [new file with mode: 0644]

index d0a9627..ffa9cb2 100644 (file)
@@ -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 (file)
index 0000000..bbf442a
--- /dev/null
@@ -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 (file)
index 0000000..327fb2c
--- /dev/null
@@ -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 (file)
index 0000000..223b92b
--- /dev/null
@@ -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;
index 559038b..f9db60d 100644 (file)
@@ -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 (file)
index 0000000..8b6f99e
--- /dev/null
@@ -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;
index e85c0de..e459fb3 100644 (file)
@@ -8,10 +8,15 @@
     <div class="title">page title</div>
     <div>
       <ul class="topbar_entries">
-        <li><a class="entry"></a></li>
+        <li><a href="/">Home</a></li>
+        <li><a href="/about">About</a></li>
+        <li><a href="/catalyst">Catalyst</a></li>
+        <li><a href="/servers">Servers</a></li>
+        <li><a href="/services">Professional Services</a></li>
+        <li><a href="/blog">Blogs</a></li>
       </ul>
     <div>
-    <div>
+    <div class="Sidebar">
       <div class="sidebar_segment">
         <h4 class="sidebar_title"></h4>
         <ul class="sidebar_entries">
index adb1d44..3c51571 100644 (file)
--- a/t/pages.t
+++ b/t/pages.t
@@ -7,8 +7,10 @@ sub check_structure {
   $s = { %$s };
   my $body = delete $s->{body};
   like($body, qr/^\s+<p>Some markdown here.<\/p>\s+$/sm, 'Body correct');
+  delete @{$s}{grep /^_/, keys %$s};
   is_deeply($s,
     {
+      created => '',
       title => '--TITLE--',
       description => '--DESCRIPTION--',
       keywords => '--KW1-- --KW2--'
diff --git a/t/pages/error_404.html b/t/pages/error_404.html
new file mode 100644 (file)
index 0000000..51696d6
--- /dev/null
@@ -0,0 +1,6 @@
+<html>
+  <head>
+    <title>404</title>
+  </head>
+  <body>Oops.</body>
+</html>
diff --git a/t/pages/one/withkids.html b/t/pages/one/withkids.html
new file mode 100644 (file)
index 0000000..2d85209
--- /dev/null
@@ -0,0 +1,15 @@
+<html>
+  <head>
+    <title>withkids</title>
+  </head>
+  <body>
+    <h1>withkids test</h1>
+    <div class="SubList">
+      <div class="entry">
+        <div class="entry title" />
+        <div class="entry description" />
+        <div class="entry created" />
+      </div>
+    </div>
+  </body>
+</html>
diff --git a/t/pages/one/withkids/one.md b/t/pages/one/withkids/one.md
new file mode 100644 (file)
index 0000000..3066078
--- /dev/null
@@ -0,0 +1,5 @@
+Title: withkids-one
+description: withkids-one-desc
+created: 2011-02-06
+
+withkids-one-body
diff --git a/t/pages/one/withkids/two.md b/t/pages/one/withkids/two.md
new file mode 100644 (file)
index 0000000..28b399f
--- /dev/null
@@ -0,0 +1,3 @@
+Title: withkids-two
+description: withkids-two-description
+created: 2011-02-07