From 77ff7c480accd61afb2c08e5223a74dab3c06e95 Mon Sep 17 00:00:00 2001 From: Brady Fomegne Date: Fri, 15 Sep 2023 11:44:51 +0100 Subject: [PATCH] fix(clafrica): improve predications (#83) Now, an element in a dictionary can have many values. A translator can return a list of predicates. --- .gitignore | 2 + clafrica/data/config_sample.toml | 2 +- clafrica/data/dictionary.toml | 1 + clafrica/data/invalid_data.toml | 4 ++ .../data/{invalid.toml => invalid_file.toml} | 0 clafrica/data/invalid_translator.toml | 4 ++ clafrica/data/scripts/datetime/date.rhai | 2 +- clafrica/src/config.rs | 40 +++++++++++++++---- clafrica/src/lib.rs | 14 ++++--- clafrica/src/translator.rs | 16 +++++--- 10 files changed, 64 insertions(+), 21 deletions(-) create mode 100644 clafrica/data/invalid_data.toml rename clafrica/data/{invalid.toml => invalid_file.toml} (100%) create mode 100644 clafrica/data/invalid_translator.toml diff --git a/.gitignore b/.gitignore index af09933..7f9e861 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,5 @@ *.swp *.un *.swo +*.swn +*.swm diff --git a/clafrica/data/config_sample.toml b/clafrica/data/config_sample.toml index 26cfe2e..688de45 100644 --- a/clafrica/data/config_sample.toml +++ b/clafrica/data/config_sample.toml @@ -1,7 +1,7 @@ # Main clafrica config file [core] -buffer_size = 12 +buffer_size = 64 auto_capitalize = false auto_commit = false page_size = 10 diff --git a/clafrica/data/dictionary.toml b/clafrica/data/dictionary.toml index 2197711..a2398fa 100644 --- a/clafrica/data/dictionary.toml +++ b/clafrica/data/dictionary.toml @@ -1,3 +1,4 @@ [translation] halo = "hello" +hola = { values = ["hello", "hi"], alias = [] } hi = { value = "hello", alias = ["hey"] } diff --git a/clafrica/data/invalid_data.toml b/clafrica/data/invalid_data.toml new file mode 100644 index 0000000..f1df08d --- /dev/null +++ b/clafrica/data/invalid_data.toml @@ -0,0 +1,4 @@ +# invalid +[data] +a = ["b", "c"] + diff --git a/clafrica/data/invalid.toml b/clafrica/data/invalid_file.toml similarity index 100% rename from clafrica/data/invalid.toml rename to clafrica/data/invalid_file.toml diff --git a/clafrica/data/invalid_translator.toml b/clafrica/data/invalid_translator.toml new file mode 100644 index 0000000..df092f8 --- /dev/null +++ b/clafrica/data/invalid_translator.toml @@ -0,0 +1,4 @@ +# invalid +[translators] +a = ["b", "c"] + diff --git a/clafrica/data/scripts/datetime/date.rhai b/clafrica/data/scripts/datetime/date.rhai index 6a58675..37f3abf 100644 --- a/clafrica/data/scripts/datetime/date.rhai +++ b/clafrica/data/scripts/datetime/date.rhai @@ -24,7 +24,7 @@ fn translate(input) { let date = parse_date(data); if !date.is_empty() { - return [input, "", `${date[0]} ${global::MONTHS[date[1]]} ${date[2]}`, true]; + return [input, "", [`${date[0]} ${global::MONTHS[date[1]]} ${date[2]}`, `${global::MONTHS[date[1]]} ${date[0]} ${date[2]}`], true]; } return [input, "", "", false]; diff --git a/clafrica/src/config.rs b/clafrica/src/config.rs index dadd480..b800a1e 100644 --- a/clafrica/src/config.rs +++ b/clafrica/src/config.rs @@ -1,5 +1,6 @@ use rhai::{Engine, AST}; use serde::Deserialize; +use std::result::Result; use std::{collections::HashMap, error, fs, path::Path}; use toml::{self}; @@ -23,8 +24,10 @@ pub struct CoreConfig { #[serde(untagged)] enum Data { Simple(String), + Multi(Vec), File(DataFile), Detailed(DetailedData), + MoreDetailed(MoreDetailedData), } #[derive(Deserialize, Debug, Clone)] @@ -38,6 +41,12 @@ struct DetailedData { alias: Vec, } +#[derive(Deserialize, Debug, Clone)] +struct MoreDetailedData { + values: Vec, + alias: Vec, +} + macro_rules! insert_with_auto_capitalize { ( $data: expr, $auto_capitalize: expr, $key: expr, $value: expr ) => { $data.insert($key.to_owned(), Data::Simple($value.to_owned())); @@ -83,6 +92,7 @@ impl Config { insert_with_auto_capitalize!(data, auto_capitalize, key, value); }); } + _ => Err(format!("Invalid script file `{filepath:?}`.\nCaused by:\n\t{value:?} not allowed in the data table."))?, }; Ok(()) }, @@ -104,7 +114,7 @@ impl Config { let filepath = config_path.join(v.clone()).to_str().unwrap().to_string(); translators.insert(key.to_owned(), Data::Simple(filepath)); } - _ => (), + _ => Err(format!("Invalid script file `{filepath:?}`.\nCaused by:\n\t{value:?} not allowed in the translator table."))?, }; Ok(()) }, @@ -122,7 +132,7 @@ impl Config { let conf = Config::from_file(&filepath)?; translation.extend(conf.translation.unwrap_or_default()); } - Data::Simple(_) => { + Data::Simple(_) | Data::Multi(_) => { translation.insert(key.to_owned(), value.clone()); } Data::Detailed(DetailedData { value, alias }) => { @@ -130,6 +140,11 @@ impl Config { translation.insert(e.to_owned(), Data::Simple(value.to_owned())); }); } + Data::MoreDetailed(MoreDetailedData { values, alias }) => { + alias.iter().chain([key.to_owned()].iter()).for_each(|e| { + translation.insert(e.to_owned(), Data::Multi(values.clone())); + }); + } }; Ok(()) }, @@ -189,7 +204,7 @@ impl Config { .collect() } - pub fn extract_translation(&self) -> HashMap { + pub fn extract_translation(&self) -> HashMap> { let empty = HashMap::new(); self.translation @@ -198,11 +213,12 @@ impl Config { .iter() .filter_map(|(k, v)| { let v = match v { - Data::Simple(v) => Some(v), + Data::Simple(v) => Some(vec![v.to_owned()]), + Data::Multi(v) => Some(v.to_owned()), _ => None, }; - v.map(|v| (k.to_owned(), v.to_owned())) + v.map(|v| (k.to_owned(), v)) }) .collect() } @@ -219,7 +235,7 @@ mod tests { assert_eq!( conf.core.as_ref().map(|core| { - assert_eq!(core.buffer_size.unwrap(), 12); + assert_eq!(core.buffer_size.unwrap(), 64); assert!(!core.auto_capitalize.unwrap()); assert!(!core.auto_commit.unwrap()); assert_eq!(core.page_size.unwrap(), 10); @@ -232,7 +248,7 @@ mod tests { assert_eq!(data.keys().len(), 23); // parsing error - let conf = Config::from_file(Path::new("./data/invalid.toml")); + let conf = Config::from_file(Path::new("./data/invalid_file.toml")); assert!(conf.is_err()); // config file not found @@ -243,6 +259,14 @@ mod tests { let conf = Config::from_file(Path::new("./data/blank_sample.toml")).unwrap(); let data = conf.extract_data(); assert_eq!(data.keys().len(), 0); + + // invalid data + let conf = Config::from_file(Path::new("./data/invalid_data.toml")); + assert!(conf.is_err()); + + // invalid translator + let conf = Config::from_file(Path::new("./data/invalid_translator.toml")); + assert!(conf.is_err()); } #[test] @@ -275,7 +299,7 @@ mod tests { let conf = Config::from_file(Path::new("./data/config_sample.toml")).unwrap(); let translation = conf.extract_translation(); - assert_eq!(translation.keys().len(), 3); + assert_eq!(translation.keys().len(), 4); let conf = Config::from_file(Path::new("./data/blank_sample.toml")).unwrap(); let translation = conf.extract_translation(); diff --git a/clafrica/src/lib.rs b/clafrica/src/lib.rs index 545e432..800e30b 100644 --- a/clafrica/src/lib.rs +++ b/clafrica/src/lib.rs @@ -118,12 +118,14 @@ pub fn run( if !committed { translator.translate(&input).iter().for_each( - |(code, remaining_code, text, translated)| { - if auto_commit && *translated { - processor.commit(code, remaining_code, text); - } else if !text.is_empty() { - frontend.add_predicate(code, remaining_code, text); - } + |(code, remaining_code, texts, translated)| { + texts.iter().for_each(|text| { + if auto_commit && *translated { + processor.commit(code, remaining_code, text); + } else if !text.is_empty() { + frontend.add_predicate(code, remaining_code, text); + } + }); }, ); }; diff --git a/clafrica/src/translator.rs b/clafrica/src/translator.rs index 429cceb..6d55c8a 100644 --- a/clafrica/src/translator.rs +++ b/clafrica/src/translator.rs @@ -2,14 +2,14 @@ use rhai::{Array, Engine, Scope, AST}; use std::collections::HashMap; pub struct Translator { - dictionary: HashMap, + dictionary: HashMap>, translators: HashMap, auto_commit: bool, } impl Translator { pub fn new( - dictionary: HashMap, + dictionary: HashMap>, translators: HashMap, auto_commit: bool, ) -> Self { @@ -20,7 +20,7 @@ impl Translator { } } - pub fn translate(&self, input: &str) -> Vec<(String, String, String, bool)> { + pub fn translate(&self, input: &str) -> Vec<(String, String, Vec, bool)> { let mut scope = Scope::new(); let engine = Engine::new(); @@ -48,10 +48,16 @@ impl Translator { (data.len() == 4).then(|| { let code = data[0].clone().into_string().unwrap(); let remaining_code = data[1].clone().into_string().unwrap(); - let text = data[2].clone().into_string().unwrap(); + let texts = data[2] + .clone() + .into_array() + .unwrap_or(vec![data[2].clone()]) + .iter() + .map(|e| e.clone().into_string().unwrap()) + .collect(); let translated = data[3].clone().as_bool().unwrap(); - (code, remaining_code, text, translated) + (code, remaining_code, texts, translated) }) })) .collect()