Skip to content

Commit

Permalink
Remove misc.rs (#491)
Browse files Browse the repository at this point in the history
Put everything that was in `misc.rs` into their own files, with some opportunistic
refactoring, because why not.
  • Loading branch information
casey authored Oct 9, 2019
1 parent ca4f2a4 commit 3de31b3
Show file tree
Hide file tree
Showing 15 changed files with 313 additions and 210 deletions.
18 changes: 9 additions & 9 deletions src/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,22 +31,22 @@ pub(crate) use crate::testing;

// functions
pub(crate) use crate::{
load_dotenv::load_dotenv,
misc::{default, empty},
output::output,
default::default, empty::empty, load_dotenv::load_dotenv, output::output,
write_message_context::write_message_context,
};

// structs and enums
pub(crate) use crate::{
alias::Alias, alias_resolver::AliasResolver, assignment_evaluator::AssignmentEvaluator,
assignment_resolver::AssignmentResolver, color::Color, compilation_error::CompilationError,
compilation_error_kind::CompilationErrorKind, config::Config, config_error::ConfigError,
expression::Expression, fragment::Fragment, function::Function,
function_context::FunctionContext, functions::Functions, interrupt_guard::InterruptGuard,
interrupt_handler::InterruptHandler, justfile::Justfile, lexer::Lexer, output_error::OutputError,
parameter::Parameter, parser::Parser, platform::Platform, position::Position, recipe::Recipe,
recipe_context::RecipeContext, recipe_resolver::RecipeResolver, runtime_error::RuntimeError,
search_error::SearchError, shebang::Shebang, state::State, string_literal::StringLiteral,
count::Count, enclosure::Enclosure, expression::Expression, fragment::Fragment,
function::Function, function_context::FunctionContext, functions::Functions,
interrupt_guard::InterruptGuard, interrupt_handler::InterruptHandler, justfile::Justfile,
lexer::Lexer, list::List, output_error::OutputError, parameter::Parameter, parser::Parser,
platform::Platform, position::Position, recipe::Recipe, recipe_context::RecipeContext,
recipe_resolver::RecipeResolver, runtime_error::RuntimeError, search_error::SearchError,
shebang::Shebang, show_whitespace::ShowWhitespace, state::State, string_literal::StringLiteral,
subcommand::Subcommand, token::Token, token_kind::TokenKind, use_color::UseColor,
variables::Variables, verbosity::Verbosity, warning::Warning,
};
Expand Down
14 changes: 6 additions & 8 deletions src/compilation_error.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
use crate::common::*;

use crate::misc::{maybe_s, show_whitespace, write_message_context, Or};

#[derive(Debug, PartialEq)]
pub(crate) struct CompilationError<'a> {
pub(crate) text: &'a str,
Expand Down Expand Up @@ -82,7 +80,7 @@ impl<'a> Display for CompilationError<'a> {
ref expected,
found,
} => {
writeln!(f, "Expected {}, but found {}", Or(expected), found)?;
writeln!(f, "Expected {}, but found {}", List::or(expected), found)?;
}
DuplicateAlias { alias, first } => {
writeln!(
Expand Down Expand Up @@ -139,7 +137,7 @@ impl<'a> Display for CompilationError<'a> {
f,
"Found a mix of tabs and spaces in leading whitespace: `{}`\n\
Leading whitespace may consist of tabs or spaces, but not both",
show_whitespace(whitespace)
ShowWhitespace(whitespace)
)?;
}
ExtraLeadingWhitespace => {
Expand All @@ -152,10 +150,10 @@ impl<'a> Display for CompilationError<'a> {
} => {
writeln!(
f,
"Function `{}` called with {} argument{} but takes {}",
"Function `{}` called with {} {} but takes {}",
function,
found,
maybe_s(found),
Count("argument", found),
expected
)?;
}
Expand All @@ -164,8 +162,8 @@ impl<'a> Display for CompilationError<'a> {
f,
"Recipe line has inconsistent leading whitespace. \
Recipe started with `{}` but found line with `{}`",
show_whitespace(expected),
show_whitespace(found)
ShowWhitespace(expected),
ShowWhitespace(found)
)?;
}
UnknownAliasTarget { alias, target } => {
Expand Down
25 changes: 25 additions & 0 deletions src/count.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
use crate::common::*;

pub struct Count<T: Display>(pub T, pub usize);

impl<T: Display> Display for Count<T> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
if self.1 == 1 {
write!(f, "{}", self.0)
} else {
write!(f, "{}s", self.0)
}
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn count() {
assert_eq!(Count("dog", 0).to_string(), "dogs");
assert_eq!(Count("dog", 1).to_string(), "dog");
assert_eq!(Count("dog", 2).to_string(), "dogs");
}
}
3 changes: 3 additions & 0 deletions src/default.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pub(crate) fn default<T: Default>() -> T {
Default::default()
}
5 changes: 5 additions & 0 deletions src/empty.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
use crate::common::*;

pub(crate) fn empty<T, C: iter::FromIterator<T>>() -> C {
iter::empty().collect()
}
31 changes: 31 additions & 0 deletions src/enclosure.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
use crate::common::*;

pub struct Enclosure<T: Display> {
enclosure: &'static str,
value: T,
}

impl<T: Display> Enclosure<T> {
pub fn tick(value: T) -> Enclosure<T> {
Enclosure {
enclosure: "`",
value,
}
}
}

impl<T: Display> Display for Enclosure<T> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "{}{}{}", self.enclosure, self.value, self.enclosure)
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn tick() {
assert_eq!(Enclosure::tick("foo").to_string(), "`foo`")
}
}
8 changes: 7 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ mod compilation_error;
mod compilation_error_kind;
mod config;
mod config_error;
mod count;
mod default;
mod empty;
mod enclosure;
mod expression;
mod fragment;
mod function;
Expand All @@ -31,8 +35,8 @@ mod interrupt_guard;
mod interrupt_handler;
mod justfile;
mod lexer;
mod list;
mod load_dotenv;
mod misc;
mod ordinal;
mod output;
mod output_error;
Expand All @@ -50,6 +54,7 @@ mod runtime_error;
mod search;
mod search_error;
mod shebang;
mod show_whitespace;
mod state;
mod string_literal;
mod subcommand;
Expand All @@ -59,6 +64,7 @@ mod use_color;
mod variables;
mod verbosity;
mod warning;
mod write_message_context;

