Skip to main content

doido_generators/generators/
mailer.rs

1use crate::generator::{GeneratedFile, Generator};
2use crate::generators::{register_module, to_pascal, to_snake};
3use doido_core::Result;
4
5/// Fallback `app/mailers/mod.rs` when the app doesn't have one on disk yet.
6const MAILERS_MOD_BASE: &str = include_str!("../../templates/new/app/mailers/mod.rs");
7const MAILERS_MOD_PATH: &str = "app/mailers/mod.rs";
8
9pub struct MailerGenerator;
10
11/// `Welcome` → `WelcomeMailer` / `welcome_mailer`; `UserMailer` stays as-is.
12fn mailer_type_name(name: &str) -> String {
13    let pascal = to_pascal(name);
14    if pascal.ends_with("Mailer") {
15        pascal
16    } else {
17        format!("{pascal}Mailer")
18    }
19}
20
21/// Module/file stem: `welcome_mailer`, not `user_mailer_mailer`.
22fn mailer_module_snake(name: &str) -> String {
23    let snake = to_snake(name);
24    if snake.ends_with("_mailer") {
25        snake
26    } else {
27        format!("{snake}_mailer")
28    }
29}
30
31impl Generator for MailerGenerator {
32    fn name(&self) -> &str {
33        "mailer"
34    }
35
36    fn generate(&self, args: &[&str]) -> Result<Vec<GeneratedFile>> {
37        let name = args.first().copied().ok_or_else(|| {
38            doido_core::anyhow::anyhow!("mailer generator requires a name argument")
39        })?;
40        let snake = mailer_module_snake(name);
41        let pascal = mailer_type_name(name);
42        let content =
43            crate::templates::get("mailer/mailer.rs.template").replace("{pascal}", &pascal);
44        let test = crate::templates::get("mailer/mailer_test.rs.template")
45            .replace("{pascal}", &pascal)
46            .replace("{snake}", &snake);
47
48        // Register the mailer's module in app/mailers/mod.rs.
49        let existing = std::fs::read_to_string(MAILERS_MOD_PATH)
50            .unwrap_or_else(|_| MAILERS_MOD_BASE.to_string());
51        let mailers_mod = register_module(&existing, &snake, "@generated-mailers");
52
53        Ok(vec![
54            GeneratedFile {
55                path: format!("app/mailers/{snake}.rs"),
56                content,
57            },
58            GeneratedFile {
59                path: MAILERS_MOD_PATH.to_string(),
60                content: mailers_mod,
61            },
62            GeneratedFile {
63                path: format!("tests/{snake}_test.rs"),
64                content: test,
65            },
66        ])
67    }
68}