From c67fdff0c3cda883b5bf577988e1c555931969cf Mon Sep 17 00:00:00 2001 From: Teddy Wing Date: Sun, 24 Apr 2016 04:43:00 -0400 Subject: Move `find_alias_in_file` function to `Alias#find_in_file` Makes more sense for this function to live in a method on `Alias` because it operates directly on an alias. Refactor our tests and code to support this new organisation. --- src/main.rs | 50 +++++++++++++++++++++++++------------------------- 1 file changed, 25 insertions(+), 25 deletions(-) (limited to 'src/main.rs') diff --git a/src/main.rs b/src/main.rs index 75e74ac..0004cc4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -53,6 +53,30 @@ impl Alias { } } + fn find_in_file>(&self, file: P) -> Result, 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) + } + } + fn write_to_file>(&self, file: P) -> Result<(), io::Error> { let mut f = try!(OpenOptions::new().append(true).open(file)); try!(f.write_all(format!("{}\n", self.to_string()).as_bytes())); @@ -68,7 +92,7 @@ impl Alias { fn write_alias>(from: String, file: P) -> Result<(), AliasSearchError> { let mut alias = Alias::new(&from); - let similar_aliases = try!(find_alias_in_file(&alias, &file)); + let similar_aliases = try!(alias.find_in_file(&file)); alias.update_alias_id(similar_aliases); try!(alias.write_to_file(&file)); Ok(()) @@ -134,30 +158,6 @@ impl PartialEq for AliasSearchError { } } -fn find_alias_in_file>(alias: &Alias, file: P) -> Result, 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(&alias.email) { - return Err(AliasSearchError::EmailExists) - } - - if split[1].starts_with(&alias.alias) { - matches.push(split[1].to_owned()); - } - } - - if matches.is_empty() { - Err(AliasSearchError::NotFound) - } else { - Ok(matches) - } -} - fn print_usage(program: &str) { println!("Usage: {} FILE", program); } -- cgit v1.2.3 From 2d1f7031f03194fbceffc15b1d6376abea243e22 Mon Sep 17 00:00:00 2001 From: Teddy Wing Date: Sun, 24 Apr 2016 05:17:19 -0400 Subject: Move `write_alias` function to `Alias#write_to_file` Expand the responsibility of `Alias#write_to_file` so that it performs what it used to do plus all of what `write_alias` did. This allows us to consolidate the functionality into a single method, and move it into the `Alias` implementation. The change required some modification to our `write_to_file` test: * Create our test alias as mutable * Write a new alias to the test file based on our test alias but with a different email. This allows the `write_to_file` method to work without erroring with an `AliasSearchError::NotFound`. * Needed to `derive(Clone)` on `Alias` in order to be able to easily clone it into the new near-duplicate alias. * Change our `unwrap()` calls to `expect()` to make it easier to see where exactly we panicked. Otherwise I didn't really have any way of knowing. * Add some comments for clarity --- src/main.rs | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) (limited to 'src/main.rs') diff --git a/src/main.rs b/src/main.rs index 0004cc4..91545bf 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,6 +8,7 @@ use std::path::Path; #[cfg(test)] mod tests; +#[derive(Clone)] struct Alias { alias: String, name: String, @@ -77,9 +78,13 @@ impl Alias { } } - fn write_to_file>(&self, file: P) -> Result<(), io::Error> { + fn write_to_file>(&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(()) } @@ -90,14 +95,6 @@ impl Alias { } } -fn write_alias>(from: String, file: P) -> Result<(), AliasSearchError> { - let mut alias = Alias::new(&from); - let similar_aliases = try!(alias.find_in_file(&file)); - alias.update_alias_id(similar_aliases); - try!(alias.write_to_file(&file)); - Ok(()) -} - #[derive(Debug)] enum AliasSearchError { NotFound, @@ -182,7 +179,8 @@ fn main() { println!("{}", line); if line.starts_with("From: ") { - match write_alias(line, &file) { + let mut alias = Alias::new(&line); + match alias.write_to_file(&file) { Ok(_) => continue, Err(e @ AliasSearchError::NotFound) | Err(e @ AliasSearchError::EmailExists) => io::stderr().write(e.to_string().as_bytes()).ok(), -- cgit v1.2.3 From afc01ecb67dd978879d423866d33ac0c526151f4 Mon Sep 17 00:00:00 2001 From: Teddy Wing Date: Sun, 24 Apr 2016 05:40:45 -0400 Subject: 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 --- src/main.rs | 155 ++---------------------------------------------------------- 1 file changed, 4 insertions(+), 151 deletions(-) (limited to 'src/main.rs') diff --git a/src/main.rs b/src/main.rs index 91545bf..0732f6d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,159 +1,12 @@ use std::env; -use std::error::{self, Error}; -use std::io::{self, BufRead, BufReader, Write}; -use std::fmt; -use std::fs::{File, OpenOptions}; -use std::path::Path; +use std::io::{self, BufRead, Write}; + +mod alias; #[cfg(test)] mod tests; -#[derive(Clone)] -struct Alias { - alias: String, - name: String, - email: String, -} - -impl Alias { - 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 } - } - - 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) - } - } - - fn find_in_file>(&self, file: P) -> Result, 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) - } - } - - fn write_to_file>(&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(()) - } - - fn update_alias_id(&mut self, similar_aliases: Vec) { - if !similar_aliases.is_empty() { - self.alias = format!("{}-{}", self.alias, similar_aliases.len() + 1); - } - } -} - -#[derive(Debug)] -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 for AliasSearchError { - fn from(err: io::Error) -> AliasSearchError { - AliasSearchError::Io(err) - } -} - -#[cfg(test)] -impl PartialEq 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, - }, - } - } -} +use alias::*; fn print_usage(program: &str) { println!("Usage: {} FILE", program); -- cgit v1.2.3