html_zoom starts to work
Matt S Trout [Tue, 31 Jul 2012 20:36:42 +0000 (20:36 +0000)]
lib/App/SCS.pm
lib/App/SCS/Page.pm
lib/App/SCS/PageSet.pm
lib/App/SCS/Plugin/Core.pm
lib/App/SCS/Plugin/Core/PagePlugin/Template.pm
lib/App/SCS/Role/PagePlugin.pm
t/02simple.t [new file with mode: 0644]
t/data/share/pages/simple/.htcache.1.html.json [new file with mode: 0644]
t/data/share/pages/simple/1.html [new file with mode: 0644]
t/data/share/templates/.htcache.layout.html.json [new file with mode: 0644]
t/data/share/templates/layout.html [new file with mode: 0644]

index c8a3c07..56b393b 100644 (file)
@@ -8,20 +8,45 @@ with 'App::SCS::Role::WithConfig';
 
 has plugins => (is => 'ro', default => sub { [] });
 
+has root_dir => (is => 'lazy');
+
+sub _build_root_dir {
+  my ($self) = @_;
+  io->dir(io->dir($self->config->{root_dir})->absolute);
+}
+
+has share_dir => (is => 'lazy');
+
+sub _build_share_dir {
+  my ($self) = @_;
+  io->dir($self->config->{share_dir}||$self->root_dir->catdir('share'));
+}
+
+has page_plugin_config => (is => 'lazy');
+
+sub _build_page_plugin_config {
+  my ($self) = @_;
+  return {
+    plugin_map => {
+      do {
+        my %map = map $_->page_plugins, reverse @{$self->plugins};
+        ref($_) or $_ = { class => $_, config => sub {} } for values %map;
+        %map;
+      }
+    },
+    defaults => [
+      map $_->default_page_plugins, @{$self->plugins}
+    ],
+  };
+}
+
 has pages => (is => 'lazy');
 
 sub _build_pages {
   my ($self) = @_;
   return use_module('App::SCS::PageSet')->new(
-    base_dir => io->dir($self->config->{share_dir})->catdir('pages'),
-    plugin_config => {
-      plugin_map => {
-        map $_->page_plugins, reverse @{$self->plugins}
-      },
-      defaults => [
-        map $_->default_page_plugins, @{$self->plugins}
-      ],
-    }
+    base_dir => $self->share_dir->catdir('pages'),
+    plugin_config => $self->page_plugin_config,
   );
 }
 
index e6f78a4..a05c5e9 100644 (file)
@@ -4,6 +4,7 @@ use IO::All;
 use Time::Local qw(timelocal);
 use Data::Pond qw(pond_read_datum pond_write_datum);
 use List::Util qw(reduce);
+use Module::Runtime qw(use_module);
 use Moo;
 
 with 'App::SCS::Role::PageChildren';
@@ -42,15 +43,15 @@ has _page_plugins => (is => 'lazy');
 sub _build__page_plugins {
   my ($self) = @_;
   my $plugin_config = $self->plugin_config;
-  my ($plugin_map, $defaults) = @{$self->_page_set}{qw(plugin_map defaults)};
-
+  my ($plugin_map, $defaults) = @{$self->_page_set->plugin_config}
+                                 {qw(plugin_map defaults)};
   my @spec = (@$defaults, @$plugin_config);
   my @plugins;
   while (my ($name, $config) = splice @spec, 0, 2) {
     my $info = $plugin_map->{$name};
     push @plugins,
       use_module($info->{class})->new(
-        %{$info->{config}||{}}, %$config, page => $self
+        ($info->{config}||sub{})->(), %$config, page => $self
       );
   }
   return \@plugins;
@@ -90,23 +91,27 @@ has _psgi_response => (is => 'lazy');
 sub _build__psgi_response {
   my ($self) = @_;
 
-  my @plugins = @{$self->page_plugins};
-
-  my $html_zoom = reduce {
-    $b->filter_html_zoom($a)
-  } HTML::Zoom->from_html($self->html), @plugins;
-
-  my $content_zoom = reduce {
-    $b->filter_content_zoom($a)
-  } $html_zoom, @plugins;
-
   my $psgi_res = [
-    200, [ 'Content-type' => 'text/html' ], $content_zoom->to_fh
+    200, [ 'Content-type' => 'text/html' ], $self->_content_zoom->to_fh
   ];
 
   return reduce {
     $b->filter_psgi_response($a)
-  } $psgi_res, @plugins;
+  } $psgi_res, @{$self->_page_plugins};
+}
+
+sub _content_zoom {
+  my ($self) = @_;
+  return reduce {
+    $b->filter_content_zoom($a)
+  } $self->_html_zoom, @{$self->_page_plugins};
+}
+
+sub _html_zoom {
+  my ($self) = @_;
+  return reduce {
+    $b->filter_html_zoom($a)
+  } HTML::Zoom->from_html($self->html), @{$self->_page_plugins};
 }
 
 no Moo;
