From 9488c41dcd776cd7f4381c963f953ccf82d0bfca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20N=2E=20Robalino?= Date: Mon, 2 Sep 2019 00:37:13 -0500 Subject: [PATCH] can embed a new field to the table --- Cargo.toml | 4 ++ README.md | 3 +- src/object/dict.rs | 3 +- src/plugins/embed.rs | 87 +++++++++++++++++++++++++++++++++++++++++++ tests/filters_test.rs | 58 +++++++++++++++++++++++++++++ 5 files changed, 153 insertions(+), 2 deletions(-) create mode 100644 src/plugins/embed.rs diff --git a/Cargo.toml b/Cargo.toml index 8aeeb0fb3c..21a5372bd1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -104,6 +104,10 @@ path = "src/plugins/inc.rs" name = "nu_plugin_sum" path = "src/plugins/sum.rs" +[[bin]] +name = "nu_plugin_embed" +path = "src/plugins/embed.rs" + [[bin]] name = "nu_plugin_add" path = "src/plugins/add.rs" diff --git a/README.md b/README.md index f56fa90297..d2243e1193 100644 --- a/README.md +++ b/README.md @@ -234,6 +234,7 @@ Nu adheres closely to a set of goals that make up its design philosophy. As feat | where condition | Filter table to match the condition | | inc (field) | Increment a value or version. Optional use the field of a table | | add field value | Add a new field to the table | +| embed field | Embeds a new field to the table | | sum | Sum a column of values | | edit field value | Edit an existing field to have a new value | | reverse | Reverses the table. | @@ -250,7 +251,7 @@ Nu adheres closely to a set of goals that make up its design philosophy. As feat | to-toml | Convert table into .toml text | | to-yaml | Convert table into .yaml text | | to-bson | Convert table into .bson text | -| to-csv | Convert table into .csv text | +| to-csv | Convert table into .csv text | | to-bson | Convert table into .bson binary data | | to-tsv | Convert table into .tsv text | | to-sqlite | Convert table to sqlite .db binary data | diff --git a/src/object/dict.rs b/src/object/dict.rs index 2f85fcfa65..7fb0b5bcf9 100644 --- a/src/object/dict.rs +++ b/src/object/dict.rs @@ -100,8 +100,9 @@ impl Dictionary { } } +#[derive(Debug)] pub struct TaggedListBuilder { - tag: Tag, + pub tag: Tag, list: Vec>, } diff --git a/src/plugins/embed.rs b/src/plugins/embed.rs new file mode 100644 index 0000000000..3c7adb01bf --- /dev/null +++ b/src/plugins/embed.rs @@ -0,0 +1,87 @@ +use nu::{ + serve_plugin, CallInfo, Plugin, Primitive, ReturnSuccess, ReturnValue, ShellError, Signature, + SyntaxType, Tag, Tagged, TaggedDictBuilder, Value, +}; + +struct Embed { + field: Option, + values: Vec>, +} +impl Embed { + fn new() -> Embed { + Embed { + field: None, + values: Vec::new(), + } + } + + fn embed(&mut self, value: Tagged) -> Result<(), ShellError> { + match value { + Tagged { item, tag } => match &self.field { + Some(_) => { + self.values.push(Tagged { + item: item, + tag: tag, + }); + Ok(()) + } + None => Err(ShellError::string( + "embed needs a field when embedding a value", + )), + }, + } + } +} + +impl Plugin for Embed { + fn config(&mut self) -> Result { + Ok(Signature::build("embed") + .desc("Embeds a new field to the table.") + .required("Field", SyntaxType::String) + .rest(SyntaxType::String) + .filter()) + } + + fn begin_filter(&mut self, call_info: CallInfo) -> Result, ShellError> { + if let Some(args) = call_info.args.positional { + match &args[0] { + Tagged { + item: Value::Primitive(Primitive::String(s)), + .. + } => { + self.field = Some(s.clone()); + self.values = Vec::new(); + } + _ => { + return Err(ShellError::string(format!( + "Unrecognized type in params: {:?}", + args[0] + ))) + } + } + } + + Ok(vec![]) + } + + fn filter(&mut self, input: Tagged) -> Result, ShellError> { + self.embed(input)?; + Ok(vec![]) + } + + fn end_filter(&mut self) -> Result, ShellError> { + let mut root = TaggedDictBuilder::new(Tag::unknown()); + root.insert_tagged( + self.field.as_ref().unwrap(), + Tagged { + item: Value::List(self.values.clone()), + tag: Tag::unknown(), + }, + ); + Ok(vec![ReturnSuccess::value(root.into_tagged_value())]) + } +} + +fn main() { + serve_plugin(&mut Embed::new()); +} diff --git a/tests/filters_test.rs b/tests/filters_test.rs index d7bfd10644..9e7365ca47 100644 --- a/tests/filters_test.rs +++ b/tests/filters_test.rs @@ -508,3 +508,61 @@ fn can_get_reverse_first() { assert_eq!(actual, "utf16.ini"); } + +#[test] +fn embed() { + Playground::setup("embed_test", |dirs, sandbox| { + sandbox.with_files(vec![FileWithContentToBeTrimmed( + "los_tres_caballeros.txt", + r#" + first_name,last_name + Andrés,Robalino + Jonathan,Turner + Yehuda,Katz + "#, + )]); + + let actual = nu!( + cwd: dirs.test(), h::pipeline( + r#" + open los_tres_caballeros.txt + | from-csv + | embed caballeros + | get caballeros + | nth 0 + | get last_name + | echo $it + "# + )); + + assert_eq!(actual, "Robalino"); + }) +} + +#[test] +fn get() { + Playground::setup("get_test", |dirs, sandbox| { + sandbox.with_files(vec![FileWithContentToBeTrimmed( + "los_tres_caballeros.txt", + r#" + first_name,last_name + Andrés,Robalino + Jonathan,Turner + Yehuda,Katz + "#, + )]); + + let actual = nu!( + cwd: dirs.test(), h::pipeline( + r#" + open los_tres_caballeros.txt + | from-csv + | nth 1 + | get last_name + | echo $it + "# + )); + + assert_eq!(actual, "Turner"); + }) +}