pub use crate::run::run;

Expand Down
123 changes: 123 additions & 0 deletions src/list.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
use crate::common::*;

pub struct List<T: Display, I: Iterator<Item = T> + Clone> {
conjunction: &'static str,
values: I,
}

impl<T: Display, I: Iterator<Item = T> + Clone> List<T, I> {
pub fn or<II: IntoIterator<Item = T, IntoIter = I>>(values: II) -> List<T, I> {
List {
conjunction: "or",
values: values.into_iter(),
}
}

pub fn and<II: IntoIterator<Item = T, IntoIter = I>>(values: II) -> List<T, I> {
List {
conjunction: "and",
values: values.into_iter(),
}
}

pub fn or_ticked<II: IntoIterator<Item = T, IntoIter = I>>(
values: II,
) -> List<Enclosure<T>, impl Iterator<Item = Enclosure<T>> + Clone> {
List::or(values.into_iter().map(Enclosure::tick))
}

pub fn and_ticked<II: IntoIterator<Item = T, IntoIter = I>>(
values: II,
) -> List<Enclosure<T>, impl Iterator<Item = Enclosure<T>> + Clone> {
List::and(values.into_iter().map(Enclosure::tick))
}
}

impl<T: Display, I: Iterator<Item = T> + Clone> Display for List<T, I> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
let mut values = self.values.clone().fuse();

if let Some(first) = values.next() {
write!(f, "{}", first)?;
} else {
return Ok(());
}

let second = values.next();

if second.is_none() {
return Ok(());
}

let third = values.next();

if let (Some(second), None) = (second.as_ref(), third.as_ref()) {
write!(f, " {} {}", self.conjunction, second)?;
return Ok(());
}

let mut current = second;
let mut next = third;

loop {
match (current, next) {
(Some(c), Some(n)) => {
write!(f, ", {}", c)?;
current = Some(n);
next = values.next();
}
(Some(c), None) => {
write!(f, ", {} {}", self.conjunction, c)?;
return Ok(());
}
_ => panic!("Iterator was fused, but returned Some after None"),
}
}
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn or() {
assert_eq!("1", List::or(&[1]).to_string());
assert_eq!("1 or 2", List::or(&[1, 2]).to_string());
assert_eq!("1, 2, or 3", List::or(&[1, 2, 3]).to_string());
assert_eq!("1, 2, 3, or 4", List::or(&[1, 2, 3, 4]).to_string());
}

#[test]
fn and() {
assert_eq!("1", List::and(&[1]).to_string());
assert_eq!("1 and 2", List::and(&[1, 2]).to_string());
assert_eq!("1, 2, and 3", List::and(&[1, 2, 3]).to_string());
assert_eq!("1, 2, 3, and 4", List::and(&[1, 2, 3, 4]).to_string());
}

#[test]
fn or_ticked() {
assert_eq!("`1`", List::or_ticked(&[1]).to_string());
assert_eq!("`1` or `2`", List::or_ticked(&[1, 2]).to_string());
assert_eq!("`1`, `2`, or `3`", List::or_ticked(&[1, 2, 3]).to_string());
assert_eq!(
"`1`, `2`, `3`, or `4`",
List::or_ticked(&[1, 2, 3, 4]).to_string()
);
}

#[test]
fn and_ticked() {
assert_eq!("`1`", List::and_ticked(&[1]).to_string());
assert_eq!("`1` and `2`", List::and_ticked(&[1, 2]).to_string());
assert_eq!(
"`1`, `2`, and `3`",
List::and_ticked(&[1, 2, 3]).to_string()
);
assert_eq!(
"`1`, `2`, `3`, and `4`",
List::and_ticked(&[1, 2, 3, 4]).to_string()
);
}
}
Loading

0 comments on commit 3de31b3

Please sign in to comment.