blendtutor_core/lib.rs
1//! # blendtutor-core
2//!
3//! Domain logic and adapters for blendtutor: the lesson model, language runners
4//! (R and Python), grading, and LLM providers — built up slice by slice.
5//!
6//! This is the reusable core a future Tauri GUI can call directly, with no
7//! process boundary. It deliberately does **not** parse command-line arguments
8//! or render terminal output; that is the responsibility of the `blendtutor-cli`
9//! crate, which depends on this one (the dependency only ever points cli → core).
10
11// This crate is the documented, reusable API surface, so an undocumented public
12// item is a defect rather than a warning: fail the build (rustdoc and ordinary
13// compile alike) until it is documented. AC2 of #3 — "API docs build with no
14// rustdoc warnings" — then holds unconditionally, not only under -D warnings.
15#![deny(missing_docs)]
16
17pub mod course;
18pub mod crypto;
19pub mod eval;
20pub mod grade;
21pub mod lesson;
22pub mod llm;
23pub mod quarto_export;
24pub mod run;
25pub mod runner;
26pub mod scaffold;
27pub mod site;
28pub mod smevals_gen;
29
30use std::error::Error;
31use std::fmt;
32
33/// Error for a command that is planned but not yet implemented in the current slice.
34///
35/// The walking skeleton wires every subcommand through `core` so the cli → core
36/// boundary is real from the start; each command returns this until its slice
37/// lands. Keeping it a typed error (rather than `anyhow`) lets `core` stay free
38/// of the error-reporting crate, which belongs at the CLI edge.
39#[derive(Debug)]
40pub struct NotYetImplemented {
41 command: &'static str,
42}
43
44impl NotYetImplemented {
45 /// Build the error for the named `command` (e.g. `"validate"`).
46 pub const fn new(command: &'static str) -> Self {
47 Self { command }
48 }
49}
50
51impl fmt::Display for NotYetImplemented {
52 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
53 write!(f, "`{}` is not yet implemented", self.command)
54 }
55}
56
57impl Error for NotYetImplemented {}
58
59#[cfg(test)]
60mod tests {
61 use super::*;
62
63 #[test]
64 fn display_names_the_command_and_the_unimplemented_state() {
65 let err = NotYetImplemented::new("validate");
66 assert_eq!(err.to_string(), "`validate` is not yet implemented");
67 }
68}