mirror of
https://github.com/nushell/nushell
synced 2024-09-20 14:42:01 +00:00
Add --to-float to str plugin (#1872)
This commit is contained in:
parent
fb09d7d1a1
commit
8a99d112fc
9 changed files with 86 additions and 5 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
@ -2319,6 +2319,7 @@ dependencies = [
|
|||
name = "nu-plugin"
|
||||
version = "0.14.1"
|
||||
dependencies = [
|
||||
"bigdecimal",
|
||||
"indexmap",
|
||||
"nu-build",
|
||||
"nu-errors",
|
||||
|
@ -2531,6 +2532,7 @@ dependencies = [
|
|||
name = "nu_plugin_str"
|
||||
version = "0.14.1"
|
||||
dependencies = [
|
||||
"bigdecimal",
|
||||
"chrono",
|
||||
"nu-build",
|
||||
"nu-errors",
|
||||
|
|
|
@ -179,7 +179,16 @@ pub fn autoview(context: RunnableContext) -> Result<OutputStream, ShellError> {
|
|||
value: UntaggedValue::Primitive(Primitive::Decimal(n)),
|
||||
..
|
||||
} => {
|
||||
out!("{}", n);
|
||||
// TODO: normalize decimal to remove trailing zeros.
|
||||
// normalization will be available in next release of bigdecimal crate
|
||||
let mut output = n.to_string();
|
||||
if output.contains('.') {
|
||||
output = output.trim_end_matches('0').to_owned();
|
||||
}
|
||||
if output.ends_with('.') {
|
||||
output.push('0');
|
||||
}
|
||||
out!("{}", output);
|
||||
}
|
||||
Value {
|
||||
value: UntaggedValue::Primitive(Primitive::Boolean(b)),
|
||||
|
|
|
@ -19,6 +19,7 @@ indexmap = { version = "1.3.2", features = ["serde-1"] }
|
|||
serde = { version = "1.0.110", features = ["derive"] }
|
||||
num-bigint = { version = "0.2.6", features = ["serde"] }
|
||||
serde_json = "1.0.53"
|
||||
bigdecimal = { version = "0.1.2", features = ["serde"] }
|
||||
|
||||
[build-dependencies]
|
||||
nu-build = { version = "0.14.1", path = "../nu-build" }
|
||||
|
|
|
@ -172,6 +172,7 @@ pub fn expect_return_value_at(
|
|||
}
|
||||
|
||||
pub mod value {
|
||||
use bigdecimal::BigDecimal;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{Primitive, TaggedDictBuilder, UntaggedValue, Value};
|
||||
use nu_source::Tag;
|
||||
|
@ -186,6 +187,10 @@ pub mod value {
|
|||
UntaggedValue::Primitive(Primitive::Int(i.into())).into_untagged_value()
|
||||
}
|
||||
|
||||
pub fn decimal(f: impl Into<BigDecimal>) -> Value {
|
||||
UntaggedValue::Primitive(Primitive::Decimal(f.into())).into_untagged_value()
|
||||
}
|
||||
|
||||
pub fn string(input: impl Into<String>) -> Value {
|
||||
UntaggedValue::string(input.into()).into_untagged_value()
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ chrono = { version = "0.4.11", features = ["serde"] }
|
|||
|
||||
regex = "1"
|
||||
num-bigint = "0.2.6"
|
||||
bigdecimal = { version = "0.1.2", features = ["serde"] }
|
||||
|
||||
[build-dependencies]
|
||||
nu-build = { version = "0.14.1", path = "../nu-build" }
|
||||
|
|
|
@ -19,6 +19,7 @@ impl Plugin for Str {
|
|||
.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("to-float", "convert string to float", Some('F'))
|
||||
.switch("trim", "trims the string", Some('t'))
|
||||
.named(
|
||||
"replace",
|
||||
|
@ -66,6 +67,9 @@ impl Plugin for Str {
|
|||
if args.has("to-int") {
|
||||
self.for_to_int();
|
||||
}
|
||||
if args.has("to-float") {
|
||||
self.for_to_float();
|
||||
}
|
||||
if args.has("substring") {
|
||||
if let Some(start_end) = args.get("substring") {
|
||||
match start_end {
|
||||
|
|
|
@ -3,7 +3,7 @@ mod integration {
|
|||
use crate::Str;
|
||||
use nu_errors::ShellError;
|
||||
use nu_plugin::test_helpers::value::{
|
||||
column_path, get_data, int, string, structured_sample_record, table,
|
||||
column_path, decimal, get_data, int, string, structured_sample_record, table,
|
||||
unstructured_sample_record,
|
||||
};
|
||||
use nu_plugin::test_helpers::{expect_return_value_at, plugin, CallStub};
|
||||
|
@ -91,6 +91,13 @@ mod integration {
|
|||
.setup(|plugin, _| plugin.expect_action(Action::ToInteger));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn picks_up_to_float_flag() {
|
||||
plugin(&mut Str::new())
|
||||
.args(CallStub::new().with_long_flag("to-float").create())
|
||||
.setup(|plugin, _| plugin.expect_action(Action::ToFloat));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn picks_up_arguments_for_replace_flag() {
|
||||
let argument = String::from("replace_text");
|
||||
|
@ -259,6 +266,24 @@ mod integration {
|
|||
assert_eq!(get_data(actual, "Nu_birthday"), int(10));
|
||||
Ok(())
|
||||
}
|
||||
#[test]
|
||||
fn converts_the_input_to_float_using_the_field_passed_as_parameter() -> Result<(), ShellError> {
|
||||
let run = plugin(&mut Str::new())
|
||||
.args(
|
||||
CallStub::new()
|
||||
.with_long_flag("to-float")
|
||||
.with_parameter("PI")?
|
||||
.create(),
|
||||
)
|
||||
.input(structured_sample_record("PI", "3.1415"))
|
||||
.setup(|_, _| {})
|
||||
.test();
|
||||
|
||||
let actual = expect_return_value_at(run, 0);
|
||||
|
||||
assert_eq!(get_data(actual, "PI"), decimal(3.1415));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn replaces_the_input_using_the_field_passed_as_parameter() -> Result<(), ShellError> {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
extern crate chrono;
|
||||
|
||||
use bigdecimal::BigDecimal;
|
||||
use chrono::DateTime;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{did_you_mean, ColumnPath, Primitive, ShellTypeName, UntaggedValue, Value};
|
||||
|
@ -7,6 +8,7 @@ use nu_source::{span_for_spanned_list, Tagged};
|
|||
use nu_value_ext::ValueExt;
|
||||
use regex::Regex;
|
||||
use std::cmp;
|
||||
use std::str::FromStr;
|
||||
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
pub enum Action {
|
||||
|
@ -14,6 +16,7 @@ pub enum Action {
|
|||
Downcase,
|
||||
Upcase,
|
||||
ToInteger,
|
||||
ToFloat,
|
||||
Substring(usize, usize),
|
||||
Replace(ReplaceAction),
|
||||
ToDateTime(String),
|
||||
|
@ -93,6 +96,10 @@ impl Str {
|
|||
Err(_) => UntaggedValue::string(input),
|
||||
}
|
||||
}
|
||||
Some(Action::ToFloat) => match BigDecimal::from_str(input.trim()) {
|
||||
Ok(v) => UntaggedValue::decimal(v),
|
||||
Err(_) => UntaggedValue::string(input),
|
||||
},
|
||||
Some(Action::ToDateTime(dt)) => match DateTime::parse_from_str(input, dt) {
|
||||
Ok(d) => UntaggedValue::date(d),
|
||||
Err(_) => UntaggedValue::string(input),
|
||||
|
@ -119,6 +126,10 @@ impl Str {
|
|||
self.add_action(Action::ToInteger);
|
||||
}
|
||||
|
||||
pub fn for_to_float(&mut self) {
|
||||
self.add_action(Action::ToFloat);
|
||||
}
|
||||
|
||||
pub fn for_capitalize(&mut self) {
|
||||
self.add_action(Action::Capitalize);
|
||||
}
|
||||
|
@ -177,7 +188,7 @@ impl Str {
|
|||
}
|
||||
|
||||
pub fn usage() -> &'static str {
|
||||
"Usage: str field [--capitalize|--downcase|--upcase|--to-int|--substring \"start,end\"|--replace|--find-replace [pattern replacement]|to-date-time|--trim]"
|
||||
"Usage: str field [--capitalize|--downcase|--upcase|--to-int|--to-float|--substring \"start,end\"|--replace|--find-replace [pattern replacement]|to-date-time|--trim]"
|
||||
}
|
||||
|
||||
pub fn strutils(&self, value: Value) -> Result<Value, ShellError> {
|
||||
|
@ -240,7 +251,7 @@ impl Str {
|
|||
pub mod tests {
|
||||
use super::ReplaceAction;
|
||||
use super::Str;
|
||||
use nu_plugin::test_helpers::value::{int, string};
|
||||
use nu_plugin::test_helpers::value::{decimal, int, string};
|
||||
|
||||
#[test]
|
||||
fn trim() -> Result<(), Box<dyn std::error::Error>> {
|
||||
|
@ -282,6 +293,14 @@ pub mod tests {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn converts_to_float() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let mut strutils = Str::new();
|
||||
strutils.for_to_float();
|
||||
assert_eq!(strutils.apply("3.1415")?, decimal(3.1415).value);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn replaces() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let mut strutils = Str::new();
|
||||
|
|
|
@ -9,7 +9,7 @@ fn can_only_apply_one() {
|
|||
"open caco3_plastics.csv | first 1 | str origin --downcase --upcase"
|
||||
);
|
||||
|
||||
assert!(actual.err.contains(r#"--capitalize|--downcase|--upcase|--to-int|--substring "start,end"|--replace|--find-replace [pattern replacement]|to-date-time|--trim]"#));
|
||||
assert!(actual.err.contains(r#"--capitalize|--downcase|--upcase|--to-int|--to-float|--substring "start,end"|--replace|--find-replace [pattern replacement]|to-date-time|--trim]"#));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -131,6 +131,21 @@ fn converts_to_int() {
|
|||
assert_eq!(actual.out, "1");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn converts_to_float() {
|
||||
let actual = nu!(
|
||||
cwd: "tests/fixtures/formats", pipeline(
|
||||
r#"
|
||||
echo "3.1, 0.0415"
|
||||
| split row ","
|
||||
| str --to-float
|
||||
| sum
|
||||
"#
|
||||
));
|
||||
|
||||
assert_eq!(actual.out, "3.1415");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn replaces() {
|
||||
Playground::setup("plugin_str_test_5", |dirs, sandbox| {
|
||||
|
|
Loading…
Reference in a new issue