Skip to content

Commit

Permalink
Merge pull request #3 from generic-user1/dev
Browse files Browse the repository at this point in the history
Version 1.0.1
  • Loading branch information
generic-user1 committed Oct 22, 2022
2 parents 2c88fc3 + a0673f1 commit 4d621c1
Show file tree
Hide file tree
Showing 12 changed files with 294 additions and 307 deletions.
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions anabot/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ readme = "README.md"
repository = "https://github.com/generic-user1/anagrambot"
keywords = ["anagram", "anagrams", "anagrambot"]
categories = ["command-line-utilities", "text-processing"]
version = "1.0.0"
version = "1.0.1"
edition = "2021"

[dependencies]

anagrambot = {path = "../anagrambot", version = "1.0.0"}
anagrambot = {path = "../anagrambot", version = "1.0.1"}

clap = {version = "3.2.12", features = ["derive"]}
29 changes: 12 additions & 17 deletions anabot/src/arg.rs
Original file line number Diff line number Diff line change
@@ -1,29 +1,26 @@
use clap::{Parser, clap_derive::ArgEnum, Subcommand};
use clap::{clap_derive::ArgEnum, Parser, Subcommand};

#[derive(Debug, Copy, Clone, PartialEq, ArgEnum)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, ArgEnum)]
pub enum AnagramType {
Standard,
Proper,
Loose
}

