Skip to content

Commit

Permalink
feat: replacement stage
Browse files Browse the repository at this point in the history
  • Loading branch information
alexpovel committed Sep 17, 2023
1 parent aa6b420 commit 8886880
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 1 deletion.
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,14 @@ regex = "1.9.5"

[features]
default = ["all"]
all = ["german", "symbols", "deletion", "squeeze", "upper", "lower"]
all = ["german", "symbols", "deletion", "squeeze", "upper", "lower", "replace"]
german = []
symbols = []
deletion = []
squeeze = []
upper = []
lower = []
replace = []

[dev-dependencies]
assert_cmd = "2.0.12"
Expand Down
11 changes: 11 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ use betterletters::stages::DeletionStage;
use betterletters::stages::GermanStage;
#[cfg(feature = "lower")]
use betterletters::stages::LowerStage;
#[cfg(feature = "replace")]
use betterletters::stages::ReplacementStage;
#[cfg(feature = "squeeze")]
use betterletters::stages::SqueezeStage;
#[cfg(feature = "upper")]
Expand All @@ -27,6 +29,11 @@ fn main() -> Result<(), Error> {

let mut stages: Vec<Box<dyn betterletters::Stage>> = Vec::new();

if let Some(replacement) = args.replace {
stages.push(Box::new(ReplacementStage::new(replacement)));
debug!("Loaded stage: Replacement");
}

if args.squeeze {
stages.push(Box::<SqueezeStage>::default());
debug!("Loaded stage: Squeeze");
Expand Down Expand Up @@ -124,6 +131,10 @@ mod cli {
#[arg(value_name = "SCOPE", default_value = GLOBAL_SCOPE)]
pub scope: regex::Regex,
/// Replace scope by this (fixed) value
///
/// Specially treated stage for ergonomics and compatibility with `tr`.
///
/// If given, will run before any other stage.
#[arg(value_name = "REPLACEMENT", env = "REPLACE")]
pub replace: Option<String>,
/// Uppercase scope
Expand Down
3 changes: 3 additions & 0 deletions src/stages/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ mod deletion;
mod german;
#[cfg(feature = "lower")]
mod lower;
#[cfg(feature = "replace")]
mod replace;
#[cfg(feature = "squeeze")]
mod squeeze;
#[cfg(feature = "symbols")]
Expand All @@ -16,6 +18,7 @@ use std::fmt::Debug;
pub use deletion::DeletionStage;
pub use german::GermanStage;
pub use lower::LowerStage;
pub use replace::ReplacementStage;
pub use squeeze::SqueezeStage;
pub use symbols::inversion::SymbolsInversionStage;
pub use symbols::SymbolsStage;
Expand Down
63 changes: 63 additions & 0 deletions src/stages/replace/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
use log::info;

use crate::scoped::Scoped;

use super::Stage;

/// Replaces input with a fixed string.
///
/// ## Example: replacing invalid characters in identifiers
///
/// ```
/// use betterletters::stages::{Stage, ReplacementStage};
/// use betterletters::scoped::Scope;
/// use regex::Regex;
///
/// let stage = ReplacementStage::new("_".to_string());
/// let scope = Scope::new(Regex::new(r"[^a-zA-Z0-9]+").unwrap());
///
/// assert_eq!(
/// stage.apply("hyphenated-variable-name", &scope),
/// "hyphenated_variable_name"
/// );
/// ```
///
/// ## Example: replace emojis
///
/// ```
/// use betterletters::stages::{Stage, ReplacementStage};
/// use betterletters::scoped::Scope;
/// use regex::Regex;
///
/// let stage = ReplacementStage::new(":(".to_string());
/// // A Unicode character class category. See also
/// // https://github.com/rust-lang/regex/blob/061ee815ef2c44101dba7b0b124600fcb03c1912/UNICODE.md#rl12-properties
/// let scope = Scope::new(Regex::new(r"\p{Emoji}").unwrap());
///
/// assert_eq!(
/// stage.apply("Party! 😁 💃 🎉 🥳 So much fun! ╰(°▽°)╯", &scope),
/// // Party is over, sorry ¯\_(ツ)_/¯
/// "Party! :( :( :( :( So much fun! ╰(°▽°)╯"
/// );
/// ```
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct ReplacementStage {
replacement: String,
}

impl ReplacementStage {
/// Creates a new `ReplacementStage`.
#[must_use]
pub fn new(replacement: String) -> Self {
Self { replacement }
}
}

impl Scoped for ReplacementStage {}

impl Stage for ReplacementStage {
fn substitute(&self, input: &str) -> String {
info!("Substituting {} with {}", input, self.replacement);
self.replacement.clone()
}
}

0 comments on commit 8886880

Please sign in to comment.