Skip to content

Commit 30b1c99

Browse files
committed
Implemented a builder for Module, but with errors
1 parent 94cfe40 commit 30b1c99

File tree

3 files changed

+89
-55
lines changed

3 files changed

+89
-55
lines changed

src/main.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@ mod cmd_line;
22
mod module;
33
mod write;
44

5-
use module::{Module, ModuleType};
5+
use module::{Input, Module, ModuleType};
66

77
/// This struct stores options based on the command-line arguments,
88
/// and is passed to various functions across the program.
9+
#[derive(Debug, Clone)]
910
pub struct Options {
1011
comments: bool,
1112
prefixes: bool,
@@ -65,8 +66,8 @@ fn main() {
6566
assert!(!include_statements.is_empty());
6667

6768
// Generate the populated assembly module
68-
let populated =
69-
Module::new(ModuleType::Assembly, title, &options).includes(include_statements);
69+
let populated: Module =
70+
Input::new(ModuleType::Assembly, title, &options).include(include_statements).into();
7071

7172
populated.write_file(&options);
7273
}
@@ -77,7 +78,7 @@ fn main() {
7778
fn process_module_type(
7879
titles: clap::Values,
7980
module_type_str: &str,
80-
options: &Options,
81+
options: &'static Options,
8182
) -> Vec<Module> {
8283
let mut modules_from_type = Vec::new();
8384

src/module.rs

Lines changed: 81 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,23 @@
11
use crate::Options;
22

33
/// All possible types of the AsciiDoc module
4-
#[derive(Debug)]
4+
#[derive(Debug, Clone)]
55
pub enum ModuleType {
66
Assembly,
77
Concept,
88
Procedure,
99
Reference,
1010
}
1111

12+
/// An initial representation of the module with input data, used to construct the `Module` struct
13+
#[derive(Debug)]
14+
pub struct Input {
15+
mod_type: ModuleType,
16+
title: String,
17+
options: &'static Options,
18+
includes: Option<Vec<String>>,
19+
}
20+
1221
/// A representation of the module with all its metadata and the generated AsciiDoc content
1322
#[derive(Debug)]
1423
pub struct Module {
@@ -17,7 +26,8 @@ pub struct Module {
1726
id: String,
1827
pub file_name: String,
1928
pub include_statement: String,
20-
included: Option<Vec<String>>,
29+
includes: Option<Vec<String>>,
30+
pub text: String,
2131
}
2232

2333
// Load the AsciiDoc templates at build time
@@ -26,27 +36,22 @@ const CONCEPT_TEMPLATE: &str = include_str!("../templates/concept.adoc");
2636
const PROCEDURE_TEMPLATE: &str = include_str!("../templates/procedure.adoc");
2737
const REFERENCE_TEMPLATE: &str = include_str!("../templates/reference.adoc");
2838

29-
impl Module {
30-
/// The constructor for the Module struct
31-
pub fn new(mod_type: ModuleType, title: &str, options: &Options) -> Module {
39+
40+
impl Input {
41+
pub fn new(mod_type: ModuleType, title: &str, options: &'static Options) -> Input {
3242
let title = String::from(title);
33-
let id = Module::convert_title_to_id(&title);
34-
let file_name = Module::compose_file_name(&id, &mod_type, &options);
35-
let include_statement = Module::compose_include_statement(&file_name);
3643

37-
Module {
44+
Input {
3845
mod_type,
3946
title,
40-
id,
41-
file_name,
42-
include_statement,
43-
included: None,
47+
options,
48+
includes: None,
4449
}
4550
}
4651

4752
/// Set the optional include statements for files that this assembly includes
48-
pub fn includes(mut self, include_statements: Vec<String>) -> Self {
49-
self.included = Some(include_statements);
53+
pub fn include(mut self, include_statements: Vec<String>) -> Self {
54+
self.includes = Some(include_statements);
5055
self
5156
}
5257

@@ -55,14 +60,8 @@ impl Module {
5560
/// * An AsciiDoc section ID
5661
/// * A DocBook section ID
5762
/// * A file name
58-
///
59-
/// ## Examples
60-
///
61-
/// ```
62-
/// let title = "Testing newdoc";
63-
/// assert_eq!(String::from("testing-newdoc"), Module::convert_title_to_id(title));
64-
/// ```
65-
fn convert_title_to_id(title: &str) -> String {
63+
pub fn id(&self) -> String {
64+
let title = &self.title;
6665
// The ID is all lower-case
6766
let mut title_with_replacements = String::from(title).to_lowercase();
6867

@@ -127,9 +126,36 @@ impl Module {
127126
title_with_replacements
128127
}
129128

129+
/// Prepare the file name for the generated file.
130+
///
131+
/// The file name is based on the module ID, with the `.adoc` extension and an optional prefix.
132+
pub fn file_name(&self) -> String {
133+
let prefix = if self.options.prefixes {
134+
// If prefixes are enabled, pick the right file prefix
135+
match self.mod_type {
136+
ModuleType::Assembly => "assembly_",
137+
ModuleType::Concept => "con_",
138+
ModuleType::Procedure => "proc_",
139+
ModuleType::Reference => "ref_",
140+
}
141+
} else {
142+
// If prefixes are disabled, use an empty string for the prefix
143+
""
144+
};
145+
146+
let suffix = ".adoc";
147+
148+
[prefix, &self.id(), suffix].join("")
149+
}
150+
151+
/// Prepare an include statement that can be used to include the generated file from elsewhere.
152+
fn include_statement(&self) -> String {
153+
format!("include::<path>/{}[leveloffset=+1]", &self.file_name())
154+
}
155+
130156
/// Perform string replacements in the modular template that matches the `ModuleType`.
131157
/// Return the template text with all replacements.
132-
pub fn compose_text(&self, options: &Options) -> String {
158+
pub fn text(&self) -> String {
133159
// TODO: Add a comment in the generated file with a pre-filled include statement
134160

135161
// Pick the right template
@@ -141,7 +167,7 @@ impl Module {
141167
};
142168

143169
// Define the strings that will be replaced in the template
144-
let replacements = [("${module_title}", &self.title), ("${module_id}", &self.id)];
170+
let replacements = [("${module_title}", &self.title), ("${module_id}", &self.id())];
145171

146172
// Perform substitutions in the template
147173
// TODO: Create a separate function to perform a replacement
@@ -151,7 +177,7 @@ impl Module {
151177
template_with_replacements = template_with_replacements.replace(old, new);
152178
}
153179

154-
if let Some(include_statements) = &self.included {
180+
if let Some(include_statements) = &self.includes {
155181
// The includes should never be empty thanks to the required group in clap
156182
assert!(!include_statements.is_empty());
157183
// Join the includes into a block of text, with blank lines in between to prevent
@@ -167,7 +193,7 @@ impl Module {
167193

168194
// If comments are disabled via an option, delete comment lines from the content
169195
// TODO: This doesn't handle AsciiDoc comment blocks at all
170-
if !options.comments {
196+
if !self.options.comments {
171197
// Filter out comment lines in an iterator
172198
let lines = template_with_replacements
173199
.lines()
@@ -180,31 +206,38 @@ impl Module {
180206

181207
template_with_replacements
182208
}
209+
}
183210

184-
/// Prepare the file name for the generated file.
185-
///
186-
/// The file name is based on the module ID, with the `.adoc` extension and an optional prefix.
187-
fn compose_file_name(module_id: &str, module_type: &ModuleType, options: &Options) -> String {
188-
let prefix = if options.prefixes {
189-
// If prefixes are enabled, pick the right file prefix
190-
match module_type {
191-
ModuleType::Assembly => "assembly_",
192-
ModuleType::Concept => "con_",
193-
ModuleType::Procedure => "proc_",
194-
ModuleType::Reference => "ref_",
195-
}
196-
} else {
197-
// If prefixes are disabled, use an empty string for the prefix
198-
""
199-
};
200211

201-
let suffix = ".adoc";
212+
impl From<Input> for Module {
213+
fn from(input: Input) -> Self {
214+
// TODO: I suspect that these `clone` calls aren't really necessary, but I don't know Rust
215+
// well enough to figure out the proper solution now.
216+
let mod_type = input.mod_type.clone();
217+
let title = input.title.clone();
218+
let id = input.id().clone();
219+
let file_name = input.file_name().clone();
220+
let include_statement = input.include_statement();
221+
let includes = input.includes.clone();
222+
let text = input.text().clone();
202223

203-
[prefix, module_id, suffix].join("")
224+
Module {
225+
mod_type,
226+
title,
227+
id,
228+
file_name,
229+
include_statement,
230+
includes,
231+
text,
232+
}
204233
}
234+
}
205235

206-
/// Prepare an include statement that can be used to include the generated file from elsewhere.
207-
fn compose_include_statement(file_name: &str) -> String {
208-
format!("include::<path>/{}[leveloffset=+1]", file_name)
236+
237+
impl Module {
238+
/// The constructor for the Module struct
239+
pub fn new(mod_type: ModuleType, title: &str, options: &'static Options) -> Module {
240+
let input = Input::new(mod_type, title, options);
241+
input.into()
209242
}
210243
}

src/write.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ use crate::module::Module;
99

1010
impl Module {
1111
/// Write the generated module content to the path specified in `options` with the set file name.
12-
pub fn write_file(&self, options: &Options) {
12+
pub fn write_file(&self) {
1313
// Compose the full (but still relative) file path from the target directory and the file name
14-
let full_path_buf: PathBuf = [&options.target_dir, &self.file_name].iter().collect();
14+
let full_path_buf: PathBuf = [&self.options.target_dir, &self.file_name].iter().collect();
1515
let full_path = full_path_buf.as_path();
1616

1717
// If the target file already exists, just print out an error
@@ -46,7 +46,7 @@ impl Module {
4646
}
4747

4848
// If the target file doesn't exist, try to write to it
49-
let result = fs::write(full_path, &self.compose_text(&options));
49+
let result = fs::write(full_path, &self.text);
5050
match result {
5151
// If the write succeeds, print the include statement
5252
Ok(()) => {

0 commit comments

Comments
 (0)