resume_generator/
project.rs

1crate::ix!();
2
3#[derive(Debug,Clone)]
4pub struct ResumeProjects(Vec<ResumeProject>);
5
6impl From<Vec<ResumeProject>> for ResumeProjects {
7    fn from(x: Vec<ResumeProject>) -> Self {
8        Self(x)
9    }
10}
11
12impl ResumeProjects {
13    delegate!{
14        to self.0 {
15            pub fn is_empty(&self) -> bool;
16            pub fn len(&self) -> usize;
17        }
18    }
19}
20
21impl LatexSectionItem for ResumeProjects {
22
23    fn render_latex_snippet(&self) -> String {
24
25        let mut result = String::new();
26
27        if !self.0.is_empty() {
28
29            result.push_str(r#"\section*{Projects}\begin{itemize}[leftmargin=*, label=-]"#);
30
31            for project in &self.0 {
32                result.push_str(&project.render_latex_snippet());
33            }
34
35            result.push_str(r#"\end{itemize}\vspace{2pt}"#);
36        }
37
38        result
39    }
40}
41
42#[derive(Debug,Clone)]
43pub struct ResumeProject {
44    title:       String,
45    dates:       DateRange,
46    description: Vec<String>,
47}
48
49impl LatexSectionItem for ResumeProject {
50
51    fn render_latex_snippet(&self) -> String {
52        let mut result = String::new();
53        result.push_str(&format!(
54            indoc! {r#"
55            \item \textbf{{{}}} \hfill \textit{{{}}} \\
56            "#},
57            self.title, format_date_range(&self.dates)
58        ));
59        if !self.description.is_empty() {
60            result.push_str(r#"\begin{itemize}[leftmargin=*, label=-]"#);
61            for desc in &self.description {
62                result.push_str(&format!("    \\item {}\n", desc));
63            }
64            result.push_str(r#"\end{itemize}"#);
65        }
66        result
67    }
68}
69
70impl ResumeProject {
71
72    pub fn builder() -> ResumeProjectBuilder {
73        ResumeProjectBuilder::default()
74    }
75
76    pub fn new(title: String, dates: DateRange, description: Vec<String>) -> Self {
77        Self { title, dates, description }
78    }
79
80    pub fn title(&self) -> &str {
81        &self.title
82    }
83
84    pub fn dates(&self) -> &DateRange {
85        &self.dates
86    }
87
88    pub fn description(&self) -> &[String] {
89        &self.description
90    }
91}
92
93#[derive(Default)]
94pub struct ResumeProjectBuilder {
95    title:       Option<String>,
96    dates:       Option<DateRange>,
97    description: Vec<String>,
98}
99
100impl ResumeProjectBuilder {
101    pub fn title(mut self, title: String) -> Self {
102        self.title = Some(title);
103        self
104    }
105
106    pub fn dates(mut self, dates: DateRange) -> Self {
107        self.dates = Some(dates);
108        self
109    }
110
111    pub fn description(mut self, description: Vec<String>) -> Self {
112        self.description = description;
113        self
114    }
115
116    pub fn build(self) -> ResumeProject {
117        ResumeProject {
118            title: self.title.expect("Title is required"),
119            dates: self.dates.expect("Dates are required"),
120            description: self.description,
121        }
122    }
123}