my $ua = LWP::UserAgent->new;
my %templates;
-sub import {
- my $caller = caller;
- my ($self, $name, $title) = @_;
+use Carp qw/cluck/;
+
+sub import_to {
+ my ($self, $caller, $name, $title) = @_;
Gruntmaster::Data->export_to_level(1, $caller);
List::Util->export_to_level(1, $caller, qw/sum/);
}
}
+sub import {
+ return unless $_[0] eq __PACKAGE__;
+ splice @_, 1, 0, scalar caller;
+ goto &import_to
+}
+
##################################################
sub generate{
sub _generate {}
-sub vary {}
+sub vary { '' }
sub max_age { 60 }
+++ /dev/null
-package Gruntmaster::Page::Ct;
-
-use 5.014000;
-use strict;
-use warnings;
-use Gruntmaster::Page::Base ct => 'Contests';
-our @ISA = qw/Gruntmaster::Page::Base/;
-our $VERSION = '0.001';
-
-sub _generate{
- my ($self, $htc, $lang, $env) = @_;
- debug $env => "language is '$lang'";
-
- my (@running, @pending, @finished);
- for (sort {contest_start $a <=> contest_start $b}contests) {
- my $ct = { id => $_,
- name => contest_name,
- start => strftime ('%c', localtime contest_start),
- end => strftime ('%c', localtime contest_end),
- owner => contest_owner };
-
- my $time = time;
- push @pending, $ct if time < contest_start;
- push @running, $ct if time >= contest_start && time < contest_end;
- push @finished, $ct if time > contest_end;
- }
-
- $htc->param(running => \@running) if @running;
- $htc->param(pending => \@pending) if @pending;
- $htc->param(finished => \@finished) if @finished;
-}
-
-1
+++ /dev/null
-package Gruntmaster::Page::Ct::Entry;
-
-use 5.014000;
-use strict;
-use warnings;
-use Gruntmaster::Page::Base ct_entry => '<tmpl_var name>';
-our @ISA = qw/Gruntmaster::Page::Base/;
-our $VERSION = '0.001';
-
-sub _generate{
- my ($self, $htc, $lang, $env, $id) = @_;
- debug $env => "language is '$lang' and id is '$id'";
-
- $htc->param(id => $id);
- $htc->param(name => contest_name $id);
- $htc->param(start => strftime '%c', localtime contest_start $id);
- $htc->param(end => strftime '%c', localtime contest_end $id);
- $htc->param(started => time >= contest_start $id);
-}
-
-1
--- /dev/null
+package Gruntmaster::Page::Generic;
+
+use 5.014000;
+use strict;
+use warnings;
+
+use Gruntmaster::Data;
+use Gruntmaster::Page::Base;
+use JSON qw/decode_json/;
+our @ISA = qw/Gruntmaster::Page::Base/;
+our $VERSION = '0.001';
+
+sub hgetall {
+ my $hash = shift;
+ my $cp = $Gruntmaster::Data::contest ? "contest.$Gruntmaster::Data::contest." : '';
+ map { { id => $_, HGETALL "$cp$hash.$_" } } SMEMBERS "$cp$hash"
+}
+
+sub putsym {
+ my ($key, $value) = @_;
+ no strict 'refs';
+ *{"$key"} = $value;
+}
+
+sub makepkg {
+ my ($pkg, $id, $title) = @_;
+ my $fn = $pkg =~ s,::,/,gr;
+ return if $INC{"$fn.pm"};
+ $INC{"$fn.pm"} = 1;
+ Gruntmaster::Page::Base->import_to($pkg, $id, $title);
+ putsym "${pkg}::ISA", ['Gruntmaster::Page::Base'];
+}
+
+sub make_generate {
+ my %thing = @_;
+ sub {
+ my ($self, $htc, $lang, $env, $ct) = @_;
+ undef $ct unless $thing{contest};
+ debug $env => "Contest is $ct";
+ local $Gruntmaster::Data::contest = $ct if $ct;
+ my @thing = hgetall $thing{hash};
+ @thing = map { $thing{mangle}->(); $_ } @thing if exists $thing{mangle};
+ @thing = grep { $thing{choose}->() } @thing if exists $thing{choose};
+ @thing = sort { $thing{sortby}->() } @thing if exists $thing{sortby};
+ my %params;
+ $thing{group} //= sub { $thing{id} };
+ for (@thing) {
+ my $group = $thing{group}->();
+ $params{$group} //= [];
+ push $params{$group}, $_
+ }
+ $htc->param(%params);
+ }
+}
+
+sub make_entry_generate{
+ my %thing = @_;
+ sub {
+ my ($self, $htc, $lang, $env, $id, $ct) = @_;
+ ($id, $ct) = ($ct, $id) if $thing{contest};
+ local $Gruntmaster::Data::contest = $ct if $ct;
+ debug $env => "Hash is $thing{hash} and id is $id";
+ my %params = HGETALL "$thing{hash}.$id";
+ $thing{mangle}->(local $_ = \%params) if exists $thing{mangle};
+ %params = (%params, $thing{hook}->(local $_ = \%params)) if exists $thing{hook};
+ $htc->param(%params);
+ }
+}
+
+sub create_thing {
+ my %thing = @_;
+ my $ucid = ucfirst $thing{id};
+ my $pkg = "Gruntmaster::Page::$ucid";
+
+ putsym "${pkg}::_generate", make_generate %thing if makepkg $pkg, @thing{qw/id title/};
+ putsym "${pkg}::Entry::_generate", make_entry_generate %thing if makepkg "${pkg}::Entry", "$thing{id}_entry", '<tmpl_var name>';
+}
+
+sub params;
+sub contest;
+sub choose (&);
+sub sortby (&);
+sub group (&);
+sub mangle (&);
+sub hook (&);
+
+sub thing (&){
+ my %thing;
+ no strict 'refs';
+ local *{"params"} = sub { @thing{qw/id hash title/} = @_ };
+ local *{"choose"} = sub { $thing{choose} = shift };
+ local *{"sortby"} = sub { $thing{sortby} = shift };
+ local *{"mangle"} = sub { $thing{mangle} = shift };
+ local *{"group"} = sub { $thing{group} = shift };
+ local *{"contest"} = sub { $thing{contest} = 1 };
+ local *{"hook"} = sub { $thing{hook} = shift };
+ use strict 'refs';
+
+ shift->();
+ create_thing %thing
+}
+
+##################################################
+
+thing {
+ params qw/us user Users/;
+ choose { $_->{name} =~ /\w/ };
+ sortby { lc $a->{name} cmp lc $b->{name} };
+};
+
+thing {
+ params qw/pb problem Problems/;
+ contest;
+ sortby { $a->{name} cmp $b->{name} };
+ group { $_->{level} };
+};
+
+thing {
+ params qw/ct contest Contests/;
+ mangle {
+ $_->{start} = strftime '%c', localtime $_->{start};
+ $_->{end} = strftime '%c', localtime $_->{end};
+ };
+ sortby { $a->{start} <=> $b->{start} };
+ group { time < $_->{start} ? 'pending' : time > $_->{end} ? 'finished' : 'running' };
+ hook { started => time >= $_->{start} };
+};
+
+thing {
+ params qw/log job/, 'Job log';
+ contest;
+ mangle {
+ $_->{results} &&= decode_json $_->{results};
+ $_->{time} = sprintf "%.4fs", $_->{time} for values ($_->{results} // [])
+ }
+};
+
+1
+++ /dev/null
-package Gruntmaster::Page::Log::Entry;
-
-use 5.014000;
-use strict;
-use warnings;
-use Gruntmaster::Page::Base log_entry => 'Job <tmpl_var id>';
-our @ISA = qw/Gruntmaster::Page::Base/;
-our $VERSION = '0.001';
-
-sub _generate{
- my ($self, $htc, $lang, $env, $ct, $id) = @_;
- debug $env => "language is '$lang', contest is '$ct' and id is '$id'";
- local $Gruntmaster::Data::contest = $ct if $ct;
-
- my @tests = ();
-
- eval {
- @tests = map {
- $_->{time} = sprintf "%.4fs", $_->{time};
- $_
- } @{job_results $id};
- };
-
- $htc->param(id => $id);
- $htc->param(tests => \@tests);
- $htc->param(errors => job_errors $id)
-}
-
-1
+++ /dev/null
-package Gruntmaster::Page::Pb;
-
-use 5.014000;
-use strict;
-use warnings;
-use Gruntmaster::Page::Base pb => 'Problems';
-our @ISA = qw/Gruntmaster::Page::Base/;
-our $VERSION = '0.001';
-
-sub _generate{
- my ($self, $htc, $lang, $env, $ct) = @_;
- debug $env => "language is '$lang' and contest is '$ct'";
- local $Gruntmaster::Data::contest = $ct if $ct;
-
- my @problems = sort { $b->{name} cmp $a->{name} } map +{
- id => $_,
- name => problem_name,
- level => problem_level}, problems;
-
- for my $d (qw/beginner easy medium advanced hard/) {
- $htc->param($d => [grep {$_->{level} and $_->{level} eq $d} @problems]);
- }
- $htc->param(levels => grep { $_->{level} } @problems);
- $htc->param(problems => \@problems);
-}
-
-1
+++ /dev/null
-package Gruntmaster::Page::Us;
-
-use 5.014000;
-use strict;
-use warnings;
-use Gruntmaster::Page::Base us => 'Users';
-our @ISA = qw/Gruntmaster::Page::Base/;
-our $VERSION = '0.001';
-
-sub _generate{
- my ($self, $htc, $lang, $env) = @_;
- debug $env => "language is '$lang'";
-
- $htc->param(users => [ sort { lc $a->{name} cmp lc $b->{name} }
- map { {id => $_, name => user_name} }
- grep { user_name =~ /\w/ } users ]);
-}
-
-1
+++ /dev/null
-package Gruntmaster::Page::Us::Entry;
-
-use 5.014000;
-use strict;
-use warnings;
-use Gruntmaster::Page::Base us_entry => '<tmpl_var name>';
-our @ISA = qw/Gruntmaster::Page::Base/;
-our $VERSION = '0.001';
-
-sub _generate{
- my ($self, $htc, $lang, $env, $us) = @_;
- debug $env => "language is '$lang', user is '$us'";
- local $_ = $us;
-
- $htc->param(name => user_name);
- $htc->param(town => user_town);
- $htc->param(university => user_university);
- $htc->param(level => user_level);
-}
-
-1
use File::Slurp qw/read_file/;
use HTTP::Negotiate qw/choose/;
use Plack::Request;
+use Gruntmaster::Page::Log;
+use Gruntmaster::Page::Pb::Entry;
+use Gruntmaster::Page::Generic;
my %handlers;
-Compiler output:
+<tmpl_if errors>
+<h2>Compiler output</h2>
<pre><tmpl_var errors></pre>
+</tmpl_if>
-Results:
+<tmpl_if results>
+<h2>Results</h2>
<table border class="table table-border table-striped">
<thead>
<tr><th>Test number<th>Result<th>Time
<tbody>
-<tmpl_loop tests><tr><td><tmpl_var id><td class="r<tmpl_var result>"><tmpl_var result_text><td><tmpl_var time>
+<tmpl_loop results><tr><td><tmpl_var id><td class="r<tmpl_var result>"><tmpl_var result_text><td><tmpl_var time>
</tmpl_loop>
</table>
+</tmpl_if>
\ No newline at end of file
-<tmpl_if levels>
+<tmpl_if beginner>
<h2>Beginner</h2>
<div class="list-group">
<tmpl_loop beginner><a class="list-group-item" href="<tmpl_var id>"><tmpl_var name></a>
</tmpl_loop></div>
+</tmpl_if>
+<tmpl_if beginner>
<h2>Easy</h2>
<div class="list-group">
<tmpl_loop easy><a class="list-group-item" href="<tmpl_var id>"><tmpl_var name></a>
</tmpl_loop></div>
+</tmpl_if>
+<tmpl_if beginner>
<h2>Medium</h2>
<div class="list-group">
<tmpl_loop medium><a class="list-group-item" href="<tmpl_var id>"><tmpl_var name></a>
</tmpl_loop></div>
+</tmpl_if>
+<tmpl_if beginner>
<h2>Hard</h2>
<div class="list-group">
<tmpl_loop hard><a class="list-group-item" href="<tmpl_var id>"><tmpl_var name></a>
</tmpl_loop></div>
-
-<tmpl_else>
-<div class="list-group">
-<tmpl_loop problems><a class="list-group-item" href="<tmpl_var id>"><tmpl_var name></a>
-</tmpl_loop></div>
</tmpl_if>
-<div class="list-group"><tmpl_loop users><a class="list-group-item" href="<tmpl_var id>"><tmpl_var name></a>
+<div class="list-group"><tmpl_loop us><a class="list-group-item" href="<tmpl_var id>"><tmpl_var name></a>
</tmpl_loop></ol>