str plugin can capitalize and trim strings. (#1652)

* Str plugin can capitalize.

* Str plugin can trim.
This commit is contained in:
Andrés N. Robalino 2020-04-24 16:37:58 -05:00 committed by GitHub
parent 716c4def03
commit 10768b6ecf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 188 additions and 8 deletions

View File

@ -15,9 +15,11 @@ impl Plugin for Str {
fn config(&mut self) -> Result<Signature, ShellError> {
Ok(Signature::build("str")
.desc("Apply string function. Optional use the column of a table")
.switch("capitalize", "capitalizes the string", Some('c'))
.switch("downcase", "convert string to lowercase", Some('d'))
.switch("upcase", "convert string to uppercase", Some('U'))
.switch("to-int", "convert string to integer", Some('i'))
.switch("trim", "trims the string", Some('t'))
.named(
"replace",
SyntaxShape::String,
@ -49,6 +51,12 @@ impl Plugin for Str {
fn begin_filter(&mut self, call_info: CallInfo) -> Result<Vec<ReturnValue>, ShellError> {
let args = call_info.args;
if args.has("trim") {
self.for_trim();
}
if args.has("capitalize") {
self.for_capitalize();
}
if args.has("downcase") {
self.for_downcase();
}

View File

@ -56,6 +56,20 @@ mod integration {
});
}
#[test]
fn picks_up_trim_flag() {
plugin(&mut Str::new())
.args(CallStub::new().with_long_flag("trim").create())
.setup(|plugin, _| plugin.expect_action(Action::Trim));
}
#[test]
fn picks_up_capitalize_flag() {
plugin(&mut Str::new())
.args(CallStub::new().with_long_flag("capitalize").create())
.setup(|plugin, _| plugin.expect_action(Action::Capitalize));
}
#[test]
fn picks_up_downcase_flag() {
plugin(&mut Str::new())
@ -169,6 +183,44 @@ mod integration {
Ok(())
}
#[test]
fn trims_the_input_using_the_field_passed_as_parameter() -> Result<(), ShellError> {
let run = plugin(&mut Str::new())
.args(
CallStub::new()
.with_long_flag("trim")
.with_parameter("name")?
.create(),
)
.input(structured_sample_record("name", "andres "))
.setup(|_, _| {})
.test();
let actual = expect_return_value_at(run, 0);
assert_eq!(get_data(actual, "name"), string("andres"));
Ok(())
}
#[test]
fn capitalizes_the_input_using_the_field_passed_as_parameter() -> Result<(), ShellError> {
let run = plugin(&mut Str::new())
.args(
CallStub::new()
.with_long_flag("capitalize")
.with_parameter("name")?
.create(),
)
.input(structured_sample_record("name", "andres"))
.setup(|_, _| {})
.test();
let actual = expect_return_value_at(run, 0);
assert_eq!(get_data(actual, "name"), string("Andres"));
Ok(())
}
#[test]
fn downcases_the_input_using_the_field_passed_as_parameter() -> Result<(), ShellError> {
let run = plugin(&mut Str::new())
@ -261,6 +313,30 @@ mod integration {
assert_eq!(actual, string("JOANDREHUDA"));
}
#[test]
fn trims_the_input() {
let run = plugin(&mut Str::new())
.args(CallStub::new().with_long_flag("trim").create())
.input(unstructured_sample_record("andres "))
.setup(|_, _| {})
.test();
let actual = expect_return_value_at(run, 0);
assert_eq!(actual, string("andres"));
}
#[test]
fn capitalizes_the_input() {
let run = plugin(&mut Str::new())
.args(CallStub::new().with_long_flag("capitalize").create())
.input(unstructured_sample_record("andres"))
.setup(|_, _| {})
.test();
let actual = expect_return_value_at(run, 0);
assert_eq!(actual, string("Andres"));
}
#[test]
fn downcases_the_input() {
let run = plugin(&mut Str::new())

View File

@ -10,12 +10,14 @@ use std::cmp;
#[derive(Debug, Eq, PartialEq)]
pub enum Action {
Capitalize,
Downcase,
Upcase,
ToInteger,
Substring(usize, usize),
Replace(ReplaceAction),
ToDateTime(String),
Trim,
}
#[derive(Debug, Eq, PartialEq)]
@ -38,6 +40,22 @@ impl Str {
fn apply(&self, input: &str) -> Result<UntaggedValue, ShellError> {
let applied = match self.action.as_ref() {
Some(Action::Trim) => UntaggedValue::string(input.trim()),
Some(Action::Capitalize) => {
let mut capitalized = String::new();
for (idx, character) in input.chars().enumerate() {
let out = if idx == 0 {
character.to_uppercase().to_string()
} else {
character.to_lowercase().to_string()
};
capitalized.push_str(&out);
}
UntaggedValue::string(capitalized)
}
Some(Action::Downcase) => UntaggedValue::string(input.to_ascii_lowercase()),
Some(Action::Upcase) => UntaggedValue::string(input.to_ascii_uppercase()),
Some(Action::Substring(s, e)) => {
@ -101,6 +119,14 @@ impl Str {
self.add_action(Action::ToInteger);
}
pub fn for_capitalize(&mut self) {
self.add_action(Action::Capitalize);
}
pub fn for_trim(&mut self) {
self.add_action(Action::Trim);
}
pub fn for_downcase(&mut self) {
self.add_action(Action::Downcase);
}
@ -151,7 +177,7 @@ impl Str {
}
pub fn usage() -> &'static str {
"Usage: str field [--downcase|--upcase|--to-int|--substring \"start,end\"|--replace|--find-replace [pattern replacement]]]"
"Usage: str field [--capitalize|--downcase|--upcase|--to-int|--substring \"start,end\"|--replace|--find-replace [pattern replacement]|to-date-time|--trim]"
}
pub fn strutils(&self, value: Value) -> Result<Value, ShellError> {
@ -216,6 +242,22 @@ pub mod tests {
use super::Str;
use nu_plugin::test_helpers::value::{int, string};
#[test]
fn trim() -> Result<(), Box<dyn std::error::Error>> {
let mut strutils = Str::new();
strutils.for_trim();
assert_eq!(strutils.apply("andres ")?, string("andres").value);
Ok(())
}
#[test]
fn capitalize() -> Result<(), Box<dyn std::error::Error>> {
let mut strutils = Str::new();
strutils.for_capitalize();
assert_eq!(strutils.apply("andres")?, string("Andres").value);
Ok(())
}
#[test]
fn downcases() -> Result<(), Box<dyn std::error::Error>> {
let mut strutils = Str::new();

View File

@ -47,4 +47,18 @@ Consumes either a single value or a table and converts the provided data to a st
─────────
6
━━━━━━━━━
```
> echo "nu" | str --capitalize
━━━━━━━━━
<value>
─────────
Nu
━━━━━━━━━
> echo "Nu " | str --trim
━━━━━━━━━
<value>
─────────
Nu
━━━━━━━━━
```

View File

@ -9,7 +9,7 @@ fn can_only_apply_one() {
"open caco3_plastics.csv | first 1 | str origin --downcase --upcase"
);
assert!(actual.contains(r#"--downcase|--upcase|--to-int|--substring "start,end"|--replace|--find-replace [pattern replacement]]"#));
assert!(actual.contains(r#"--capitalize|--downcase|--upcase|--to-int|--substring "start,end"|--replace|--find-replace [pattern replacement]|to-date-time|--trim]"#));
}
#[test]
@ -34,8 +34,48 @@ fn acts_without_passing_field() {
}
#[test]
fn downcases() {
fn trims() {
Playground::setup("plugin_str_test_2", |dirs, sandbox| {
sandbox.with_files(vec![FileWithContent(
"sample.toml",
r#"
[dependency]
name = "nu "
"#,
)]);
let actual = nu!(
cwd: dirs.test(),
"open sample.toml | str dependency.name --trim | get dependency.name | echo $it"
);
assert_eq!(actual, "nu");
})
}
#[test]
fn capitalizes() {
Playground::setup("plugin_str_test_3", |dirs, sandbox| {
sandbox.with_files(vec![FileWithContent(
"sample.toml",
r#"
[dependency]
name = "nu"
"#,
)]);
let actual = nu!(
cwd: dirs.test(),
"open sample.toml | str dependency.name --capitalize | get dependency.name | echo $it"
);
assert_eq!(actual, "Nu");
})
}
#[test]
fn downcases() {
Playground::setup("plugin_str_test_4", |dirs, sandbox| {
sandbox.with_files(vec![FileWithContent(
"sample.toml",
r#"
@ -55,7 +95,7 @@ fn downcases() {
#[test]
fn upcases() {
Playground::setup("plugin_str_test_3", |dirs, sandbox| {
Playground::setup("plugin_str_test_5", |dirs, sandbox| {
sandbox.with_files(vec![FileWithContent(
"sample.toml",
r#"
@ -93,7 +133,7 @@ fn converts_to_int() {
#[test]
fn replaces() {
Playground::setup("plugin_str_test_4", |dirs, sandbox| {
Playground::setup("plugin_str_test_5", |dirs, sandbox| {
sandbox.with_files(vec![FileWithContent(
"sample.toml",
r#"
@ -118,7 +158,7 @@ fn replaces() {
#[test]
fn find_and_replaces() {
Playground::setup("plugin_str_test_5", |dirs, sandbox| {
Playground::setup("plugin_str_test_6", |dirs, sandbox| {
sandbox.with_files(vec![FileWithContent(
"sample.toml",
r#"
@ -143,7 +183,7 @@ fn find_and_replaces() {
#[test]
fn find_and_replaces_without_passing_field() {
Playground::setup("plugin_str_test_6", |dirs, sandbox| {
Playground::setup("plugin_str_test_7", |dirs, sandbox| {
sandbox.with_files(vec![FileWithContent(
"sample.toml",
r#"