resufancy 0.1.1

Supercharge your resume with the power of your favourite web development tools
Documentation
use std::cell::RefCell;
use std::io::Read;
use std::rc::Rc;

use filesystem::{FileSystem, OsFileSystem, TempDir, TempFileSystem};
use wkhtmltopdf::PdfApplication;

use crate::error::Result;
use crate::resume::Resume;
use crate::FILE_SYSTEM;

pub struct PdfCompiler<'a, T = OsFileSystem> {
    fs: &'a T,
    compiler: Rc<RefCell<Option<PdfApplication>>>,
}

impl<'a> PdfCompiler<'a, OsFileSystem> {
    pub fn new() -> Self {
        Self {
            fs: &FILE_SYSTEM,
            compiler: Rc::new(RefCell::new(None)),
        }
    }
}

impl<'a, FS: FileSystem> PdfCompiler<'a, FS> {
    pub fn fs<'b: 'a, T: FileSystem>(self, fs: &'b T) -> PdfCompiler<'a, T> {
        PdfCompiler {
            fs,
            compiler: self.compiler,
        }
    }
}

impl<'a, FS: FileSystem + TempFileSystem> PdfCompiler<'a, FS> {
    pub fn compile(&self, resume: &Resume) -> Result<Vec<u8>> {
        let mut compiler = self.compiler.borrow_mut();
        let mut builder = match *compiler {
            Some(ref mut compiler) => compiler.builder(),
            None => {
                let mut app = PdfApplication::new()?;
                let b = app.builder();

                *compiler = Some(app);

                b
            }
        };
        let temp_dir = self.fs.temp_dir("pdf")?;
        let html_path = temp_dir.path().join("resume.html");
        let css_path = temp_dir.path().join("style.css");

        self.fs.create_file(&html_path, &resume.html())?;
        self.fs.create_file(&css_path, &resume.stylesheet())?;

        let mut pdf = builder.build_from_path(&html_path)?;
        let mut bytes: Vec<u8> = vec![];

        pdf.read_to_end(&mut bytes)?;

        Ok(bytes)
    }
}

impl<'a> Default for PdfCompiler<'a, OsFileSystem> {
    fn default() -> Self {
        Self::new()
    }
}

#[cfg(test)]
mod tests {
    use crate::resume::RawResume;
    use crate::templates::BASIC;
    use crate::HtmlCompiler;

    use super::*;

    #[test]
    fn compile_creates_pdf_from_valid_resume() {
        let raw_resume = RawResume::new(BASIC.html(), BASIC.stylesheet());
        let resume = HtmlCompiler::default().compile(&raw_resume).unwrap();
        let compiler = PdfCompiler::default();

        let pdf = compiler.compile(&resume);
        assert!(pdf.is_ok());
    }
}