index b71c5d4..9dfc792 100644 (file)
@@ -8,6 +8,7 @@ use App::SCS::Page;
 use IO::All;
 use Try::Tiny;
 use List::Util qw(reduce);
+use Module::Runtime qw(use_module);
 use JSON;
 use Moo;
 
@@ -131,15 +132,16 @@ sub _all_files {
 
 sub latest {
   my ($self, $max) = @_;
-  require SCSite::LatestPageSet;
-  SCSite::LatestPageSet->new(
+  use_module('App::SCS::LatestPageSet')->new(
     parent => $self,
     max_entries => $max,
   );
 }
 
 sub _new_page {
-  SCSite::Page->new({ path => $_[1], page_set => $_[0], %{$_[2]} })
+  use_module('App::SCS::Page')->new(
+    path => $_[1], page_set => $_[0], %{$_[2]}
+  );
 }
 
 sub _types_re { qw/\.(html|md)/ }
index f799f70..e6a943b 100644 (file)
@@ -1,5 +1,7 @@
 package App::SCS::Plugin::Core;
 
+use Module::Runtime qw(use_module);
+use IO::All;
 use Moo;
 no warnings::illegalproto;
 use Safe::Isa;
@@ -11,7 +13,10 @@ has templates => (is => 'lazy');
 sub _build_templates {
   my ($self) = @_;
   return use_module('App::SCS::PageSet')->new(
-    base_dir => io->dir($self->app->config->{share_dir})->catdir('templates'),
+    base_dir => io->dir($self->app->share_dir)->catdir('templates'),
+    plugin_config => {
+      plugin_map => $self->app->page_plugin_config->{plugin_map}
+    }
   );
 }
 
@@ -29,11 +34,11 @@ sub page_plugins {
   PageList => 'App::SCS::Plugin::Core::PagePlugin::PageList',
   Template => {
     class => 'App::SCS::Plugin::Core::PagePlugin::Template',
-    config => { templates => $self->templates },
+    config => sub { templates => $self->templates },
   },
   Include => {
     class => 'App::SCS::Plugin::Core::PagePlugin::Include',
-    config => { includes => $self->includes },
+    config => sub { includes => $self->includes },
   },
   PageData => 'App::SCS::Plugin::Core::PagePlugin::PageData',
 }
index b1e47ce..6bac9fe 100644 (file)
@@ -14,13 +14,14 @@ sub filter_html_zoom {
     or die "No such template ${\$self->name}";
   my $template_zoom = HTML::Zoom->from_html($template_page->html);
   my @ev;
-  $template_zoom->collect('*[data-replace]', { into => \@ev })
+  $template_zoom->select('*[data-replace]')
+                ->collect({ into => \@ev, passthrough => 1 })
                 ->then
-                ->${\sub {
+                ->replace(sub {
                     my $sel = $ev[0]->{attrs}{'data-replace'};
-                    $zoom->collect($self, { into => \my @replace })->run;
-                    shift->replace(\@replace);
-                  }}
+                    $zoom->collect($sel, { into => \my @replace })->run;
+                    HTML::Zoom::ArrayStream->new({ array => \@replace })
+                  });
 }
 
 1;
index f7b1055..ceee4cb 100644 (file)
@@ -6,10 +6,10 @@ has 'page' => (is => 'ro', weak_ref => 1, required => 1);
 
 sub extra_pages { () }
 
-sub filter_html_zoom { shift }
+sub filter_html_zoom { $_[1] }
 
-sub filter_content_zoom { shift }
+sub filter_content_zoom { $_[1] }
 
-sub filter_psgi_response { shift }
+sub filter_psgi_response { $_[1] }
 
 1;
diff --git a/t/02simple.t b/t/02simple.t
new file mode 100644 (file)
index 0000000..1854a8f
--- /dev/null
@@ -0,0 +1,46 @@
+use strictures 1;
+use Test::More;
+use App::SCS;
+use IO::All;
+
+my $app = App::SCS->new(
+  config => { root_dir => 't/data' }
+);
+
+my $simple1 = $app->pages->get({ path => 'simple/1' });
+
+ok($simple1, 'Got a page object');
+
+is(
+  $simple1->html,
+  io->file('t/data/share/pages/simple/1.html')->all,
+  "Correct file loaded"
+);
+
+my @page_plugins = @{$simple1->_page_plugins};
+
+is(scalar(@page_plugins), 2, 'Two plugins applied');
+
+my ($tp, $pdp) = @page_plugins;
+
+ok(
+  $tp->isa('App::SCS::Plugin::Core::PagePlugin::Template'),
+  'Template plugin'
+);
+
+is($tp->name, 'layout', 'Template name');
+
+ok(
+  $pdp->isa('App::SCS::Plugin::Core::PagePlugin::PageData'),
+  'PageData plugin'
+);
+
+like(
+  $simple1->_html_zoom->to_html,
+  qr{<div id="content">.*<h1>Hello world}s,
+  'Layout woven correctly'
+);
+
+warn $simple1->_content_zoom->to_html;
+
+done_testing;
diff --git a/t/data/share/pages/simple/.htcache.1.html.json b/t/data/share/pages/simple/.htcache.1.html.json
new file mode 100644 (file)
index 0000000..0c27fc5
--- /dev/null
@@ -0,0 +1 @@
+{"keywords":"","created":"","subtitle":"","plugins":"","html":"<html>\n  <head>\n    <title>Simple 1</title>\n  </head>\n  <body>\n    <h1>Hello world</h1>\n  </body>\n</html>\n","title":"Simple 1","description":""}
\ No newline at end of file
diff --git a/t/data/share/pages/simple/1.html b/t/data/share/pages/simple/1.html
new file mode 100644 (file)
index 0000000..9116bed
--- /dev/null
@@ -0,0 +1,8 @@
+<html>
+  <head>
+    <title>Simple 1</title>
+  </head>
+  <body>
+    <h1>Hello world</h1>
+  </body>
+</html>
diff --git a/t/data/share/templates/.htcache.layout.html.json b/t/data/share/templates/.htcache.layout.html.json
new file mode 100644 (file)
index 0000000..57e9c50
--- /dev/null
@@ -0,0 +1 @@
+{"keywords":"","created":"","subtitle":"","plugins":"","html":"<html data-wrap=\"html\">\n  <head data-replace=\"head\" />\n  <body>\n    <div id=\"content\">\n      <div data-replace=\"h1\" />\n    </div>\n  </body>\n</html>\n","title":"","description":""}
\ No newline at end of file
diff --git a/t/data/share/templates/layout.html b/t/data/share/templates/layout.html
new file mode 100644 (file)
index 0000000..946c744
--- /dev/null
@@ -0,0 +1,8 @@
+<html data-wrap="html">
+  <head data-replace="head" />
+  <body>
+    <div id="content">
+      <div data-replace="h1" />
+    </div>
+  </body>
+</html>