Skip to content

Instantly share code, notes, and snippets.

@memowe
Last active December 12, 2017 09:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save memowe/6993495 to your computer and use it in GitHub Desktop.
Save memowe/6993495 to your computer and use it in GitHub Desktop.
{
tasks => [
{
name => 'simple-sum',
description => 'Implement a function that adds two numbers!',
template => "sub sum {\n my (\$x, \$y) = \@_;\n\n}",
tests => [
{name => 'zeroes', test => 'sum(0, 0)', expected => 0},
{name => 'left zero', test => 'sum(0, 42)', expected => 42},
{name => 'right zero', test => 'sum(17, 0)', expected => 17},
{name => 'some values', test => 'sum(42, 17)', expected => 59},
{name => 'some values', test => 'sum(-17, 42)', expected => 25},
{name => 'some values', test => 'sum(1742, -4217)', expected => -2475},
],
},
{
name => 'sum',
description => 'Implement a function that sums all natural numbers up to the input!',
template => "sub sum {\n my \$n = shift;\n\n}",
tests => [
{name => 'negative input', test => 'sum(-42)', expected => 0},
{name => 'zero', test => 'sum(0)', expected => 0},
{name => 'one', test => 'sum(1)', expected => 1},
{name => 'six', test => 'sum(3)', expected => 6},
{name => 'big sum', test => 'sum(42)', expected => 903},
],
},
{
name => 'fibonacci',
description => 'Implement a fibonacci function!',
template => "sub fibonacci {\n my \$n = shift;\n\n}",
tests => [
{name => 'negative input', test => 'fibonacci(-42)', expected => 0},
{name => 'first fibonacci number', test => 'fibonacci(0)', expected => 0},
{name => 'second fibonacci number', test => 'fibonacci(1)', expected => 1},
{name => 'third fibonacci number', test => 'fibonacci(2)', expected => 1},
{name => 'fifth fibonacci number', test => 'fibonacci(4)', expected => 3},
{name => '18th fibonacci number', test => 'fibonacci(17)', expected => 1597},
],
},
],
};
#!/usr/bin/env perl
use Mojolicious::Lite;
use List::Util 'first';
use Safe;
# prepare sandbox
my $sandbox = Safe->new();
# retrieve tasks
my @tasks = @{ plugin('Config')->{tasks} };
# home page: list of tasks
get '/' => {tasks => \@tasks} => 'index';
# task route
get '/task/:task' => sub {
my $self = shift;
my $task = first {$_->{name} eq $self->param('task')} @tasks;
return $self->render_not_found unless defined $task;
$self->stash(
task => $task,
template => 'task',
);
} => 'task';
# task evaluation route
post "/task/:task" => sub {
my $self = shift;
my $code = $self->param('code');
my $task = first {$_->{name} eq $self->param('task')} @tasks;
return $self->render_not_found unless defined $task;
# evaluate code-test pairs for all tests
my (@results, @correct);
for my $test (@{$task->{tests}}) {
my $test_code = $code . "\n" . $test->{test};
my $result = $sandbox->reval($test_code);
push @results, $result;
push @correct, $result == $test->{expected};
}
# done
$self->stash(
task => $task,
results => \@results,
correct => \@correct,
template => 'task',
);
} => "taskeval";
app->start;
__DATA__
@@ index.html.ep
% layout 'default';
% title 'Welcome, stranger!';
<h1>Welcome to PEasy, the easy Perl Easy!</h1>
<hr>
<p>Select a task:</p>
<ul>
% for my $task (@$tasks) {
% my $url = url_for 'task', task => $task->{name};
<li><%= link_to $task->{name} => $url %></li>
% }
</ul>
@@ task.html.ep
% use List::Util 'first';
% layout 'default';
% title "Task $task->{name}";
<h1><%= link_to PEasy => 'index' %>: the <%= $task->{name} %> task</h1>
<hr>
<h2>Description</h2>
<p><%== $task->{description} %></p>
<h2>Your solution</h2>
%= form_for 'taskeval', task => $task->{name} => begin
%= text_area code => $task->{template}, cols => 100, rows => 10
%= tag p => begin
%= submit_button 'Evaluate!'
% end
% end
<h2>The test suite</h2>
<table border="1">
<thead>
<th>Test name</th>
<th>test</th>
<th>expected output</th>
% if (defined stash('results')) {
<th>actual output</th
% }
</thead>
<tbody>
% for my $ti (0 .. $#{$task->{tests}}) {
% my $test = $task->{tests}[$ti];
% my $class = '';
% if (defined stash('results')) {
% $class = ' class="' . (stash('correct')->[$ti] ? 'ok' : 'fail') . '"';
% }
<tr<%== $class %>>
<th><%= $test->{name} %></th>
<td><%= $test->{test} %></td>
<td><%= $test->{expected} %></td>
% if (defined stash('results')) {
<td><%= stash('results')->[$ti] %></td>
% }
</tr>
% }
</tbody>
</table>
@@ layouts/default.html.ep
<!DOCTYPE html>
<html>
<head><title><%= title %> - PEasy</title>
<style type="text/css">
tr.ok th, tr.ok td { background-color: lime }
tr.fail th, tr.fail td { background-color: red }
</style></head>
<body>
%= content
<hr><p>&copy;
<a href="http://mirko.westermeier.de/">Mirko Westermeier</a>
(<a href="http://twitter.com/memowe">@memowe</a>)
</p>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment