Pārlūkot izejas kodu

Memoize config getter, address TODO in Trog/Routes/JSON

Also moves to using Config::Tiny, as it doesn't use bareword FH
Andy Baugh 3 gadi atpakaļ
vecāks
revīzija
378803892f
6 mainītis faili ar 69 papildinājumiem un 18 dzēšanām
  1. 1 2
      config/default.cfg
  2. 29 5
      lib/Trog/Config.pm
  3. 1 1
      lib/Trog/Data.pm
  4. 5 6
      lib/Trog/Routes/HTML.pm
  5. 1 4
      lib/Trog/Routes/JSON.pm
  6. 32 0
      t/Trog-Config.t

+ 1 - 2
config/default.cfg

@@ -1,3 +1,2 @@
 [general]
-    data_model=FlatFile
-    title=tCMS
+theme=dippy

+ 29 - 5
lib/Trog/Config.pm

@@ -3,26 +3,50 @@ package Trog::Config;
 use strict;
 use warnings;
 
-use Config::Simple;
+use Config::Tiny;
 
 =head1 Trog::Config
 
 A thin wrapper around Config::Simple which reads the configuration from the appropriate place.
 
-=head2 Trog::Config::get() = Config::Simple
+=head2 Trog::Config::get() = Config::Tiny
 
 Returns a configuration object that will be used by server.psgi, the data model and Routing modules.
+The object will be cached in memory, so that re-run of get() will return the object fetched earlier.
+Pass in a truthy argument to force refetch.
 
 =cut
 
 our $home_cfg = "config/main.cfg";
 
+my $cf;
+
 sub get {
-    my $cf;
-    $cf = Config::Simple->new($home_cfg) if -f $home_cfg;
+    my ($refetch) = @_;
+    undef $cf if $refetch;
+    return $cf if $cf;
+    $cf = Config::Tiny->read($home_cfg) if -f $home_cfg;
     return $cf if $cf;
-    $cf = Config::Simple->new('config/default.cfg');
+    $cf = Config::Tiny->read('config/default.cfg');
     return $cf;
 }
 
+=head2 Trog::Config::theme_dir()
+
+Returns string corresponding to the path of the theme in use per config.
+The string will be cached in memory, so that re-run of get() will return the object fetched earlier.
+Pass in a truthy argument to force refetch of both theme dir and config object.
+
+=cut
+
+my $theme_dir = '';
+sub theme_dir {
+    my ($refetch) = @_;
+    $theme_dir = '' if $refetch;
+    return $theme_dir if $theme_dir;
+    get($refetch) if !$cf || $refetch;
+    $theme_dir = "themes/$cf->{'general'}{'theme'}" if $cf->{'general'}{'theme'} && -d "www/themes/$cf->{'general'}{'theme'}";
+    return $theme_dir;
+}
+
 1;

+ 1 - 1
lib/Trog/Data.pm

@@ -19,7 +19,7 @@ Returns a new Trog::Data::* class appropriate to what is configured in the Trog:
 =cut
 
 sub new( $class, $config ) {
-    my $module = "Trog::Data::".$config->param('general.data_model');
+    my $module = "Trog::Data::".$config->{'general'}{'data_model'};
     my $req = $module;
     $req =~ s/::/\//g;
     require "$req.pm";

+ 5 - 6
lib/Trog/Routes/HTML.pm

@@ -25,8 +25,7 @@ use Trog::Data;
 
 my $conf = Trog::Config::get();
 my $template_dir = 'www/templates';
-my $theme_dir = '';
-$theme_dir = "themes/".$conf->param('general.theme') if $conf->param('general.theme') && -d "www/themes/".$conf->param('general.theme');
+my $theme_dir = Trog::Config::theme_dir();
 my $td = $theme_dir ? "/$theme_dir" : '';
 
 use lib 'www';
@@ -542,8 +541,8 @@ sub config ($query) {
         categories         => \@series,
         themes             => _get_themes() || [],
         data_models        => _get_data_models(),
-        current_theme      => $conf->param('general.theme') // '',
-        current_data_model => $conf->param('general.data_model') // 'DUMMY',
+        current_theme      => $conf->{'general'}{'theme'} // '',
+        current_data_model => $conf->{'general'}{'data_model'} // 'DUMMY',
         message     => $query->{message},
         failure     => $query->{failure},
         to          => '/config',
@@ -587,8 +586,8 @@ sub config_save ($query) {
     return see_also('/login') unless $query->{user};
     return Trog::Routes::HTML::forbidden($query) unless grep { $_ eq 'admin' } @{$query->{user_acls}};
 
-    $conf->param( 'general.theme',      $query->{theme} )      if defined $query->{theme};
-    $conf->param( 'general.data_model', $query->{data_model} ) if $query->{data_model};
+    $conf->{'general'}{'theme'}      = $query->{theme}      if defined $query->{theme};
+    $conf->{'general'}{'data_model'} = $query->{data_model} if $query->{data_model};
 
     $query->{failure} = 1;
     $query->{message} = "Failed to save configuration!";

+ 1 - 4
lib/Trog/Routes/JSON.pm

@@ -12,10 +12,6 @@ use Trog::Config();
 
 my $conf = Trog::Config::get();
 
-# TODO de-duplicate this, it's shared in html
-my $theme_dir = '';
-$theme_dir = "themes/".$conf->param('general.theme') if $conf->param('general.theme') && -d "www/themes/".$conf->param('general.theme');
-
 our %routes = (
     '/api/catalog' => {
         method     => 'GET',
@@ -58,6 +54,7 @@ sub catalog ($query) {
 }
 
 sub webmanifest ($query) {
+    my $theme_dir = Trog::Config::theme_dir();
     state $headers = ['Content-type' => "application/json", ETag => 'manifest-'._version()];
     state %manifest = (
         "icons" => [

+ 32 - 0
t/Trog-Config.t

@@ -0,0 +1,32 @@
+use strict;
+use warnings;
+
+use Test::More;
+use Test::MockModule qw{strict};
+use Test::Deep;
+use Test::Fatal qw{exception};
+use FindBin;
+
+use lib "$FindBin::Bin/../lib";
+
+use Test::MockFile;
+
+require_ok('Trog::Config') or BAIL_OUT("Can't find SUT");
+
+subtest 'theme_dir' => sub {
+    my $cust_cfg   = Test::MockFile->file("config/main.cfg");
+    my $mocked_cfg = Test::MockFile->file( "config/default.cfg", "[general]\ntheme=zippy\n" );
+    my @mocked_dirs = map { Test::MockFile->new_dir($_) } qw{www www/themes www/themes/zippy};
+    is( Trog::Config::theme_dir(), "themes/zippy", "Got expected theme_dir when directory existent" );
+    pop @mocked_dirs;
+    is( Trog::Config::theme_dir(), "themes/zippy", "Caching works" ); # would die if this did not
+    unlink "config/default.cfg"; # The mocker ain't terribly smart. Maybe a bug?
+    undef $mocked_cfg;
+    my $mocked_cfg = Test::MockFile->file( "config/default.cfg", "[general]\ntheme=dippy\n" );
+    push @mocked_dirs, Test::MockFile->dir( "www/themes/dippy" );
+    is( Trog::Config::theme_dir(1), "", "Got expected theme_dir when directory not existent and cache popped" );
+};
+
+# So far no test for get, but the above actually exercises most of it anyways, so eh
+
+done_testing();