forked from extern/nushell
add "into int" behavior (#3279)
* add 'int' command * create `into int` behavior - forcibly overwrote prior implementation ```sh git mv -f crates/nu-command/src/commands/int_.rs crates/nu-command/src/commands/into_int.rs ``` - picked up prior work, polished and renamed Co-authored-by: Saeed Rasooli <saeed.gnu@gmail.com>
This commit is contained in:
parent
b791d1ab0d
commit
556596bce8
@ -1,28 +1,33 @@
|
|||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use nu_engine::WholeStreamCommand;
|
use nu_engine::WholeStreamCommand;
|
||||||
use nu_errors::ShellError;
|
use nu_errors::ShellError;
|
||||||
use nu_protocol::{Primitive, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
|
use nu_protocol::{
|
||||||
|
ColumnPath, Primitive, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value,
|
||||||
|
};
|
||||||
|
|
||||||
use num_bigint::ToBigInt;
|
use num_bigint::{BigInt, ToBigInt};
|
||||||
|
|
||||||
pub struct IntoInt;
|
pub struct IntoInt;
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct IntoIntArgs {
|
pub struct IntoIntArgs {
|
||||||
pub rest: Vec<Value>,
|
pub rest: Vec<ColumnPath>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WholeStreamCommand for IntoInt {
|
impl WholeStreamCommand for IntoInt {
|
||||||
fn name(&self) -> &str {
|
fn name(&self) -> &str {
|
||||||
"into-int"
|
"into int"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build("into-int").rest(SyntaxShape::Any, "the values to into-int")
|
Signature::build("into int").rest(
|
||||||
|
SyntaxShape::ColumnPath,
|
||||||
|
"column paths to convert to int (for table input)",
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
fn usage(&self) -> &str {
|
||||||
"Convert value to integer."
|
"Convert value to integer"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
@ -32,45 +37,136 @@ impl WholeStreamCommand for IntoInt {
|
|||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
vec![
|
vec![
|
||||||
Example {
|
Example {
|
||||||
description: "Convert filesize to integer",
|
description: "Convert string to integer in table",
|
||||||
example: "into-int 1kb | each { = $it / 1000 }",
|
example: "echo [[num]; ['-5'] [4] [1.5]] | into int num",
|
||||||
result: Some(vec![UntaggedValue::int(1).into()]),
|
result: Some(vec![
|
||||||
|
UntaggedValue::row(indexmap! {
|
||||||
|
"num".to_string() => UntaggedValue::int(-5).into(),
|
||||||
|
})
|
||||||
|
.into(),
|
||||||
|
UntaggedValue::row(indexmap! {
|
||||||
|
"num".to_string() => UntaggedValue::int(4).into(),
|
||||||
|
})
|
||||||
|
.into(),
|
||||||
|
UntaggedValue::row(indexmap! {
|
||||||
|
"num".to_string() => UntaggedValue::int(1).into(),
|
||||||
|
})
|
||||||
|
.into(),
|
||||||
|
]),
|
||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "Convert filesize to integer",
|
description: "Convert string to integer",
|
||||||
example: "into-int 1kib | each { = $it / 1024 }",
|
example: "echo '2' | into int",
|
||||||
result: Some(vec![UntaggedValue::int(1).into()]),
|
result: Some(vec![UntaggedValue::int(2).into()]),
|
||||||
|
},
|
||||||
|
Example {
|
||||||
|
description: "Convert decimal to integer",
|
||||||
|
example: "echo 5.9 | into int",
|
||||||
|
result: Some(vec![UntaggedValue::int(5).into()]),
|
||||||
|
},
|
||||||
|
Example {
|
||||||
|
description: "Convert decimal string to integer",
|
||||||
|
example: "echo '5.9' | into int",
|
||||||
|
result: Some(vec![UntaggedValue::int(5).into()]),
|
||||||
|
},
|
||||||
|
Example {
|
||||||
|
description: "Convert file size to integer",
|
||||||
|
example: "echo 4KB | into int",
|
||||||
|
result: Some(vec![UntaggedValue::int(4000).into()]),
|
||||||
|
},
|
||||||
|
Example {
|
||||||
|
description: "Convert bool to integer",
|
||||||
|
example: "echo $false $true | into int",
|
||||||
|
result: Some(vec![
|
||||||
|
UntaggedValue::int(0).into(),
|
||||||
|
UntaggedValue::int(1).into(),
|
||||||
|
]),
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn into_int(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
fn into_int(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
let (args, _): (IntoIntArgs, _) = args.process()?;
|
let (IntoIntArgs { rest: column_paths }, input) = args.process()?;
|
||||||
|
|
||||||
let stream = args.rest.into_iter().map(|i| match i {
|
Ok(input
|
||||||
Value {
|
.map(move |v| {
|
||||||
value: UntaggedValue::Primitive(primitive_val),
|
if column_paths.is_empty() {
|
||||||
|
ReturnSuccess::value(action(&v, v.tag())?)
|
||||||
|
} else {
|
||||||
|
let mut ret = v;
|
||||||
|
for path in &column_paths {
|
||||||
|
ret = ret.swap_data_by_column_path(
|
||||||
|
path,
|
||||||
|
Box::new(move |old| action(old, old.tag())),
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnSuccess::value(ret)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.to_output_stream())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn action(input: &Value, tag: impl Into<Tag>) -> Result<Value, ShellError> {
|
||||||
|
let tag = tag.into();
|
||||||
|
match &input.value {
|
||||||
|
UntaggedValue::Primitive(prim) => Ok(UntaggedValue::int(match prim {
|
||||||
|
Primitive::String(a_string) => match int_from_string(a_string, &tag) {
|
||||||
|
Ok(n) => n,
|
||||||
|
Err(e) => {
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Primitive::Decimal(dec) => match dec.to_bigint() {
|
||||||
|
Some(n) => n,
|
||||||
|
None => {
|
||||||
|
return Err(ShellError::unimplemented(
|
||||||
|
"failed to convert decimal to int",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Primitive::Int(n_ref) => n_ref.to_bigint().expect("unexpected error"),
|
||||||
|
Primitive::Boolean(a_bool) => match a_bool {
|
||||||
|
false => 0.to_bigint().expect("unexpected error"),
|
||||||
|
true => 1.to_bigint().expect("unexpected error"),
|
||||||
|
},
|
||||||
|
Primitive::Filesize(a_filesize) => a_filesize
|
||||||
|
.to_bigint()
|
||||||
|
.expect("Conversion should never fail."),
|
||||||
|
_ => {
|
||||||
|
return Err(ShellError::unimplemented(
|
||||||
|
"'int' for non-numeric primitives",
|
||||||
|
))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.into_value(&tag)),
|
||||||
|
UntaggedValue::Row(_) => Err(ShellError::labeled_error(
|
||||||
|
"specify column name to use, with 'int COLUMN'",
|
||||||
|
"found table",
|
||||||
tag,
|
tag,
|
||||||
} => match primitive_val {
|
)),
|
||||||
Primitive::Filesize(size) => OutputStream::one(Ok(ReturnSuccess::Value(Value {
|
_ => Err(ShellError::unimplemented("'int' for unsupported type")),
|
||||||
value: UntaggedValue::int(size.to_bigint().expect("Conversion should never fail.")),
|
}
|
||||||
tag,
|
}
|
||||||
}))),
|
|
||||||
Primitive::Int(_) => OutputStream::one(Ok(ReturnSuccess::Value(Value {
|
|
||||||
value: UntaggedValue::Primitive(primitive_val),
|
|
||||||
tag,
|
|
||||||
}))),
|
|
||||||
_ => OutputStream::one(Err(ShellError::labeled_error(
|
|
||||||
"Could not convert int value",
|
|
||||||
"original value",
|
|
||||||
tag,
|
|
||||||
))),
|
|
||||||
},
|
|
||||||
_ => OutputStream::one(Ok(ReturnSuccess::Value(i))),
|
|
||||||
});
|
|
||||||
|
|
||||||
Ok(stream.flatten().to_output_stream())
|
fn int_from_string(a_string: &str, tag: &Tag) -> Result<BigInt, ShellError> {
|
||||||
|
match a_string.parse::<BigInt>() {
|
||||||
|
Ok(n) => Ok(n),
|
||||||
|
Err(_) => match a_string.parse::<f64>() {
|
||||||
|
Ok(res_float) => match res_float.to_bigint() {
|
||||||
|
Some(n) => Ok(n),
|
||||||
|
None => Err(ShellError::unimplemented(
|
||||||
|
"failed to convert decimal to int",
|
||||||
|
)),
|
||||||
|
},
|
||||||
|
Err(_) => Err(ShellError::labeled_error(
|
||||||
|
"Could not convert string value to int",
|
||||||
|
"original value",
|
||||||
|
tag.clone(),
|
||||||
|
)),
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -5,7 +5,7 @@ fn into_int_filesize() {
|
|||||||
let actual = nu!(
|
let actual = nu!(
|
||||||
cwd: ".", pipeline(
|
cwd: ".", pipeline(
|
||||||
r#"
|
r#"
|
||||||
into-int 1kb | each {= $it / 1000 }
|
echo 1kb | into int | each {= $it / 1000 }
|
||||||
"#
|
"#
|
||||||
));
|
));
|
||||||
|
|
||||||
@ -17,7 +17,7 @@ fn into_int_filesize2() {
|
|||||||
let actual = nu!(
|
let actual = nu!(
|
||||||
cwd: ".", pipeline(
|
cwd: ".", pipeline(
|
||||||
r#"
|
r#"
|
||||||
into-int 1kib | each {= $it / 1024 }
|
echo 1kib | into int | each {= $it / 1024 }
|
||||||
"#
|
"#
|
||||||
));
|
));
|
||||||
|
|
||||||
@ -29,7 +29,7 @@ fn into_int_int() {
|
|||||||
let actual = nu!(
|
let actual = nu!(
|
||||||
cwd: ".", pipeline(
|
cwd: ".", pipeline(
|
||||||
r#"
|
r#"
|
||||||
into-int 1024 | each {= $it / 1024 }
|
echo 1024 | into int | each {= $it / 1024 }
|
||||||
"#
|
"#
|
||||||
));
|
));
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user