quickstart_lib/template/
mod.rs

1//! Template system for project generation
2//!
3//! This module handles loading, rendering, and managing templates for
4//! project scaffolding with variable substitution and conditional sections.
5
6mod engine;
7mod loader;
8mod variables;
9
10pub use engine::TemplateEngine;
11pub use loader::TemplateLoader;
12pub use variables::TemplateVariables;
13
14/// Represents the variant of templates to use
15#[derive(Debug, Clone, Copy)]
16pub enum TemplateVariant {
17    /// Essential files only
18    Minimal,
19    /// Full-featured setup with additional tooling
20    Extended,
21}
22
23impl Default for TemplateVariant {
24    fn default() -> Self {
25        Self::Extended
26    }
27}
28
29/// Error type for template-related operations
30#[derive(Debug, thiserror::Error)]
31pub enum TemplateError {
32    /// Failed to load template from filesystem
33    #[error("Failed to load template at {path}: {source}")]
34    LoadError {
35        /// Template path
36        path: String,
37        /// Source error
38        source: std::io::Error,
39    },
40
41    /// Failed to render template
42    #[error("Failed to render template {name}: {source}")]
43    RenderError {
44        /// Template name
45        name: String,
46        /// Source error
47        source: handlebars::RenderError,
48    },
49
50    /// Template was not found
51    #[error("Template not found: {path}")]
52    TemplateNotFound {
53        /// Template path
54        path: String,
55    },
56}
57
58/// Result type for template operations
59pub type Result<T> = std::result::Result<T, TemplateError>;
60
61#[cfg(test)]
62mod tests {
63    use super::*;
64    use handlebars::RenderErrorReason;
65    use pretty_assertions::assert_eq;
66    use std::fmt::Debug;
67    use std::io;
68
69    #[test]
70    fn test_template_variant_enum() {
71        let _min = TemplateVariant::Minimal;
72        let _ext = TemplateVariant::Extended;
73        assert_eq!(
74            TemplateVariant::default() as u8,
75            TemplateVariant::Extended as u8
76        );
77    }
78
79    #[test]
80    fn test_template_error_variants() {
81        // LoadError
82        let err = TemplateError::LoadError {
83            path: "foo".to_string(),
84            source: io::Error::other("fail"),
85        };
86        assert!(format!("{err}").contains("Failed to load template"));
87
88        // RenderError
89        let render_err = TemplateError::RenderError {
90            name: "bar".to_string(),
91            source: handlebars::RenderError::from(RenderErrorReason::Other("fail".into())),
92        };
93        assert!(format!("{render_err}").contains("Failed to render template"));
94
95        // TemplateNotFound
96        let not_found = TemplateError::TemplateNotFound {
97            path: "baz".to_string(),
98        };
99        assert!(format!("{not_found}").contains("Template not found"));
100    }
101
102    #[test]
103    fn test_result_type() {
104        fn takes_result<T: Debug>(r: Result<T>) -> bool {
105            r.is_ok()
106        }
107        let ok: Result<u8> = Ok(42);
108        let err: Result<u8> = Err(TemplateError::TemplateNotFound { path: "x".into() });
109        assert!(takes_result(ok));
110        assert!(!takes_result(err));
111    }
112}