Skip to content

Commit

Permalink
Use rustfmt to format the code.
Browse files Browse the repository at this point in the history
  • Loading branch information
boholder committed Nov 3, 2021
1 parent b90b1c9 commit 56498f6
Show file tree
Hide file tree
Showing 12 changed files with 408 additions and 229 deletions.
246 changes: 160 additions & 86 deletions crates/clt_lib/src/conversion.rs

Large diffs are not rendered by default.

105 changes: 63 additions & 42 deletions crates/clt_lib/src/extraction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,27 @@ use regex::{self, Regex};

/// Convert Vec<String> into a slice of &str in Rust:
/// https://stackoverflow.com/a/41180422/11397457
pub fn read_from_files<T: AsRef<str>>(files: &[T], eof: Option<&str>)
-> Result<Vec<String>, String> {
pub fn read_from_files<T: AsRef<str>>(
files: &[T],
eof: Option<&str>,
) -> Result<Vec<String>, String> {
let mut text = Vec::new();
for file in files {
text.push(read_file(file.as_ref(), eof)?);
};
}
Ok(text)
}

fn read_file(file: &str, eof: Option<&str>) -> Result<String, String> {
match fs::read_to_string(file) {
Ok(text) => { Ok(apply_eof_on_text(eof, text)) }
Err(msg) => { Err(format!("naming: {}: {}", file, msg)) }
Ok(text) => Ok(apply_eof_on_text(eof, text)),
Err(msg) => Err(format!("naming: {}: {}", file, msg)),
}
}

