mlelarge / mdbook-quiz

Interactive quizzes for Markdown

Home Page:https://willcrichton.net/mdbook-quiz/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

mdbook-quiz: interactive quizzes for Markdown

tests crates.io

live demo

This repository provides an mdBook preprocessor that allows you to add interactive quizzes to your Markdown books. A quiz looks like this:

Screenshot of mdbook-quiz embedded in a web page

Table of contents:

Installation

These instructions assume you have an mdBook already set up. Unfamiliar with mdBook? Read the mdBook guide!

From crates.io

cargo install mdbook-quiz

Note: this tool is under active development. I recommend pinning to a specific version to avoid breakage, e.g. by running

cargo install mdbook-quiz --version <YOUR_VERSION>

And you can check your version by running mdbook-quiz -V. This repository uses semantic versioning for the quiz data format, so your quizzes should not break if you update to a more recent patch.

From source

You need Cargo and pnpm installed. Then run:

git clone https://github.com/willcrichton/mdbook-quiz
cd mdbook-quiz
cargo install --path .

Usage

First, create a quiz file. Quizzes are encoded as TOML files (see Quiz schema). For example:

# quizzes/rust-variables.toml
[[questions]]
type = "ShortAnswer"
prompt.prompt = "What is the keyword for declaring a variable in Rust?"
answer.answer = "let"
context = "For example, you can write: `let x = 1`"

Then in your Markdown file, add a reference to the quiz file:

<!-- src/your-chapter.md -->

And now, a _quiz_:

{{#quiz ../quizzes/rust-variables.toml}}

Configure your book.toml to activate mdbook-quiz.

# book.toml
[preprocessor.quiz]

Then mdbook build should correctly embed the quiz.

Note: due to limitations of mdBook (see mdBook#1087), the mdbook-quiz preprocessor will copy files into your book's source directory under a subdirectory named mdbook-quiz. I recommend adding this directory to your .gitignore.

Quiz schema

A quiz is an array of questions.

export interface Quiz {
  questions: Question[];
}

A question is one of a set of predefined question types.

export type Question = ShortAnswer | Tracing | MultipleChoice;

Each question type is an instantiation of this Typescript interface:

export interface QuestionFields<Type extends string, Prompt, Answer> {
  type: Type;
  prompt: Prompt;
  answer: Answer;
  context?: Markdown;
}

It has a discriminating string name type and then a prompt and answer, along with additional context for explaining the answer.

Note that the Markdown type is just a string, but will be interpreted as Markdown by the quiz renderer.

Currently, mdbook-quiz supports these question types:


Short answer

A question where the answer is a one-line string.

Example

[[questions]]
type = "ShortAnswer"
prompt.prompt = "What is the keyword for declaring a variable in Rust?"
answer.answer = "let"
context = "For example, you can write: `let x = 1`"

Interface

export interface ShortAnswerPrompt {
  /** The text of the prompt. */
  prompt: Markdown;
}

export interface ShortAnswerAnswer {
  /** The exact string that answers the question. */
  answer: string;
}

export type ShortAnswer = QuestionFields<"ShortAnswer", ShortAnswerPrompt, ShortAnswerAnswer>;

Multiple choice

A question with multiple options that the user selects from.

Example

[[questions]]
type = "MultipleChoice"
prompt.prompt = "What does it mean if a variable `x` is immutable?"
prompt.choices = [
  "`x` is stored in the immutable region of memory.",
  "After being defined, `x` can be changed at most once.",
  "`x` cannot be changed after being assigned to a value.",
  "You cannot create a reference to `x`."
]
answer.answer = 2
context = """
Immutable means "not mutable", or not changeable.
"""

Interface

export interface MultipleChoicePrompt {
  /** The text of the prompt. */
  prompt: Markdown;
  
  /** An array of text explaining each choice. */
  choices: Markdown[];
}

export interface MultipleChoiceAnswer {
  /** The index of the correct answer in the choices array (0-based). */
  answer: number;
}

Tracing

A question where the user has to predict how a program will execute (or fail to compile).

Example

[[questions]]
type = "Tracing"
prompt.program = """
fn main() {
  let x = 1;
  println!("{x}");
  x += 1;
  println!("{x}");
}
"""
answer.doesCompile = false
answer.lineNumber = 4
context = """
This is a compiler error because line 4 tries to mutate `x` when `x` is not marked as `mut`.
"""

Interface

export interface TracingPrompt {
  /** The contents of the program to trace */
  program: string;
}

export interface TracingAnswer {
  /** True if the program should pass the compiler */
  doesCompile: boolean;

  /** If doesCompile=true, then the contents of stdout after running the program */
  stdout?: string;

  /** If doesCompile=false, then the line number of the code causing the error */
  lineNumber?: number;
}

export type Tracing = QuestionFields<"Tracing", TracingPrompt, TracingAnswer>;

Quiz configuration

You can configure mdbook-quiz by adding options to the [preprocessor.quiz] section of book.toml. The options are:

  • validate (boolean): If true, then mdbook-quiz will validate your quiz TOML files using the validator.js script installed with mdbook-quiz. You must have NodeJS installed on your machine and PATH for this to work.
  • fullscreen (boolean): If true, then a quiz will take up the web page's full screen during use.
  • cache-answers (boolean): If true, then the user's answers will be saved in their browser's localStorage. Then the quiz will show the user's answers even after they reload the page.

About

Interactive quizzes for Markdown

https://willcrichton.net/mdbook-quiz/

License:MIT License


Languages

Language:TypeScript 66.0%Language:Rust 16.9%Language:SCSS 9.8%Language:JavaScript 7.4%