grading
Version:
Grading of student submissions, in particular programming tests.
141 lines • 8.27 kB
JavaScript
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.cmdCompare = exports.compareResults = void 0;
const fs_1 = __importDefault(require("fs"));
const cliUtil_1 = require("./cliUtil");
const path_1 = __importDefault(require("path"));
const fsUtil_1 = require("../fsUtil");
const csv_1 = require("../csv");
async function compareResults(newCSV, options) {
if (!await (0, fsUtil_1.fileExists)(newCSV)) {
return;
}
const dir = path_1.default.dirname(newCSV);
const newCSVRel = path_1.default.basename(newCSV);
const foundPrefix = newCSVRel.match(/^[^0-9]+/);
if (!foundPrefix) {
(0, cliUtil_1.verb)("Cannot compare results automatically, no prefix (without digits) found in file name.");
return;
}
const prefix = foundPrefix[0];
(0, cliUtil_1.verb)(`Looking for old results with prefix '${prefix}' (and extension '.csv') in '${dir}'`);
const oldResults = (await (0, fsUtil_1.readDir)(dir, "file", false)).filter(f => {
// verb(`Found file '${f}'`);
return f !== newCSVRel && f.startsWith(prefix) && f.endsWith(".csv");
});
if (oldResults.length === 0) {
(0, cliUtil_1.verb)("Cannot compare results automatically, no old result found.");
return;
}
const latestResult = oldResults.map(f => path_1.default.join(dir, f)).sort((a, b) => fs_1.default.statSync(b).mtimeMs - fs_1.default.statSync(a).mtimeMs)[0];
cmdCompare(latestResult, newCSV, options, true);
}
exports.compareResults = compareResults;
async function cmdCompare(oldCSV, newCSV, options, runInternally = false) {
(0, cliUtil_1.verbosity)(options);
if (oldCSV === newCSV) {
program.error("Comparing the same file doesn't make any sense.");
}
(0, cliUtil_1.log)(`Compare '${oldCSV}' (old) with '${newCSV}' (new)`);
try {
const oldResult = await (0, csv_1.loadTableWithEncoding)(oldCSV, options.encoding, options.resultCSVDelimiter);
const oldColSubmissionID = oldResult.getColForTitles('submissionID', "userID");
const oldColName = oldResult.getColForTitles('name');
const oldColSubmissionFlag = oldResult.getColForTitles('abgabe', "submitted");
const oldColGrade = oldResult.getColForTitles('note', "grade");
const oldColPoints = oldResult.getColForTitles('punkte', "points");
const newResult = await (0, csv_1.loadTableWithEncoding)(newCSV, options.encoding, options.resultCSVDelimiter);
const newColSubmissionID = newResult.getColForTitles('submissionID', "userID");
const newColName = newResult.getColForTitles('name');
const newColSubmissionFlag = newResult.getColForTitles('abgabe', "submitted");
const newColGrade = newResult.getColForTitles('note', "grade");
const newColPoints = newResult.getColForTitles('punkte', "points");
const changes = [];
let oldSum = 0;
let newSum = 0;
let oldCount = 0;
let newCount = 0;
const oldOnly = [];
const newOnly = [];
for (let oldRow = 2; oldRow <= oldResult.rowsCount; oldRow++) {
oldCount++;
const submissionID = oldResult.getText(oldColSubmissionID, oldRow);
const name = oldResult.getText(oldColName, oldRow);
const oldGrade = (0, csv_1.parseGrading)(oldResult.getText(oldColGrade, oldRow));
const oldPoints = (0, csv_1.parseGrading)(oldResult.getText(oldColPoints, oldRow));
const newRow = newResult.findRowWhere(row => newResult.getText(newColSubmissionID, row) === submissionID);
oldSum += oldGrade;
let newGrade = 0;
let newPoints = 0;
if (newRow > 0) {
newGrade = (0, csv_1.parseGrading)(newResult.getText(newColGrade, newRow));
newPoints = (0, csv_1.parseGrading)(newResult.getText(newColPoints, newRow));
newSum += newGrade;
newCount++;
changes.push({ submissionId: submissionID, name: name, oldGrade: oldGrade, oldPoints: oldPoints, newGrade: newGrade, newPoints: newPoints, delta: newGrade - oldGrade });
}
else {
oldOnly.push((0, cliUtil_1.quickFormat)(submissionID, 8) + ", " + (0, cliUtil_1.quickFormat)(name.substring(0, 20), 20) + ": " + (0, cliUtil_1.quickFormat)((0, cliUtil_1.withDecimals)(oldGrade), 3));
}
}
for (let newRow = 2; newRow <= newResult.rowsCount; newRow++) {
const submissionID = newResult.getText(newColSubmissionID, newRow);
const name = newResult.getText(newColName, newRow);
const newGrade = (0, csv_1.parseGrading)(newResult.getText(newColGrade, newRow));
const newPoints = (0, csv_1.parseGrading)(newResult.getText(newColPoints, newRow));
const oldRow = oldResult.findRowWhere(row => oldResult.getText(oldColSubmissionID, row) === submissionID);
if (oldRow <= 0) {
newSum += newGrade;
newCount++;
newOnly.push(`${(0, cliUtil_1.quickFormat)(submissionID, 8)}, ${(0, cliUtil_1.quickFormat)(name.substring(0, 20), 20)}: ${(0, cliUtil_1.quickFormat)((0, cliUtil_1.withDecimals)(newGrade), 3)} (${(0, cliUtil_1.quickFormat)((0, cliUtil_1.withDecimals)(newPoints), 3)})`);
}
}
const improved = changes.filter(c => c.delta < 0).length;
const deteriorated = changes.filter(c => c.delta > 0).length;
const unchanged = changes.filter(c => c.delta === 0).length;
const avg1 = oldCount ? oldSum / oldCount : 0;
const avg2 = newCount ? newSum / newCount : 0;
if (!options.summaryOnly) {
(0, cliUtil_1.log)("- Individual changes:");
(options.showUnchanged ? changes : changes.filter(c => c.delta !== 0)).forEach(c => {
(0, cliUtil_1.log)(` - ${(0, cliUtil_1.quickFormat)(c.submissionId, 8)}, ${(0, cliUtil_1.quickFormat)(c.name.substring(0, 20), 20)}: ${(0, cliUtil_1.quickFormat)((0, cliUtil_1.withDecimals)(c.oldGrade), 3)} (${(0, cliUtil_1.quickFormat)((0, cliUtil_1.withDecimals)(c.oldPoints), 3)}) <-> ${(0, cliUtil_1.quickFormat)((0, cliUtil_1.withDecimals)(c.newGrade), 3)} (${(0, cliUtil_1.quickFormat)((0, cliUtil_1.withDecimals)(c.newPoints), 3)}) = ${(0, cliUtil_1.withDecimals)(c.delta)}`);
});
if (oldOnly.length || newOnly.length) {
if (oldOnly.length) {
(0, cliUtil_1.log)("- Submitters only in 1st (old) result: " + oldOnly.length);
oldOnly.forEach(s => (0, cliUtil_1.log)(" - " + s));
}
if (newOnly.length) {
(0, cliUtil_1.log)("- Submitters only in 2nd (new) result: " + newOnly.length);
newOnly.forEach(s => (0, cliUtil_1.log)(" - " + s));
}
}
}
(0, cliUtil_1.log)("Summary:");
(0, cliUtil_1.log)("- " + (0, cliUtil_1.quickFormat)("Improved: ", 10) + improved);
(0, cliUtil_1.log)("- " + (0, cliUtil_1.quickFormat)("Deteriorated: ", 10) + deteriorated);
(0, cliUtil_1.log)("- " + (0, cliUtil_1.quickFormat)("Unchanged: ", 10) + unchanged);
(0, cliUtil_1.log)("- " + (0, cliUtil_1.quickFormat)("Submissions: ", 10) + oldCount + " <--> " + newCount);
(0, cliUtil_1.log)("- " + (0, cliUtil_1.quickFormat)("Averages: ", 10) + (0, cliUtil_1.withDecimals)(avg1) + " <--> " + (0, cliUtil_1.withDecimals)(avg2));
if (options.summaryOnly) {
if (oldOnly.length) {
(0, cliUtil_1.log)("- Submitters only in 1st (old) result: " + oldOnly.length);
}
if (newOnly.length) {
(0, cliUtil_1.log)("- Submitters only in 2nd (new) result: " + newOnly.length);
}
}
}
catch (err) {
(0, cliUtil_1.error)(`${SEP}\nError: ${err}`);
program.error(String(err));
}
if (!runInternally) {
(0, cliUtil_1.log)(`${SEP}\nDone.`);
}
}
exports.cmdCompare = cmdCompare;
//# sourceMappingURL=cmdCompare.js.map
;