This commit is contained in:
Michael Zhang 2021-08-28 15:08:35 -05:00
parent 9d7e8e4511
commit 92b571b0b2
Signed by: michael
GPG key ID: BDA47A31A3C8EE6B
16 changed files with 142 additions and 55 deletions

View file

@ -5,3 +5,4 @@ indent_style = space
[*.{md,svelte,ts,json,rst}]
indent_size = 2

View file

@ -1,23 +0,0 @@
import { PrimaryKey, Sequelize, Column, Table, Model } from "sequelize-typescript";
@Table
export class Page extends Model {
@PrimaryKey
@Column
public slug: string;
@Column
public title: string;
}
@Table
export class Exercise extends Model {
}
export async function init(path: string): Promise<Sequelize> {
let sequelize = new Sequelize(`sqlite:${path}`, {
models: [Page, Exercise],
});
await sequelize.sync({ force: true });
return sequelize;
}

View file

@ -0,0 +1,54 @@
import { PrimaryKey, Sequelize, Column, Table, Model, DataType } from "sequelize-typescript";
@Table
export class Page extends Model {
@PrimaryKey
@Column
public slug: string;
@Column
public title: string;
@Column
public content: string;
}
@Table
export class Exercise extends Model {
@PrimaryKey
@Column
public page_slug: string;
@PrimaryKey
@Column
public name: string;
}
@Table
export class Grader extends Model {
@PrimaryKey
@Column
public page_slug: string;
@PrimaryKey
@Column
public exercise_name: string;
@PrimaryKey
@Column
public language: string;
@Column
public style: string;
@Column(DataType.JSON)
public props: any;
}
export async function init(path: string): Promise<Sequelize> {
let sequelize = new Sequelize(`sqlite:${path}`, {
models: [Page, Exercise, Grader],
});
await sequelize.sync({ force: true });
return sequelize;
}

View file