fn apply_eof_on_text(eof: Option<&str>, text: String) -> String {
match eof {
None => { text }
None => text,
Some(eof) => {
let position = text.find(eof);
text[..position.unwrap_or_else(|| text.len())].to_string()
Expand All @@ -38,11 +40,13 @@ pub fn read_from_std_in(eof: Option<&str>) -> Result<String, String> {

/// How to test stdin https://stackoverflow.com/a/28370712/11397457
fn read_from_input<R>(mut input: R, eof: Option<&str>) -> Result<String, String>
where R: BufRead {
where
R: BufRead,
{
let mut buffer = String::new();
match input.read_to_string(&mut buffer) {
Ok(_) => { Ok(apply_eof_on_text(eof, buffer)) }
Err(msg) => { Err(format!("naming: stdin: {}", msg)) }
Ok(_) => Ok(apply_eof_on_text(eof, buffer)),
Err(msg) => Err(format!("naming: stdin: {}", msg)),
}
}

Expand All @@ -56,25 +60,31 @@ impl Captor {
/// Options should be manually escaped by user.
/// If there is a locator pair which couldn't be converted to regex, return an Err.
pub fn new(locators: Option<Vec<String>>) -> Result<Captor, String> {
let locators = locators.unwrap_or(
vec![r"\s \s".to_string()]);
let locators = locators.unwrap_or_else(|| vec![r"\s \s".to_string()]);

let mut patterns = Vec::new();

for locator in locators {
let pair = locator.split_once(" ");
if let None = pair {
if pair.is_none() {
return Err(format!(
"naming: locator `{}`: can't build locator pair from this.", locator));
"naming: locator `{}`: can't build locator pair from this.",
locator
));
}
let pair = pair.unwrap();

patterns.push(Regex::new(
// \A for start of file position,
// \z for end of file position
&format!(r"(?:{}|\A)([a-zA-Z0-9_-]+)(?:{}|\z)",
pair.0, pair.1)
).unwrap());
patterns.push(
Regex::new(
// \A for start of file position,
// \z for end of file position
&format!(
r"(?:{}|\A)([a-zA-Z0-9_-]+)(?:{}|\z)",
pair.0, pair.1
),
)
.unwrap(),
);
}

Ok(Captor { patterns })
Expand All @@ -84,17 +94,23 @@ impl Captor {
/// with regular expression and given locating prefix & suffix.
pub fn capture_words(&self, text: Vec<String>) -> Vec<String> {
// apply matching on each file's content
let mut matches: Vec<String> = text.iter()
let mut matches: Vec<String> = text
.iter()
.map(|text| {
// for each file's content, apply all patterns on it.
self.patterns.iter()
self.patterns
.iter()
.map(move |pattern| {
pattern.captures_iter(text)
pattern
.captures_iter(text)
.into_iter()
.map(|cap| cap[1].to_string())
}).flatten()
})
.flatten()
// now get one file's matches
}).flatten().collect();
})
.flatten()
.collect();

// dedup while keep the order, what an elegant solution:
// https://users.rust-lang.org/t/deduplicate-vector-in-place-while-preserving-order/56568/6
Expand Down Expand Up @@ -145,38 +161,43 @@ mod captor_tests {

#[test]
fn default_captor_works() {
let text = to_string_vec(
vec!["int i = 1; String s = oneMethod(arg1, arg2);"]);
let actual = Captor::new(
Some(to_string_vec(vec![r"\s \s*=", r"\s \s*;"]))
).unwrap().capture_words(text);
let expect: Vec<String> =
to_string_vec(vec!["i", "s", "1"]);
let text =
to_string_vec(vec!["int i = 1; String s = oneMethod(arg1, arg2);"]);
let actual =
Captor::new(Some(to_string_vec(vec![r"\s \s*=", r"\s \s*;"])))
.unwrap()
.capture_words(text);
let expect: Vec<String> = to_string_vec(vec!["i", "s", "1"]);
assert_eq!(actual, expect);
}

#[test]
fn custom_captor_works() {
let text = to_string_vec(vec!["@now#can$be&matched"]);
// note that "$" is manually escaped.
let locators: Vec<String> = to_string_vec(vec![r"# \$", "@ #", r"\$ &", r"& \z"]);
let locators: Vec<String> =
to_string_vec(vec![r"# \$", "@ #", r"\$ &", r"& \z"]);

let actual =
Captor::new(Some(locators)).unwrap().capture_words(text);
let actual = Captor::new(Some(locators)).unwrap().capture_words(text);
// notice that the result order is based on option order.
let expect: Vec<String> = to_string_vec(vec!["can", "now", "be", "matched"]);
let expect: Vec<String> =
to_string_vec(vec!["can", "now", "be", "matched"]);
assert_eq!(actual, expect);
}

#[test]
fn duplicating_matches_are_removed() {
let text = to_string_vec(vec!["let a = 1; let b = 2; let c = 3;",
"let a = 1; let b = 2; let c = 3;"]);
let actual = Captor::new(
Some(to_string_vec(vec![r"\s \s*=", r"\s \s*;"]))
).unwrap().capture_words(text);
let text = to_string_vec(vec![
"let a = 1; let b = 2; let c = 3;",
"let a = 1; let b = 2; let c = 3;",
]);
let actual =
Captor::new(Some(to_string_vec(vec![r"\s \s*=", r"\s \s*;"])))
.unwrap()
.capture_words(text);
// notice that the result order is based on option order.
let expect: Vec<String> = to_string_vec(vec!["a", "b", "c", "1", "2", "3"]);
let expect: Vec<String> =
to_string_vec(vec!["a", "b", "c", "1", "2", "3"]);
assert_eq!(actual, expect);
}
}
}
52 changes: 33 additions & 19 deletions crates/clt_lib/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,42 +7,56 @@ pub use conversion::*;
pub use extraction::*;
use naming_lib::NamingCase;

mod extraction;
mod conversion;
mod extraction;

/// Intermediate type for converting
/// NamingCase type to String in different output format.
struct Formatter {
pub inner: fn(&NamingCase) -> String,
}

impl Clone for Formatter {
fn clone(&self) -> Self {
Formatter { inner: self.inner }
}
}

impl Copy for Formatter {}

lazy_static! {
// default option of `--filter` and `--output`, i.e. allow all formats.
static ref DEFAULT_OPTIONS: Vec<String> = to_string_vec(vec!["S", "s", "k", "c", "p"]);

// used for converting NamingCase to String type in iteration.
static ref DIRECT_MAPPERS: HashMap<&'static str, fn(&NamingCase) -> String> = {
let mut map: HashMap<&'static str, fn(&NamingCase) -> String> = HashMap::new();
map.insert("S", |case| case.to_screaming_snake().unwrap());
map.insert("s", |case| case.to_snake().unwrap());
map.insert("k", |case| case.to_kebab().unwrap());
map.insert("c", |case| case.to_camel().unwrap());
map.insert("p", |case| case.to_pascal().unwrap());
static ref DIRECT_MAPPERS: HashMap<&'static str, Formatter> = {
let mut map: HashMap<&'static str, Formatter> = HashMap::new();
map.insert("S", Formatter{inner:|case| case.to_screaming_snake().unwrap()});
map.insert("s", Formatter{inner:|case| case.to_snake().unwrap()});
map.insert("k", Formatter{inner:|case| case.to_kebab().unwrap()});
map.insert("c", Formatter{inner:|case| case.to_camel().unwrap()});
map.insert("p", Formatter{inner:|case| case.to_pascal().unwrap()});
map
};

// same as above.
static ref JSON_MAPPERS:HashMap<&'static str, fn(&NamingCase) -> String> = {
static ref JSON_MAPPERS:HashMap<&'static str, Formatter> = {
fn compose(key:&str,value:String) -> String {
"\"".to_string() + key + "\":\"" + &value + "\""
}

let mut map: HashMap<&'static str, fn(&NamingCase) -> String> = HashMap::new();
map.insert("S", |case| compose("screaming_snake",case.to_screaming_snake().unwrap()));
map.insert("s", |case| compose("snake",case.to_snake().unwrap()));
map.insert("k", |case| compose("kebab",case.to_kebab().unwrap()));
map.insert("c", |case| compose("camel",case.to_camel().unwrap()));
map.insert("p", |case| compose("pascal",case.to_pascal().unwrap()));
let mut map: HashMap<&'static str, Formatter> = HashMap::new();
map.insert("S", Formatter{
inner:|case| compose("screaming_snake",case.to_screaming_snake().unwrap())
});
map.insert("s", Formatter{inner:|case| compose("snake",case.to_snake().unwrap())});
map.insert("k", Formatter{inner:|case| compose("kebab",case.to_kebab().unwrap())});
map.insert("c", Formatter{inner:|case| compose("camel",case.to_camel().unwrap())});
map.insert("p", Formatter{inner:|case| compose("pascal",case.to_pascal().unwrap())});
map
};
}

pub fn to_string_vec(ori: Vec<&str>) -> Vec<String> {
ori.iter()
.map(|str| str.to_string())
.collect()
}
ori.iter().map(|str| str.to_string()).collect()
}
21 changes: 13 additions & 8 deletions crates/clt_lib/tests/file_reading_function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,24 @@ fn read_from_single_file_without_logical_eof() {
fn read_from_multiple_files_without_logical_eof() {
let files = ["tests/data/a.txt", "tests/data/b.txt"];
let text = lib::read_from_files(&files, None);
assert_eq!(text.unwrap(),
lib::to_string_vec(vec!["front-a stop after-a", "front-b hold after-b"]));
assert_eq!(
text.unwrap(),
lib::to_string_vec(vec![
"front-a stop after-a",
"front-b hold after-b"
])
);
}

#[test]
fn read_from_file_with_logical_eof_exists_in_file() {
let text =
lib::read_from_files(&["tests/data/a.txt"], Some("stop"));
let text = lib::read_from_files(&["tests/data/a.txt"], Some("stop"));
assert_eq!(text.unwrap(), lib::to_string_vec(vec!["front-a "]));
}

#[test]
fn read_whole_file_content_when_logical_eof_not_exists_but_is_passed_to_func() {
let text =
lib::read_from_files(&["tests/data/b.txt"], Some("stop"));
let text = lib::read_from_files(&["tests/data/b.txt"], Some("stop"));
assert_eq!(text.unwrap(), lib::to_string_vec(vec!["front-b hold after-b"]));
}

Expand All @@ -35,6 +38,8 @@ fn apply_logical_eof_on_each_file_when_read_multiple_files() {
let files = ["tests/data/a.txt", "tests/data/b.txt"];
let text = lib::read_from_files(&files, Some("stop"));
// a.txt has this eof, but b.txt doesn't have.
assert_eq!(text.unwrap(), lib::to_string_vec(vec!["front-a ", "front-b hold after-b"]));
assert_eq!(
text.unwrap(),
lib::to_string_vec(vec!["front-a ", "front-b hold after-b"])
);
}

54 changes: 33 additions & 21 deletions crates/clt_lib/tests/identifying_ability_on_languages.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,31 +7,37 @@
// and marked this in the document for users.

use clt_lib::{self as lib, Captor, Filter};
use naming_lib::{NamingCase, which_case};
use naming_lib::{which_case, NamingCase};

#[ignore]
#[test]
fn java() {
let text =
lib::read_from_files(&["tests/data/java.txt"], None).unwrap();
let text = lib::read_from_files(&["tests/data/java.txt"], None).unwrap();

// java variables are in camel case.
let actual = Filter::new(Some(vec!["c".to_string()]))
.unwrap().to_naming_cases_from(
Captor::new(
Some(lib::to_string_vec(vec![r"\s \s*=", r"\s \s*;"]))
).unwrap().capture_words(text)
);
let actual =
Filter::new(Some(vec!["c".to_string()])).unwrap().to_naming_cases_from(
Captor::new(Some(lib::to_string_vec(vec![r"\s \s*=", r"\s \s*;"])))
.unwrap()
.capture_words(text),
);

// =========================Failure:
// line 1: "package data;"
// There is no language-insensitive general rule
// to identifying difference between lines like this
// with common assignment statements like
// line 51: "private String name;"
let expect = to_naming_case_vec(Box::from(
["count", "targetIsLive", "liveNeighborCount", "rowSize",
"colSize", "data", "name", "category"]));
let expect = to_naming_case_vec(Box::from([
"count",
"targetIsLive",
"liveNeighborCount",
"rowSize",
"colSize",
"data",
"name",
"category",
]));

assert_eq!(actual, expect);
}
Expand All @@ -47,21 +53,27 @@ fn javascript() {
lib::read_from_files(&["tests/data/javascript.txt"], None).unwrap();

// variables in example file are in camel case.
let actual = Filter::new(Some(vec!["c".to_string()]))
.unwrap().to_naming_cases_from(
Captor::new(
Some(lib::to_string_vec(vec![r"\s \s*=", r"\s \s*;"]))
).unwrap().capture_words(text)
);
let actual =
Filter::new(Some(vec!["c".to_string()])).unwrap().to_naming_cases_from(
Captor::new(Some(lib::to_string_vec(vec![r"\s \s*=", r"\s \s*;"])))
.unwrap()
.capture_words(text),
);

// =========================Failure:
// line 9: "for (let i = 0; i < timePoints.length - 1; i++) {" -> "i"
// can't fix it.
// line 16: "return a - b;" -> "b"
// should I add logic that discard words that matched in method params?
// no, that's unnecessary complex.
let expect = to_naming_case_vec(Box::from(
["findMinDifference", "sorted", "headTail", "min", "i", "b"]));
let expect = to_naming_case_vec(Box::from([
"findMinDifference",
"sorted",
"headTail",
"min",
"i",
"b",
]));

assert_eq!(actual, expect);
}
}
Loading

0 comments on commit 56498f6

Please sign in to comment.