domain support for feeds, factor out sc-specific bits
[scpubgit/SCS.git] / lib / SCSite.pm
old mode 100644 (file)
new mode 100755 (executable)
index 7d821d4..a5266cf
@@ -1,5 +1,9 @@
+#!/usr/bin/env perl
+
 package SCSite;
 
+our $VERSION = '0.001001'; # 0.1.1
+
 use IO::All;
 use SCSite::PageSet;
 use Web::Simple;
@@ -10,10 +14,19 @@ has filters => (is => 'lazy');
 
 has _layout_zoom => (is => 'lazy');
 
+has _feed_configs => (is => 'lazy');
+
+has _feed_generator => (
+  is => 'lazy',
+  handles => { _feed_http_response => 'feed_http_response' },
+);
+
 sub default_config {
   (
-    pages_dir => 'share/content',
-    template_dir => 'share/skin',
+    pages_dir => 'share/pages',
+    template_dir => 'share/templates',
+    static_dir => 'share/static',
+    generate_host => 'www.example.com',
   )
 }
 
@@ -24,18 +37,35 @@ sub _build_pages {
 
 sub _build_filters {
   my ($self) = @_;
-  require SCSite::SubListFilter;
-  require SCSite::SidebarFilter;
   +{
-    map +($_ => "SCSite::${_}Filter"->new_from_site($self)),
-      qw(SubList Sidebar)
+    map {
+      require "SCSite/${_}Filter.pm";
+      +($_ => "SCSite::${_}Filter"->new_from_site($self))
+    } @{$self->config->{filters}}
   }
 }
 
+sub _build__feed_configs {
+  my ($self) = @_;
+  my $f = $self->config->{feeds}||{};
+  $f->{$_}{base} ||= $_ for keys %$f;
+  $f;
+}
+
+sub _build__feed_generator {
+  my ($self) = @_;
+  require SCSite::FeedGenerator;
+  SCSite::FeedGenerator->new(
+    pages => $self->pages,
+  );
+}
+
 sub dispatch_request {
   my $self = shift;
   sub (/feed/**/) {
-    $self->_http_response(500 => 'text/plain' => 'Not implemented');
+    if (my $conf = $self->_feed_configs->{$_[1]}) {
+      $self->_feed_http_response(200 => $conf => $_[PSGI_ENV]);
+    }
   },
   sub (/) {
     $self->_page_http_response(200 => $self->_find_page('index'));
@@ -76,9 +106,19 @@ sub _render_page {
   my $zoom = $self->_layout_zoom;
   my %filters = %{$self->filters};
   $zoom->select('.page.title')->replace_content($page->title)
-       ->select('meta[name=description]')->replace_content($page->description)
-       ->select('meta[name=keywords]')->replace_content($page->keywords)
-       ->select('.main')->replace_content(\$page->body)
+       ->select('.page.subtitle')->${\sub {
+           $page->subtitle
+             ? $_[0]->replace_content($page->subtitle)
+             : $_[0]->replace('')
+         }}
+       ->select('.page.published_at')->replace_content($page->published_at)
+       ->select('meta[name=description]')
+         ->set_attribute(content => $page->description)
+       ->select('meta[name=keywords]')
+         ->set_attribute(content => $page->keywords)
+       ->select('meta[name=created]')
+         ->set_attribute(content => $page->created)
+       ->select('.page.body')->replace_content(\$page->body)
        ->apply(sub {
            foreach my $fname (sort keys %filters) {
              my $cb = $filters{$fname}->callback_for($page);
@@ -100,16 +140,65 @@ sub _build__layout_zoom {
 
 sub run_if_script {
   return $_[0]->to_psgi_app if caller(1);
-  my $class = shift;
-  my @config_keys = keys %{{$class->default_config}};
+  my $self = ref($_[0]) ? $_[0] : $_[0]->new;
+  my @config_keys = keys %{{$self->default_config}};
   require Getopt::Long;
-  my %config;
+  my %config = map +($_ => $ENV{"SCS_${\uc $_}"}), @config_keys;
   Getopt::Long::GetOptions(
     map +("$_=s" => \$config{$_}), @config_keys
   );
   delete $config{$_} for grep !defined($config{$_}), keys %config;
-  my $new = $class->new(config => \%config);
-  $new->run(@_)
+  @{$self->config}{keys %config} = values %config;
+  $self->run(@_)
+}
+
+around _run_cli => sub {
+  my ($orig, $self) = (shift, shift);
+  if (@_ >= 2 and $_[0] eq 'dev') {
+    require SCSite::DevMode;
+    Moo::Role->apply_roles_to_object($self, 'SCSite::DevMode');
+    if ($self->can("_run_dev_$_[1]")) {
+      return $self->${\"_run_dev_$_[1]"}(@_[2..$#_]);
+    } else {
+      die "No such dev mode $_[1]";
+    }
+  }
+  if (@_ >= 1 and my $code = $self->can("_run_cli_$_[0]")) {
+    shift;
+    return $self->$code(@_);
+  }
+  return $self->$orig(@_);
+};
+
+sub _run_cli_generate {
+  my ($self, $to, @spec) = @_;
+  die "generate requires a directory to generate to"
+    unless $to and -d $to;
+  my $out = io($to);
+  my $check = do {
+    if (@spec) { '^('.join('|',map quotemeta($_),@spec).')' }
+    else { '.' }
+  };
+  my $prefix = 'http://'.$self->config->{generate_host};
+  foreach my $path ('', $self->pages->all_paths) {
+    next unless "$path/" =~ /$check/;
+    print "Generating page ${path}\n";
+    my $dir = $out->catdir($path);
+    $dir->mkpath;
+    $dir->catfile('index.html')->print(
+      $self->run_test_request(GET => "${prefix}${path}/")->content
+    );
+  }
+  foreach my $path (map "/feed/$_/", keys %{$self->_feed_configs}) {
+    next unless "$path/" =~ /$check/;
+    print "Generating feed ${path}\n";
+    my $dir = $out->catdir($path);
+    $dir->mkpath;
+    $dir->catfile('index.atom')->print(
+      $self->run_test_request(GET => "${prefix}${path}")->content
+    );
+  }
 }
+   
 
 __PACKAGE__->run_if_script;