mdmg 0.1.6

A scaffold prototype code tool
Documentation
use crate::delete_executor::{DeleteExecutor, FSDeleteExecutor, FSDeleteExecutorDeps};
use crate::markdown::parse;
use crate::template::{render, MdmgCtx};
use crate::template_repository::{FSTemplateRepository, TemplateRepository};
use crate::Result;

use std::env::current_dir;
use std::sync::Arc;

pub trait DeleteCommand {
    fn run(&self, plan_name: String, component_name: String) -> Result<()>;
}

pub struct DeleteCommandImpl {
    template_repository_ref: Arc<dyn TemplateRepository>,
    delete_executor_ref: Arc<dyn DeleteExecutor>,
}

trait Dependencies {
    fn template_repository(&self) -> Arc<dyn TemplateRepository>;
    fn delete_executor(&self) -> Arc<dyn DeleteExecutor>;
}

impl Dependencies for DeleteCommandImpl {
    fn template_repository(&self) -> Arc<dyn TemplateRepository> {
        self.template_repository_ref.clone()
    }

    fn delete_executor(&self) -> Arc<dyn DeleteExecutor> {
        self.delete_executor_ref.clone()
    }
}

#[cfg(not(tarpaulin_include))]
impl DeleteCommandImpl {
    pub fn new() -> Self {
        let current_dir = current_dir().expect("failed fetch current dir");
        let delete_executor_deps = Arc::new(FSDeleteExecutorDeps::new());

        DeleteCommandImpl {
            template_repository_ref: Arc::new(FSTemplateRepository::new(current_dir.join(".mdmg"))),
            delete_executor_ref: Arc::new(FSDeleteExecutor::new(delete_executor_deps)),
        }
    }
}

impl DeleteCommand for DeleteCommandImpl {
    fn run(&self, plan_name: String, component_name: String) -> Result<()> {
        let template = self.template_repository().resolve(plan_name)?;
        let render_ctx = MdmgCtx::new(component_name);
        let scaffolds = parse(render(template, &render_ctx)?)?;

        for scaffold in scaffolds.into_iter() {
            match &self.delete_executor().execute(&scaffold) {
                Ok(_) => {}
                Err(e) => eprintln!("{}", e),
            }
        }

        Ok(())
    }
}

#[cfg(not(tarpaulin_include))]
#[cfg(test)]
mod tests {
    use crate::{
        commands::delete::DeleteCommand, delete_executor::DeleteExecutor, file::FileName,
        template_repository::TemplateRepository,
    };

    use super::DeleteCommandImpl;

    use indoc::indoc;
    use std::cell::RefCell;
    use std::sync::Arc;

    #[test]
    pub fn success_delete_command() {
        #[derive(Default)]
        struct StubTemplateRepository {}

        #[derive(Default)]
        struct StubDeleteExecutor {
            pub deleted_file: RefCell<Vec<String>>,
        }

        impl TemplateRepository for StubTemplateRepository {
            fn resolve(&self, _template_name: String) -> crate::Result<crate::template::Template> {
                Ok(crate::template::Template::new(
                    indoc! {"
                    ## foobar/foo/bar01.md

                    ```
                    dummy
                    ```

                    ## foobar/foo/bar02.md

                    ```
                    dummy
                    ```
                "}
                    .to_string(),
                ))
            }

            fn list(&self) -> crate::Result<Vec<FileName>> {
                unimplemented!()
            }
        }

        impl DeleteExecutor for StubDeleteExecutor {
            fn execute(&self, scaffold: &crate::scaffold::Scaffold) -> crate::Result<()> {
                match scaffold {
                    crate::scaffold::Scaffold::Complete {
                        file_name,
                        file_body: _,
                    } => self.deleted_file.borrow_mut().push(file_name.clone()),
                    crate::scaffold::Scaffold::Pending { file_name } => {
                        self.deleted_file.borrow_mut().push(file_name.clone())
                    }
                }
                Ok(())
            }
        }

        let stub_delete_executor_ref = Arc::new(StubDeleteExecutor::default());

        impl DeleteCommandImpl {
            fn dummy_new(stub_delete_executor_ref: Arc<StubDeleteExecutor>) -> Self {
                DeleteCommandImpl {
                    template_repository_ref: Arc::new(StubTemplateRepository::default()),
                    delete_executor_ref: stub_delete_executor_ref,
                }
            }
        }

        let delete_command = DeleteCommandImpl::dummy_new(stub_delete_executor_ref.clone());
        let actual = delete_command.run("dummy".to_string(), "dummy".to_string());

        assert!(actual.is_ok());
        assert_eq!(
            *stub_delete_executor_ref.deleted_file.borrow(),
            vec![
                "foobar/foo/bar01.md".to_string(),
                "foobar/foo/bar02.md".to_string()
            ]
        );
    }
}