From 4c172a9d54e5de1e374911c3ad02b92dac01af02 Mon Sep 17 00:00:00 2001 From: Federico Terzi Date: Fri, 13 Dec 2019 22:52:24 +0100 Subject: [PATCH] Add Random Extension to enable non-deterministic matches --- Cargo.lock | 7 ++-- Cargo.toml | 1 + src/extension/mod.rs | 2 + src/extension/random.rs | 93 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 100 insertions(+), 3 deletions(-) create mode 100644 src/extension/random.rs diff --git a/Cargo.lock b/Cargo.lock index 3acfc1b..84de321 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -384,6 +384,7 @@ dependencies = [ "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "log-panics 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "reqwest 0.9.20 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1003,7 +1004,7 @@ dependencies = [ [[package]] name = "rand" -version = "0.7.0" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1410,7 +1411,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1892,7 +1893,7 @@ dependencies = [ "checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" "checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" "checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" -"checksum rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d47eab0e83d9693d40f825f86948aa16eff6750ead4bdffc4ab95b8b3a7f052c" +"checksum rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3ae1b169243eaf61759b8475a998f0a385e42042370f3a7dbaf35246eacc8412" "checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" "checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853" "checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" diff --git a/Cargo.toml b/Cargo.toml index e4c7b17..fccfc68 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,6 +29,7 @@ reqwest = "0.9.20" git2 = {version = "0.10.1", features = ["https"]} tempfile = "3.1.0" dialoguer = "0.4.0" +rand = "0.7.2" [target.'cfg(unix)'.dependencies] libc = "0.2.62" diff --git a/src/extension/mod.rs b/src/extension/mod.rs index 26da4cd..4c0f11e 100644 --- a/src/extension/mod.rs +++ b/src/extension/mod.rs @@ -22,6 +22,7 @@ use serde_yaml::Mapping; mod date; mod shell; mod script; +mod random; pub trait Extension { fn name(&self) -> String; @@ -33,5 +34,6 @@ pub fn get_extensions() -> Vec> { Box::new(date::DateExtension::new()), Box::new(shell::ShellExtension::new()), Box::new(script::ScriptExtension::new()), + Box::new(random::RandomExtension::new()), ] } \ No newline at end of file diff --git a/src/extension/random.rs b/src/extension/random.rs new file mode 100644 index 0000000..e44a2e6 --- /dev/null +++ b/src/extension/random.rs @@ -0,0 +1,93 @@ +/* + * This file is part of espanso. + * + * Copyright (C) 2019 Federico Terzi + * + * espanso is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * espanso is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with espanso. If not, see . + */ + +use serde_yaml::{Mapping, Value}; +use rand::seq::SliceRandom; +use log::{warn, error}; + +pub struct RandomExtension {} + +impl RandomExtension { + pub fn new() -> RandomExtension { + RandomExtension{} + } +} + +impl super::Extension for RandomExtension { + fn name(&self) -> String { + String::from("random") + } + + fn calculate(&self, params: &Mapping) -> Option { + let choices = params.get(&Value::from("choices")); + if choices.is_none() { + warn!("No 'choices' parameter specified for random variable"); + return None + } + let choices = choices.unwrap().as_sequence(); + if let Some(choices) = choices { + let str_choices = choices.iter().map(|arg| { + arg.as_str().unwrap_or_default().to_string() + }).collect::>(); + + // Select a random choice between the possibilities + let choice = str_choices.choose(&mut rand::thread_rng()); + + match choice { + Some(output) => { + return Some(output.clone()) + }, + None => { + error!("Could not select a random choice."); + return None + }, + } + + } + + error!("choices array have an invalid format '{:?}'", choices); + None + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::extension::Extension; + + #[test] + fn test_random_basic() { + let mut params = Mapping::new(); + let choices = vec!( + "first", + "second", + "third", + ); + params.insert(Value::from("choices"), Value::from(choices.clone())); + + let extension = RandomExtension::new(); + let output = extension.calculate(¶ms); + + assert!(output.is_some()); + + let output = output.unwrap(); + + assert!(choices.iter().any(|x| x == &output)); + } +} \ No newline at end of file