refactor
This commit is contained in:
parent
4c496fc7a9
commit
921082f61d
3 changed files with 66 additions and 40 deletions
38
README.md
38
README.md
|
|
@ -20,7 +20,7 @@ A summary is then printed on the front page.
|
|||
|
||||
Writing an exam is now easy:
|
||||
|
||||
#import "@local/exam:0.1.0": exam, exercise_header, exercise_items, mtext
|
||||
#import "@local/exam:0.1.0": exam, exercise, exercise-items, mtext
|
||||
|
||||
#show: exam.with(
|
||||
title: "Exam",
|
||||
|
|
@ -32,7 +32,7 @@ Writing an exam is now easy:
|
|||
date: "1. January 1970",
|
||||
course_short_title: "ABC & EFG",
|
||||
|
||||
course_number: "π",
|
||||
course_code: "π",
|
||||
duration_minutes: "90",
|
||||
|
||||
ask_trainer_name: false,
|
||||
|
|
@ -43,37 +43,59 @@ Writing an exam is now easy:
|
|||
|
||||
### Defining exercises and items
|
||||
|
||||
A new exercise can be started using `#exercise_header("title", nb_points)`, for example:
|
||||
A new exercise can be started using `#exercise("title", nb_points)`, for example:
|
||||
|
||||
#exercise_header("Relations and their properties", 2)
|
||||
#exercise("Relations and their properties", 2)
|
||||
|
||||
Consider the relation $R subset NN^2$, defined as follows:
|
||||
|
||||
$ (x, y) in R #h(0.5cm) <==> #h(0.5cm) x + y #mtext[is odd]. $
|
||||
|
||||
Is $R$ reflexive? transitiv? symmetrisch? antisymmetrisch?
|
||||
Is $R$ reflexive? transitive? symmetric? antisymmetric?
|
||||
|
||||
On can also defined (sub-)items for the exercise using `#exercise_items(items, override_points:true)`,
|
||||
On can also defined (sub-)items for the exercise using `#exercise-items(override_points:true, numbering:"a)", items)`,
|
||||
where `items` is an array of `(nb_points, statement)`. By default, the number of points the exercise
|
||||
is worth is recomputed as the sum of points for all items. This behaviour can be turned off by
|
||||
setting `override_points: false`.
|
||||
|
||||
#exercise_header("Properties of functions", 3)
|
||||
#exercise("Properties of functions", 3)
|
||||
|
||||
Let $f : (0, +infinity) → (0, +infinity)$ with $f (x) = e^(-x)$.
|
||||
|
||||
#exercise_items((
|
||||
#exercise-items((
|
||||
(1, [Is $f$ injective?]),
|
||||
(1, [Is $f$ surjective?]),
|
||||
(1, [Is $f$ bijective?]),
|
||||
))
|
||||
|
||||
#exercise("Logical operators", 3.14)
|
||||
|
||||
Consider the following truthtable:
|
||||
|
||||
#align(center, table(
|
||||
stroke: frame(0.5pt),
|
||||
columns: (auto, auto, auto),
|
||||
align: center,
|
||||
[$A$], [$B$], [$A or B$],
|
||||
[1], [1], [1],
|
||||
[1], [0], [1],
|
||||
[0], [1], [1],
|
||||
[0], [0], [1]
|
||||
))
|
||||
|
||||
#exercise-items(override-points: false, numbering: "i)", (
|
||||
(1, [Is the truthtable correct?]),
|
||||
(1, [If not, fix it.]),
|
||||
))
|
||||
|
||||
All together, this should output something like:
|
||||
|
||||

