Skip to content

Commit

Permalink
Implement clippy suggestions
Browse files Browse the repository at this point in the history
  • Loading branch information
msuchane committed Jun 27, 2022
1 parent fd1357e commit 01703c3
Show file tree
Hide file tree
Showing 7 changed files with 75 additions and 59 deletions.
1 change: 1 addition & 0 deletions src/cmd_line.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
use clap::{command, Arg, ArgGroup, ArgMatches};

/// Define the command-line arguments and return them as the `clap::ArgMatches` struct.
#[must_use]
pub fn get_args() -> ArgMatches {
// Define command-line options
let matches = command!()
Expand Down
23 changes: 12 additions & 11 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ mod templating;
mod validation;
mod write;

pub use module::{Input, Module, ModuleType};
pub use module::{ContentType, Input, Module};

/// This struct stores options based on the command-line arguments,
/// and is passed to various functions across the program.
Expand All @@ -23,6 +23,7 @@ pub struct Options {

impl Options {
/// Set current options based on the command-line options
#[must_use]
pub fn new(args: &ArgMatches) -> Self {
// Determine the configured verbosity level.
// The clap configuration ensures that verbose and quiet
Expand Down Expand Up @@ -60,7 +61,7 @@ pub enum Verbosity {
Quiet,
}

pub fn run(options: Options, cmdline_args: ArgMatches) -> Result<()> {
pub fn run(options: &Options, cmdline_args: &ArgMatches) -> Result<()> {
// Initialize the logging system based on the set verbosity
logging::initialize_logger(options.verbosity)?;

Expand All @@ -74,7 +75,7 @@ pub fn run(options: Options, cmdline_args: ArgMatches) -> Result<()> {
for module_type_str in ["assembly", "concept", "procedure", "reference", "snippet"] {
// Check if the given module type occurs on the command line
if let Some(titles_iterator) = cmdline_args.values_of(module_type_str) {
let mut modules = process_module_type(titles_iterator, module_type_str, &options);
let mut modules = process_module_type(titles_iterator, module_type_str, options);

// Move all the newly created modules into the common Vec
non_populated.append(&mut modules);
Expand All @@ -83,7 +84,7 @@ pub fn run(options: Options, cmdline_args: ArgMatches) -> Result<()> {

// Write all non-populated modules to the disk
for module in &non_populated {
module.write_file(&options)?;
module.write_file(options)?;
}

// Treat the populated assembly module as a special case:
Expand All @@ -100,11 +101,11 @@ pub fn run(options: Options, cmdline_args: ArgMatches) -> Result<()> {
assert!(!include_statements.is_empty());

// Generate the populated assembly module
let populated: Module = Input::new(ModuleType::Assembly, title, &options)
let populated: Module = Input::new(ContentType::Assembly, title, options)
.include(include_statements)
.into();

populated.write_file(&options)?;
populated.write_file(options)?;
}

// Validate all file names specified on the command line
Expand All @@ -125,11 +126,11 @@ fn process_module_type(
options: &Options,
) -> Vec<Module> {
let module_type = match module_type_str {
"assembly" | "include-in" => ModuleType::Assembly,
"concept" => ModuleType::Concept,
"procedure" => ModuleType::Procedure,
"reference" => ModuleType::Reference,
"snippet" => ModuleType::Snippet,
"assembly" | "include-in" => ContentType::Assembly,
"concept" => ContentType::Concept,
"procedure" => ContentType::Procedure,
"reference" => ContentType::Reference,
"snippet" => ContentType::Snippet,
_ => unimplemented!(),
};

Expand Down
2 changes: 1 addition & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ fn main() -> Result<()> {
let options = Options::new(&cmdline_args);

// Run the main functionality
newdoc::run(options, cmdline_args)?;
newdoc::run(&options, &cmdline_args)?;

Ok(())
}
45 changes: 27 additions & 18 deletions src/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::Options;

/// All possible types of the AsciiDoc module
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum ModuleType {
pub enum ContentType {
Assembly,
Concept,
Procedure,
Expand All @@ -15,7 +15,7 @@ pub enum ModuleType {
}

// Implement human-readable string display for the module type
impl fmt::Display for ModuleType {
impl fmt::Display for ContentType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let name = match self {
Self::Assembly => "assembly",
Expand All @@ -31,7 +31,7 @@ impl fmt::Display for ModuleType {
/// An initial representation of the module with input data, used to construct the `Module` struct
#[derive(Debug)]
pub struct Input {
pub mod_type: ModuleType,
pub mod_type: ContentType,
pub title: String,
pub options: Options,
pub includes: Option<Vec<String>>,
Expand All @@ -40,7 +40,7 @@ pub struct Input {
/// A representation of the module with all its metadata and the generated AsciiDoc content
#[derive(Debug, PartialEq)]
pub struct Module {
mod_type: ModuleType,
mod_type: ContentType,
title: String,
id: String,
pub file_name: String,
Expand All @@ -51,7 +51,8 @@ pub struct Module {

/// Construct a basic builder for `Module`, storing information from the user input.
impl Input {
pub fn new(mod_type: ModuleType, title: &str, options: &Options) -> Input {
#[must_use]
pub fn new(mod_type: ContentType, title: &str, options: &Options) -> Input {
log::debug!("Processing title `{}` of type `{:?}`", title, mod_type);

let title = String::from(title);
Expand All @@ -66,6 +67,7 @@ impl Input {
}

/// Set the optional include statements for files that this assembly includes
#[must_use]
pub fn include(mut self, include_statements: Vec<String>) -> Self {
self.includes = Some(include_statements);
self
Expand All @@ -76,6 +78,7 @@ impl Input {
/// * An AsciiDoc section ID
/// * A DocBook section ID
/// * A file name
#[must_use]
pub fn id(&self) -> String {
let title = &self.title;
// The ID is all lower-case
Expand Down Expand Up @@ -161,6 +164,7 @@ impl Input {
/// Prepare the file name for the generated file.
///
/// The file name is based on the module ID, with the `.adoc` extension.
#[must_use]
pub fn file_name(&self) -> String {
let suffix = ".adoc";

Expand All @@ -171,11 +175,11 @@ impl Input {
if self.options.prefixes {
// If prefixes are enabled, pick the right file prefix
match self.mod_type {
ModuleType::Assembly => "assembly_",
ModuleType::Concept => "con_",
ModuleType::Procedure => "proc_",
ModuleType::Reference => "ref_",
ModuleType::Snippet => "snip_",
ContentType::Assembly => "assembly_",
ContentType::Concept => "con_",
ContentType::Procedure => "proc_",
ContentType::Reference => "ref_",
ContentType::Snippet => "snip_",
}
} else {
// If prefixes are disabled, use an empty string for the prefix
Expand Down Expand Up @@ -206,8 +210,8 @@ impl Input {
// The first directory in the include path is either `assemblies/` or `modules/`,
// based on the module type, or `snippets/` for snippet files.
let include_root = match &self.mod_type {
ModuleType::Assembly => "assemblies",
ModuleType::Snippet => "snippets",
ContentType::Assembly => "assemblies",
ContentType::Snippet => "snippets",
_ => "modules",
};

Expand Down Expand Up @@ -277,7 +281,8 @@ impl From<Input> for Module {
impl Module {
/// The constructor for the Module struct. Creates a basic version of Module
/// without any optional features.
pub fn new(mod_type: ModuleType, title: &str, options: &Options) -> Module {
#[must_use]
pub fn new(mod_type: ContentType, title: &str, options: &Options) -> Module {
let input = Input::new(mod_type, title, options);
input.into()
}
Expand Down Expand Up @@ -312,12 +317,12 @@ mod tests {
fn check_basic_assembly_fields() {
let options = basic_options();
let assembly = Module::new(
ModuleType::Assembly,
ContentType::Assembly,
"A testing assembly with /special-characters*",
&options,
);

assert_eq!(assembly.mod_type, ModuleType::Assembly);
assert_eq!(assembly.mod_type, ContentType::Assembly);
assert_eq!(
assembly.title,
"A testing assembly with /special-characters*"
Expand All @@ -338,12 +343,12 @@ mod tests {
fn check_module_builder_and_new() {
let options = basic_options();
let from_new: Module = Module::new(
ModuleType::Assembly,
ContentType::Assembly,
"A testing assembly with /special-characters*",
&options,
);
let from_builder: Module = Input::new(
ModuleType::Assembly,
ContentType::Assembly,
"A testing assembly with /special-characters*",
&options,
)
Expand All @@ -355,7 +360,11 @@ mod tests {
fn check_detected_path() {
let options = path_options();

let module = Module::new(ModuleType::Procedure, "Testing the detected path", &options);
let module = Module::new(
ContentType::Procedure,
"Testing the detected path",
&options,
);

assert_eq!(
module.include_statement,
Expand Down
13 changes: 7 additions & 6 deletions src/templating.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use askama::Template;
use regex::{Regex, RegexBuilder};

use crate::module::{Input, ModuleType};
use crate::module::{ContentType, Input};

// A note on the structure of this file:
// This file repeats a lot of code when it configures the Askama templates.
Expand Down Expand Up @@ -78,34 +78,35 @@ impl Input {

/// Perform string replacements in the modular template that matches the `ModuleType`.
/// Return the template text with all replacements.
#[must_use]
pub fn text(&self) -> String {
let mut document = match self.mod_type {
ModuleType::Assembly => AssemblyTemplate {
ContentType::Assembly => AssemblyTemplate {
module_id: &self.id(),
module_title: &self.title,
include_statements: &self.includes_block(),
examples: self.options.examples,
}
.render(),
ModuleType::Concept => ConceptTemplate {
ContentType::Concept => ConceptTemplate {
module_id: &self.id(),
module_title: &self.title,
examples: self.options.examples,
}
.render(),
ModuleType::Procedure => ProcedureTemplate {
ContentType::Procedure => ProcedureTemplate {
module_id: &self.id(),
module_title: &self.title,
examples: self.options.examples,
}
.render(),
ModuleType::Reference => ReferenceTemplate {
ContentType::Reference => ReferenceTemplate {
module_id: &self.id(),
module_title: &self.title,
examples: self.options.examples,
}
.render(),
ModuleType::Snippet => SnippetTemplate {
ContentType::Snippet => SnippetTemplate {
module_title: &self.title,
examples: self.options.examples,
}
Expand Down
30 changes: 17 additions & 13 deletions src/validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use std::path::Path;
use color_eyre::eyre::{Context, Result};
use regex::{Regex, RegexBuilder};

use crate::module::ModuleType;
use crate::module::ContentType;

#[derive(Clone, Copy, Debug)]
struct IssueDefinition {
Expand Down Expand Up @@ -110,7 +110,7 @@ pub fn validate(file_name: &str) -> Result<()> {

let reports = match mod_type {
// If the file is an assembly, test the assembly requirements
ModTypeOrReport::Type(ModuleType::Assembly) => assembly::check(&content),
ModTypeOrReport::Type(ContentType::Assembly) => assembly::check(&content),
// If the module type is indeterminate, test the requirements that don't depend on the type
ModTypeOrReport::Report(type_report) => {
let mut reports = check_common(&content);
Expand Down Expand Up @@ -150,17 +150,21 @@ fn report_issues(mut issues: Vec<IssueReport>, file_path: &str) {
/// This enum contains either the module type determined from a file, or an issue report saying
/// that the module type could not be determined.
enum ModTypeOrReport {
Type(ModuleType),
Type(ContentType),
Report(IssueReport),
}

/// Try to determine the module type of a file, using the file name and the file content.
fn determine_mod_type(base_name: &str, content: &str) -> ModTypeOrReport {
let mod_patterns = [
("assembly", ":_content-type: ASSEMBLY", ModuleType::Assembly),
("con", ":_content-type: CONCEPT", ModuleType::Concept),
("proc", ":_content-type: PROCEDURE", ModuleType::Procedure),
("ref", ":_content-type: REFERENCE", ModuleType::Reference),
(
"assembly",
":_content-type: ASSEMBLY",
ContentType::Assembly,
),
("con", ":_content-type: CONCEPT", ContentType::Concept),
("proc", ":_content-type: PROCEDURE", ContentType::Procedure),
("ref", ":_content-type: REFERENCE", ContentType::Reference),
];
for pattern in &mod_patterns {
if base_name.starts_with(pattern.0) || content.contains(pattern.1) {
Expand Down Expand Up @@ -235,7 +239,7 @@ mod title {
fn find_first_heading(content: &str) -> Option<(usize, &str)> {
let any_heading_regex = Regex::new(r"^(\.|=+\s+)\S+.*").unwrap();

find_first_occurrence(content, any_heading_regex)
find_first_occurrence(content, &any_heading_regex)
}

/// Check that the first heading found in the file is a title: a level-1, numbered heading
Expand Down Expand Up @@ -340,7 +344,7 @@ mod content {
let metadata_var_pattern =
r":_content-type:\s*(?:ASSEMBLY|PROCEDURE|CONCEPT|REFERENCE|SNIPPET)";
let metadata_var_regex = Regex::new(metadata_var_pattern).unwrap();
let metadata_var = find_first_occurrence(content, metadata_var_regex);
let metadata_var = find_first_occurrence(content, &metadata_var_regex);

let mod_id = find_mod_id(content);

Expand Down Expand Up @@ -377,7 +381,7 @@ mod content {
/// if it exists at all. The abstract flag is not required.
fn check_abstract_flag(content: &str) -> Option<IssueReport> {
let abstract_regex = Regex::new(r#"^\[role="_abstract"\]"#).unwrap();
let abstract_flag = find_first_occurrence(content, abstract_regex);
let abstract_flag = find_first_occurrence(content, &abstract_regex);

// If the file contains an abstract flag, test for the following paragraph
if let Some((line_no, _line)) = abstract_flag {
Expand Down Expand Up @@ -621,7 +625,7 @@ mod additional_resources {
)
.unwrap();

find_first_occurrence(content, add_res_regex)
find_first_occurrence(content, &add_res_regex)
}

/// See if the additional resources heading is missing the additional resources flag,
Expand Down Expand Up @@ -750,11 +754,11 @@ mod additional_resources {
fn find_mod_id(content: &str) -> Option<(usize, &str)> {
let id_regex = Regex::new(r"^\[id=\S+\]").unwrap();

find_first_occurrence(content, id_regex)
find_first_occurrence(content, &id_regex)
}

/// Search for a predefined regex in a file. If found, return the line number and the line text.
fn find_first_occurrence(content: &str, regex: Regex) -> Option<(usize, &str)> {
fn find_first_occurrence<'a>(content: &'a str, regex: &Regex) -> Option<(usize, &'a str)> {
for (index, line) in content.lines().enumerate() {
if let Some(_occurrence) = regex.find(line) {
return Some((index, line));
Expand Down
Loading

0 comments on commit 01703c3

Please sign in to comment.