UNPKG

grading

Version:

Grading of student submissions, in particular programming tests.

141 lines 8.27 kB
"use strict"; 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