@ -4,8 +4,8 @@ import * as yaml from "js-yaml";
import { plainToClass } from "class-transformer";
import { validate } from "class-validator";
import { init, Page } from "./db";
import { Page as PageConfig, Exercise as ExerciseConfig } from "./page";
import { init, Page, Exercise, Grader } from "./db/page";
import { Page as PageConfig, Exercise as ExerciseConfig, Grader as GraderConfig } from "./page";
// TODO: configure this thru cmdline or something later
let materials_dir = "../material";
@ -17,7 +17,6 @@ let SLUG_RE = /([A-Za-z\-\_]+)/;
async function loadPageIntoDb(name: string): Promise<void> {
let slug_match = name.match(SLUG_RE);
let slug = slug_match[0];
console.log("SLUG", slug);
// if this slug has already been loaded into the database, don't do anything
let hasPage = await Page.count({ where: { slug }}) > 0;
@ -33,18 +32,36 @@ async function loadPageIntoDb(name: string): Promise<void> {
let page = new Page({
slug,
title: page_cfg.title,
content: page_cfg.content,
});
await page.save();
// save exercises
async function loadExerciseIntoDb(ex_cfg: ExerciseConfig): Promise<void> {
console.log("pog", ex_cfg);
let exercise = new Exercise({
page_slug: slug,
name: ex_cfg.name,
});
await exercise.save();
async function loadGraderIntoDb([language, grader_cfg]: [string, GraderConfig]): Promise<void> {
let grader = new Grader({
page_slug: slug,
exercise_name: ex_cfg.name,
language,
style: grader_cfg.style,
props: grader_cfg.props,
});
await grader.save();
}
let graders = Object.entries(ex_cfg.graders);
await Promise.all(graders.map(loadGraderIntoDb));
}
let exercises = page_cfg.exercises;
if (exercises != null) {
await Promise.all(exercises
.map(loadExerciseIntoDb));
await Promise.all(exercises.map(loadExerciseIntoDb));
}
}

View file

@ -3,14 +3,12 @@ export class Page {
public type: string;
public summary?: string;
public content?: string;
public content: string;
public exercises?: Exercise[];
};
export class Exercise {
public slug: string;
public name: string;
public description: string;
public graders: Grader[];
};

View file

@ -1,4 +1,6 @@
title: Functional Programming Basics
type: listing
content: |
This listing contains some of the basics of functional programming.
- [Functions](page://fp-function)

View file

@ -7,12 +7,13 @@ content: |
output, but in functional programming, we can usually get around this either
by using [tuples][1] or by [currying][2].
[1]: page://tuples
[2]: page://currying
[1]: page://fp-tuples
[2]: page://fp-currying
exercises:
- name: doubleIt
style: gradedProgram
description: |
Write a function called `doubleIt` that takes an integer and doubles it.
@ -28,3 +29,13 @@ exercises:
(fun x -> assert ((doubleIt x) = (x * 2)))
(List.init 100 (fun x -> x + 1));
- name: whichIsFunction
style: multipleChoice
description: |
Which of the following can be described as a _function_?
graders:
ocaml:
style: multipleChoice
props:
foo: bar

View file

@ -34,3 +34,14 @@ ocaml student.cmo driver.ml
probably should have like $OCAMLCFLAGS in there to be able to customize each
step as well
---
what are some good classes to start out with?
- functional programming
- ctfs?
- possibly a logic class for math
- proof class
- ML???? look into running it
- can we do reading????????????

View file

@ -1,4 +1,9 @@
{
"scripts": {
"compiledb": "cd compile-database && npm start",
"webdev": "cd web && npm run dev"
},
"devDependencies": {
"compile-database": "file:compile-database",
"web": "file:web"

View file

@ -26,5 +26,8 @@
"tslib": "^2.0.0",
"typescript": "^4.0.0"
},
"type": "module"
"type": "module",
"dependencies": {
"sequelize-typescript": "^2.1.0"
}
}

View file

@ -4,6 +4,11 @@
<meta charset="utf-8" />
<link rel="icon" href="/favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Heebo:wght@300;400;700&display=swap" integrity="sha384-TIFtbbKQ3b73InoKF2MDgqFhPYGLQ1h2cnNtGUFVvvd/eRw94RvudHY4y+MMmbw4" crossorigin="anonymous">
%svelte.head%
<style>html, body { margin: 0; paddding: 0; }</style>
</head>

View file

@ -1,5 +1,5 @@
<script lang="ts">
import QuizBox from "$lib/QuizBox.svelte";
import MultipleChoice from "$lib/activity/MultipleChoice.svelte";
</script>
<QuizBox />
<MultipleChoice />

View file

@ -1,10 +0,0 @@
export default class Question {
public description: string;
public choices: Choice[];
public concepts: string[];
};
export class Choice {
public text: string;
public correct: boolean;
};

View file

@ -1,7 +1,5 @@
<script lang="ts">
import type Question from "$lib/Question";
export let question: Question = {
export let question = {
description: `
what is 1 + 1?
`,
@ -13,12 +11,15 @@
],
};
// State related variables
let state = "ask";
let currentChoice;
let wasCorrect = false;
let choose = (index: number) => {
state = "answer";
wasCorrect = question.choices[index].correct;
currentChoice = index;
// state = "answer";
// wasCorrect = question.choices[index].correct;
};
</script>
@ -33,6 +34,11 @@
</li>
{/each}
</ul>
<div class="answer-buttons">
<button>Not sure</button>
<button>Sure</button>
</div>
{:else}
<small>A:</small>
{#if wasCorrect }
@ -47,6 +53,7 @@
.quiz-box {
border: 1px solid gray;
border-radius: 8px;
padding: 8px;
.choices {
display: flex;
@ -63,5 +70,10 @@
}
}
}
.answer-buttons {
display: flex;
justify-content: flex-end;
}
}
</style>

1
web/src/lib/db/index.ts Normal file
View file

@ -0,0 +1 @@
export {};

View file

@ -22,7 +22,7 @@
<div class="footer-block">
<div class="footer-block-title">Eduproj</div>
<ul class="list-reset">
<li>Hellosus</li>
<li><a href="https://git.mzhang.io/michael/eduproj" target="_blank">Source Code</a></li>
</ul>
</div>
<div class="footer-block">
@ -53,7 +53,7 @@
$footer-height: 180px;
#app {
font-family: sans-serif;
font-family: Heebo, sans-serif;
position: relative;
min-height: 100vh;