diff options
| author | Teddy Wing | 2016-04-24 05:40:45 -0400 |
|---|---|---|
| committer | Teddy Wing | 2016-04-24 05:40:45 -0400 |
| commit | afc01ecb67dd978879d423866d33ac0c526151f4 (patch) | |
| tree | 262d27a7ec2c80ab257f53008df57ac5fd16c20f /src/alias.rs | |
| parent | 2d1f7031f03194fbceffc15b1d6376abea243e22 (diff) | |
| download | mutt-alias-auto-add-afc01ecb67dd978879d423866d33ac0c526151f4.tar.bz2 | |
Move `Alias` to separate alias module
Take all of our Alias code, functions, errors, etc. and move them into
their own module. This removes some clutter from our `main.rs` file and
makes things better organised. Now all the alias code lives in its own
dedicated place.
Update our test file imports to match this change.
Updates to alias code:
* Reordered imports alphabetically
* Made `Alias` public
* Made `AliasSearchError` public
* Made all methods on `Alias` public
Diffstat (limited to 'src/alias.rs')
| -rw-r--r-- | src/alias.rs | 152 |
1 files changed, 152 insertions, 0 deletions
diff --git a/src/alias.rs b/src/alias.rs new file mode 100644 index 0000000..8a66db8 --- /dev/null +++ b/src/alias.rs @@ -0,0 +1,152 @@ +use std::error::{self, Error}; +use std::fs::{File, OpenOptions}; +use std::fmt; +use std::io::{self, BufRead, BufReader, Write}; +use std::path::Path; + +#[derive(Clone)] +pub struct Alias { + pub alias: String, + pub name: String, + pub email: String, +} + +impl Alias { + pub fn new(email: &str) -> Alias { + let mut split: Vec<&str> = email.split_whitespace().collect(); + + // Remove "From: " + split.remove(0); + + let mut alias = String::new(); + let mut name = String::new(); + let mut email = String::new(); + + if split.len() == 1 { + alias = split[0].to_lowercase().to_string(); + email = split[0].to_string(); + } else if split.len() == 2 { + alias = split[0].to_lowercase().to_string(); + name = split[0].to_string(); + email = split[1].to_string(); + } else if split.len() > 2 { + alias = format!("{}-{}", split[split.len() - 2], split[0]).to_lowercase().to_string(); + name = split[0..(split.len() - 1)].join(" "); + email = split[split.len() - 1].to_string(); + } + + alias = alias.replace(',', ""); + alias = alias.replace('\'', ""); + alias = alias.replace('"', ""); + + Alias { alias: alias, name: name, email: email } + } + + pub fn to_string(&self) -> String { + if self.name.is_empty() { + format!("alias {} {}", self.alias, self.email) + } else { + format!("alias {} {} {}", self.alias, self.name, self.email) + } + } + + pub fn find_in_file<P: AsRef<Path>>(&self, file: P) -> Result<Vec<String>, AliasSearchError> { + let mut matches = Vec::new(); + let f = try!(File::open(file)); + let file = BufReader::new(&f); + for line in file.lines() { + let line = try!(line); + let split: Vec<&str> = line.split_whitespace().collect(); + + if line.contains(&self.email) { + return Err(AliasSearchError::EmailExists) + } + + if split[1].starts_with(&self.alias) { + matches.push(split[1].to_owned()); + } + } + + if matches.is_empty() { + Err(AliasSearchError::NotFound) + } else { + Ok(matches) + } + } + + pub fn write_to_file<P: AsRef<Path>>(&mut self, file: P) -> Result<(), AliasSearchError> { + let similar_aliases = try!(self.find_in_file(&file)); + self.update_alias_id(similar_aliases); + + let mut f = try!(OpenOptions::new().append(true).open(file)); + try!(f.write_all(format!("{}\n", self.to_string()).as_bytes())); + + Ok(()) + } + + pub fn update_alias_id(&mut self, similar_aliases: Vec<String>) { + if !similar_aliases.is_empty() { + self.alias = format!("{}-{}", self.alias, similar_aliases.len() + 1); + } + } +} + +#[derive(Debug)] +pub enum AliasSearchError { + NotFound, + EmailExists, + Io(io::Error), +} + +impl fmt::Display for AliasSearchError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + AliasSearchError::NotFound => writeln!(f, "{}", self.description()), + AliasSearchError::EmailExists => writeln!(f, "{}", self.description()), + AliasSearchError::Io(ref err) => writeln!(f, "IO error: {}", err), + } + } +} + +impl error::Error for AliasSearchError { + fn description(&self) -> &str { + match *self { + AliasSearchError::NotFound => "Alias could not be found in aliases file", + AliasSearchError::EmailExists => "Email already exists in aliases file", + AliasSearchError::Io(ref err) => err.description(), + } + } + + fn cause(&self) -> Option<&error::Error> { + match *self { + AliasSearchError::Io(ref err) => Some(err), + _ => None, + } + } +} + +impl From<io::Error> for AliasSearchError { + fn from(err: io::Error) -> AliasSearchError { + AliasSearchError::Io(err) + } +} + +#[cfg(test)] +impl PartialEq<AliasSearchError> for AliasSearchError { + fn eq(&self, other: &AliasSearchError) -> bool { + match *self { + AliasSearchError::NotFound => match *other { + AliasSearchError::NotFound => true, + _ => false, + }, + AliasSearchError::EmailExists => match *other { + AliasSearchError::EmailExists => true, + _ => false, + }, + AliasSearchError::Io(_) => match *other { + AliasSearchError::Io(_) => true, + _ => false, + }, + } + } +} |