#[derive(Debug, PartialEq, Subcommand)]
#[derive(Debug, PartialEq, Eq, Subcommand)]
pub enum ActionType {
/// Test if two words are anagrams
Test {
word_a: String,
word_b: String
},
Test { word_a: String, word_b: String },
/// Find and print anagrams for a word, up to a given limit
Find {
word: String,
word: String,
/// The maximum number of anagrams to find
///
///
/// The actual number of anagrams found may be under this limit, but never above.
#[clap(short, long, default_value_t = 100)]
limit: usize,
/// The minimum length of each sub-word (only used with loose anagrams)
///
///
/// For example, with this set to 3, no 1 or 2 letter words will appear in the results.
#[clap(short, long, default_value_t = 1)]
min_word_length: usize
Expand All @@ -33,18 +30,17 @@ pub enum ActionType {
#[derive(Parser, Debug)]
#[clap(author, version, about, long_about = None)]
pub struct CliArgs {

#[clap(short = 'i', long)]
/// Ignore case when testing or finding anagrams
pub case_insensitive: bool,

/// Type of anagrams to search for
///
///
/// `standard`: every letter in word A appears in word B the same number of times.
///
/// `proper`: word A and word B both appear in the word list and are
///
/// `proper`: word A and word B both appear in the word list and are
/// standard anagrams of each other (requires a word list)
///
///
/// `loose`: word A and word B are proper anagrams but may have a different number of
/// spaces. For example, "racecar" and "arc care" are loose anagrams but not proper anagrams
/// (requires a word list)
Expand All @@ -64,5 +60,4 @@ pub struct CliArgs {

#[clap(subcommand)]
pub action: ActionType

}
}
164 changes: 97 additions & 67 deletions anabot/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
use anagrambot::{wordlist::{OwnedWordList, Wordlist}, anagram, default_wordlist};
use anagrambot::{
anagram, default_wordlist,
wordlist::{OwnedWordList, Wordlist}
};
use clap::Parser;

use std::path::Path;

mod arg;
use arg::{CliArgs, AnagramType, ActionType};
use arg::{ActionType, AnagramType, CliArgs};

const REASON_DUPLICATES: &str = "a word cannot be an anagram of itself";
const REASON_FIRST_NOT_WORD: &str = "first provided word is not a valid word";
Expand All @@ -17,46 +20,47 @@ fn main() -> Result<(), String> {
}

/// main arg handling function
///
///
/// includes full handling for standard anagrams and delegates other types of anagrams to do_action
fn handle_args(args: CliArgs) -> Result<(), String>
{
fn handle_args(args: CliArgs) -> Result<(), String> {
// handle Standard first, as it requires no wordlist and thus no wordlist handling
if &args.anagram_type == &AnagramType::Standard {
if args.anagram_type == AnagramType::Standard {
match &args.action {
ActionType::Find{word, limit, min_word_length:_} => {
ActionType::Find {
word,
limit,
min_word_length: _
} => {
let limit = *limit;
let mut iter = anagram::find_anagrams(word);
let iter = anagram::find_anagrams(word);
let mut index: usize = 0;
while let Some(word) = iter.next(){
for word in iter {
if index >= limit {
break;
}
println!("{}", word);

index += 1;
}
if !args.simple_output{
if !args.simple_output {
println!("found {} standard anagrams", index);
}
},
ActionType::Test {word_a, word_b } => {
if anagram::are_anagrams(word_a, word_b, !args.case_insensitive){
}
ActionType::Test { word_a, word_b } => {
if anagram::are_anagrams(word_a, word_b, !args.case_insensitive) {
if args.simple_output {
println!("true")
} else {
println!("\"{}\" is standard anagram of \"{}\"", word_a, word_b);
}
} else if args.simple_output {
println!("false");
} else {
if args.simple_output{
println!("false");
println!("\"{}\" is not standard anagram of \"{}\"", word_a, word_b);
if word_a == word_b {
println!("Reason: {}", REASON_DUPLICATES);
} else {
println!("\"{}\" is not standard anagram of \"{}\"", word_a, word_b);
if word_a == word_b {
println!("Reason: {}", REASON_DUPLICATES);
} else {
println!("Reason: {}", REASON_CHARS_DIFFERENT);
}
println!("Reason: {}", REASON_CHARS_DIFFERENT);
}
}
}
Expand All @@ -66,9 +70,7 @@ fn handle_args(args: CliArgs) -> Result<(), String>
// if this fails, return Err(message)
// if this succeeds, call do_action to perform whatever action
if let Some(wordlist_path) = &args.wordlist_path {
let wordlist = match OwnedWordList::from_file(
&Path::new(wordlist_path))
{
let wordlist = match OwnedWordList::from_file(Path::new(wordlist_path)) {
Ok(wordlist) => wordlist,
Err(_) => {
return Err(format!("Failed to read word list file {}", wordlist_path));
Expand All @@ -80,9 +82,9 @@ fn handle_args(args: CliArgs) -> Result<(), String>
let wordlist = match default_wordlist::default_wordlist() {
Some(wordlist) => wordlist,
None => {
let errmsg = String::from("No word list was provided, ") +
"but no default wordlist could be found. Please provide a word list " +
"file (text file, one word per line) using the `-w` option";
let errmsg = String::from("No word list was provided, ")
+ "but no default wordlist could be found. Please provide a word list "
+ "file (text file, one word per line) using the `-w` option";
return Err(errmsg);
}
};
Expand All @@ -94,30 +96,33 @@ fn handle_args(args: CliArgs) -> Result<(), String>
}

/// used to handle actions involving a wordlist in a common manner independant of wordlist type
///
/// called after a wordlist is determined to be needed and has been successfully resolved.
///
///
/// called after a wordlist is determined to be needed and has been successfully resolved.
///
///# Panics
///
///
/// this function panics if args.anagram_type is `Standard`, as this is meant to be handled
/// before this function is called (due to the lack of requirement of a wordlist)
fn do_action<'a>(args: &CliArgs, wordlist: &'a impl Wordlist<'a>)
{
fn do_action<'a>(args: &CliArgs, wordlist: &'a impl Wordlist<'a>) {
const PANIC_MSG: &str = "Logic Error! Used do_action for standard anagram";

let case_sensitive = !args.case_insensitive;
match &args.action {
ActionType::Test {word_a, word_b } => {
ActionType::Test { word_a, word_b } => {
let (are_anagrams, anagram_name) = match &args.anagram_type {
AnagramType::Standard => panic!("{}", PANIC_MSG),
AnagramType::Proper => {
let are_anagrams =
anagram::are_proper_anagrams(&word_a, &word_b, wordlist, case_sensitive);
let are_anagrams =
anagram::are_proper_anagrams(word_a, word_b, wordlist, case_sensitive);
(are_anagrams, "proper")
},
}
AnagramType::Loose => {
let are_anagrams =
anagram::are_loose_anagrams_strict(&word_a, &word_b, wordlist, case_sensitive);
let are_anagrams = anagram::are_loose_anagrams_strict(
word_a,
word_b,
wordlist,
case_sensitive
);
(are_anagrams, "loose")
}
};
Expand All @@ -128,42 +133,54 @@ fn do_action<'a>(args: &CliArgs, wordlist: &'a impl Wordlist<'a>)
} else {
println!("false");
}
} else if are_anagrams {
println!(
"\"{}\" is {} anagram of \"{}\"",
word_a, anagram_name, word_b
);
} else {
if are_anagrams{
println!("\"{}\" is {} anagram of \"{}\"",word_a, anagram_name, word_b);
println!(
"\"{}\" is not {} anagram of \"{}\"",
word_a, anagram_name, word_b
);
if word_a == word_b {
println!("Reason: {}", REASON_DUPLICATES);
} else {
println!("\"{}\" is not {} anagram of \"{}\"",word_a, anagram_name, word_b);
if word_a == word_b {
println!("Reason: {}", REASON_DUPLICATES);
} else {
let word_a_real = wordlist.includes_word(&word_a);
let word_b_real = wordlist.includes_word(&word_b);
if !word_a_real {
println!("Reason: {}", REASON_FIRST_NOT_WORD);
}
if !word_b_real {
println!("Reason: {}", REASON_SECOND_NOT_WORD);
}
if word_a_real && word_b_real {
println!("Reason: {}", REASON_CHARS_DIFFERENT);
}
}
let word_a_real = wordlist.includes_word(word_a);
let word_b_real = wordlist.includes_word(word_b);
if !word_a_real {
println!("Reason: {}", REASON_FIRST_NOT_WORD);
}
if !word_b_real {
println!("Reason: {}", REASON_SECOND_NOT_WORD);
}
if word_a_real && word_b_real {
println!("Reason: {}", REASON_CHARS_DIFFERENT);
}
}
}
},
ActionType::Find { word, limit, min_word_length} => {
fn print_fn(args: &CliArgs, mut iter: impl Iterator<Item = impl std::fmt::Display>, limit: usize) {
}
ActionType::Find {
word,
limit,
min_word_length
} => {
fn print_fn(
args: &CliArgs,
iter: impl Iterator<Item = impl std::fmt::Display>,
limit: usize
) {
let mut index: usize = 0;
while let Some(word) = iter.next(){
for word in iter {
if index >= limit {
break;
}
println!("{}", word);

index += 1;
}
if !args.simple_output{
let anagram_type = match args.anagram_type{
if !args.simple_output {
let anagram_type = match args.anagram_type {
AnagramType::Standard => panic!("{}", PANIC_MSG),
AnagramType::Proper => "proper",
AnagramType::Loose => "loose"
Expand All @@ -174,10 +191,23 @@ fn do_action<'a>(args: &CliArgs, wordlist: &'a impl Wordlist<'a>)
match &args.anagram_type {
AnagramType::Standard => panic!("{}", PANIC_MSG),
AnagramType::Proper => {
print_fn(&args, anagram::find_proper_anagrams(&word, wordlist, case_sensitive), *limit);
},
print_fn(
args,
anagram::find_proper_anagrams(word, wordlist, case_sensitive),
*limit
);
}
AnagramType::Loose => {
print_fn(&args, anagram::find_loose_anagrams(&word, wordlist, *min_word_length, case_sensitive), *limit);
print_fn(
args,
anagram::find_loose_anagrams(
word,
wordlist,
*min_word_length,
case_sensitive
),
*limit
);
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion anagrambot/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ readme = "README.md"
repository = "https://github.com/generic-user1/anagrambot"
keywords = ["anagram", "anagrams"]
categories = ["text-processing"]
version = "1.0.0"
version = "1.0.1"
edition = "2021"

[features]
Expand Down
Loading

0 comments on commit 4d621c1

Please sign in to comment.