|
||||
|
||||
### Utilities
|
||||
|
||||
These are used in the example above.
|
||||
|
||||
- `mtext(str)` to typeset text within math mode using the default text font.
|
||||
- `frame(stroke_width)` provides `stroke` for use in a `table`, horizontal lines only,
|
||||
top and bottom lines are bold.
|
||||
|
|
|
|||
68
lib.typ
68
lib.typ
|
|
@ -57,13 +57,13 @@
|
|||
// - int is the number of points this item is worth,
|
||||
// - expression is the item to typeset.
|
||||
// example:
|
||||
// #exercise_items((
|
||||
// #exercise-items((
|
||||
// (1, [Untersuchen Sie, ob $f$ injektiv ist.]),
|
||||
// (1, [Untersuchen Sie, ob $f$ surjektiv ist.]),
|
||||
// (1, [Geben Sie im Falle ihrer Existenz die Umkehrfunktion $f^(−1)$ an.])
|
||||
//))
|
||||
#let exercise_items(items) = block[
|
||||
#let c = counter("exercise_items")
|
||||
#let exercise-items(override-points: true, numbering: "a)", items) = block[
|
||||
#let c = counter("exercise-items")
|
||||
#let exercise_points = 0
|
||||
#c.update(0)
|
||||
#table(
|
||||
|
|
@ -78,21 +78,24 @@
|
|||
pt = get_L("points_short")
|
||||
}
|
||||
(
|
||||
[#c.step()#v(4pt) *#context c.display("a)")* #statement],
|
||||
[#c.step()#v(4pt) *#context c.display(numbering)* #statement],
|
||||
rect(radius:1cm, inset: (x:5pt, y:3pt), stroke: gray+0.5pt)[#points #pt],
|
||||
)
|
||||
}
|
||||
)
|
||||
#context {
|
||||
state("exercise-registry").update( arr => {
|
||||
if (arr.len() == 0) {
|
||||
arr
|
||||
} else {
|
||||
let new_arr = arr.slice(0, arr.len()-1)
|
||||
new_arr.push((arr.last().at(0), arr.last().at(1), exercise_points))
|
||||
new_arr
|
||||
}
|
||||
})
|
||||
|
||||
#if override-points {
|
||||
context {
|
||||
state("exercise-registry").update( arr => {
|
||||
if (arr.len() == 0) {
|
||||
arr
|
||||
} else {
|
||||
let new_arr = arr.slice(0, arr.len()-1)
|
||||
new_arr.push((arr.last().at(0), arr.last().at(1), exercise_points))
|
||||
new_arr
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
|
|
@ -100,7 +103,7 @@
|
|||
// Used to compute the overview table (see below)
|
||||
// title: string, title of the exercise
|
||||
// points: int, the number of points the exercise is worth
|
||||
#let exercise_header(title, points) = {
|
||||
#let exercise(title, points, numbering: "1") = {
|
||||
// state("exercise_points").update(points)
|
||||
let exercise_counter = counter("exercise")
|
||||
exercise_counter.step()
|
||||
|
|
@ -111,32 +114,33 @@
|
|||
if (exercise_registry.final().len() >= current_exercise) {
|
||||
final_points = exercise_registry.final().at(exercise_counter.get().at(0)-1).at(2)
|
||||
}
|
||||
let exercise_label = exercise_counter.display()
|
||||
let exercise_label = exercise_counter.display(numbering)
|
||||
exercise_registry.update(entries => entries + ((exercise_label, title, points),))
|
||||
block(radius: 1cm, stroke: none, fill: lightgray, inset: 1pt,
|
||||
table(
|
||||
columns: (auto, 1fr, auto),
|
||||
align: (left, center, right),
|
||||
stroke: none,
|
||||
[#rect(radius:1cm, outset: 4pt, inset: (x:2pt, y:0pt), fill: white)[*#get_L("exercise") #context{exercise_counter.display()}*]], [#title], [#rect(radius:1cm, outset: 4pt, inset: (x:2pt, y:0pt), fill: white)[*#format_points(final_points)*]],
|
||||
[#rect(radius:1cm, outset: 4pt, inset: (x:2pt, y:0pt), fill: white)[*#get_L("exercise") #context{exercise_counter.display(numbering)}*]], [#title], [#rect(radius:1cm, outset: 4pt, inset: (x:2pt, y:0pt), fill: white)[*#format_points(final_points)*]],
|
||||
)
|
||||
)}}
|
||||
|
||||
#let exam(
|
||||
title: "%KLAUSUR or EXAM%",
|
||||
|
||||
course_title: [%COURSE_TITLE_FIRST_LINE% \ %COURSE_TITLE_SECOND_LINE%],
|
||||
course_short_title: "%COURSE_SHORT_TITLE%",
|
||||
course-title: [%COURSE_TITLE_FIRST_LINE% \ %COURSE_TITLE_SECOND_LINE%],
|
||||
course-short-title: "%course-short-title%",
|
||||
course-code: "%course-code%",
|
||||
|
||||
date: "%DATE%",
|
||||
|
||||
institution: smallcaps("NAWI Graz"),
|
||||
|
||||
course_number: "%COURSE_NUMBER%",
|
||||
duration_minutes: "%DURATION%",
|
||||
duration-minutes: "%DURATION%",
|
||||
|
||||
ask_student_number: false,
|
||||
ask_trainer_name: false,
|
||||
ask_group: true,
|
||||
ask-student-number: false,
|
||||
ask-trainer-name: false,
|
||||
ask-group: true,
|
||||
|
||||
instructions: none,
|
||||
|
||||
|
|
@ -162,7 +166,7 @@ set text(size: font-size, lang: language, hyphenate: true)
|
|||
let translations = none
|
||||
if language == "en" {
|
||||
translations = (
|
||||
course_number: "Course number",
|
||||
course-code: "Course code",
|
||||
exam_duration: "Exam duration",
|
||||
student_name: "Name",
|
||||
student_number: "Student number",
|
||||
|
|
@ -180,7 +184,7 @@ if language == "en" {
|
|||
)
|
||||
} else if language == "de" {
|
||||
translations = (
|
||||
course_number: "LV-Nummer",
|
||||
course-code: "LV-Nummer",
|
||||
exam_duration: "Arbeitszeit",
|
||||
student_name: "Name",
|
||||
student_number: "Matrikelnr.",
|
||||
|
|
@ -260,7 +264,7 @@ set page(
|
|||
inset: 0pt,
|
||||
align: (x, y) => { if x < 2 { left+bottom } else { right }},
|
||||
columns: (auto, 1fr, auto),
|
||||
[#institution], [], [#course_short_title \ _#(date)_],
|
||||
[#institution], [], [#course-short-title \ _#(date)_],
|
||||
)
|
||||
],
|
||||
footer: [#align(right)[#context(counter(page).display("1 / 1", both:true))]],
|
||||
|
|
@ -271,10 +275,10 @@ set page(
|
|||
v(1fr)
|
||||
align(center)[= #title]
|
||||
v(0.5cm)
|
||||
align(center)[== #course_title]
|
||||
align(center)[== #course-title]
|
||||
v(1fr)
|
||||
|
||||
[*#get_L("course_number")*: #course_number* \ #get_L("exam_duration"): #duration_minutes #get_L("minutes")*]
|
||||
[*#get_L("course-code")*: #course-code \ *#get_L("exam_duration"): #duration-minutes #get_L("minutes")*]
|
||||
|
||||
v(0.5cm)
|
||||
|
||||
|
|
@ -286,13 +290,13 @@ block(radius: 0.2cm, fill: lightgray, inset: 3pt, clip: true, table(
|
|||
inset: (left:7pt, right:0pt, y:0pt),
|
||||
align: horizon,
|
||||
[#get_L("student_name")], rect(fill: white, width: 100%, radius: 0.2cm),
|
||||
.. if ask_student_number {
|
||||
.. if ask-student-number {
|
||||
([#get_L("student_number")], rect(fill: white, width: 100%, radius: 0.2cm))
|
||||
},
|
||||
..if ask_trainer_name {
|
||||
..if ask-trainer-name {
|
||||
([#get_L("trainer_name")], rect(fill: white, width: 100%, radius: 0.2cm))
|
||||
},
|
||||
..if ask_group {
|
||||
..if ask-group {
|
||||
([#get_L("group")], rect(fill: white, width: 100%, radius: 0.2cm))
|
||||
}
|
||||
))
|
||||
|
|
|
|||
Binary file not shown.
|
Before Width: | Height: | Size: 64 KiB After Width: | Height: | Size: 179 KiB |
Loading…
Add table
Add a link
Reference in a new issue