Port rename (#877)

* Port rename

* Update description

* Fix fmt issues

* Refactor the code a bit and move things around
This commit is contained in:
Stefan Stanciulescu 2022-01-29 11:26:47 +01:00 committed by GitHub
parent 9450bcb90c
commit 1a25970645
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 171 additions and 0 deletions

View file

@ -83,6 +83,7 @@ pub fn create_default_context(cwd: impl AsRef<Path>) -> EngineState {
Range, Range,
Reduce, Reduce,
Reject, Reject,
Rename,
Reverse, Reverse,
Select, Select,
Shuffle, Shuffle,

View file

@ -26,6 +26,7 @@ mod prepend;
mod range; mod range;
mod reduce; mod reduce;
mod reject; mod reject;
mod rename;
mod reverse; mod reverse;
mod select; mod select;
mod shuffle; mod shuffle;
@ -66,6 +67,7 @@ pub use prepend::Prepend;
pub use range::Range; pub use range::Range;
pub use reduce::Reduce; pub use reduce::Reduce;
pub use reject::Reject; pub use reject::Reject;
pub use rename::Rename;
pub use reverse::Reverse; pub use reverse::Reverse;
pub use select::Select; pub use select::Select;
pub use shuffle::Shuffle; pub use shuffle::Shuffle;

View file

@ -0,0 +1,168 @@
use nu_engine::CallExt;
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Value,
};
#[derive(Clone)]
pub struct Rename;
impl Command for Rename {
fn name(&self) -> &str {
"rename"
}
fn signature(&self) -> Signature {
Signature::build("rename")
.named(
"column",
SyntaxShape::List(Box::new(SyntaxShape::String)),
"column name to be changed",
Some('c'),
)
.rest("rest", SyntaxShape::String, "the new names for the columns")
.category(Category::Filters)
}
fn usage(&self) -> &str {
"Creates a new table with columns renamed."
}
fn run(
&self,
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
rename(engine_state, stack, call, input)
}
fn examples(&self) -> Vec<Example> {
vec![
Example {
description: "Rename a column",
example: "[[a, b]; [1, 2]] | rename my_column",
result: Some(Value::List {
vals: vec![Value::Record {
cols: vec!["my_column".to_string(), "b".to_string()],
vals: vec![Value::test_int(1), Value::test_int(2)],
span: Span::test_data(),
}],
span: Span::test_data(),
}),
},
Example {
description: "Rename many columns",
example: "[[a, b, c]; [1, 2, 3]] | rename eggs ham bacon",
result: Some(Value::List {
vals: vec![Value::Record {
cols: vec!["eggs".to_string(), "ham".to_string(), "bacon".to_string()],
vals: vec![Value::test_int(1), Value::test_int(2), Value::test_int(3)],
span: Span::test_data(),
}],
span: Span::test_data(),
}),
},
Example {
description: "Rename a specific column",
example: "[[a, b, c]; [1, 2, 3]] | rename -c [a ham]",
result: Some(Value::List {
vals: vec![Value::Record {
cols: vec!["ham".to_string(), "b".to_string(), "c".to_string()],
vals: vec![Value::test_int(1), Value::test_int(2), Value::test_int(3)],
span: Span::test_data(),
}],
span: Span::test_data(),
}),
},
]
}
}
fn rename(
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
let specified_column: Option<Vec<String>> = call.get_flag(engine_state, stack, "column")?;
// get the span for the column's name to be changed and for the given list
let (specified_col_span, list_span) = if let Some(Value::List {
vals: columns,
span: column_span,
}) = call.get_flag(engine_state, stack, "column")?
{
(Some(columns[0].span()?), column_span)
} else {
(None, call.head)
};
if let Some(ref cols) = specified_column {
if cols.len() != 2 {
return Err(ShellError::UnsupportedInput(
"The list must contain only two values: the column's name and its replacement value"
.to_string(),
list_span,
));
}
}
let columns: Vec<String> = call.rest(engine_state, stack, 0)?;
input.map(
move |item| match item {
Value::Record {
mut cols,
vals,
span,
} => {
match &specified_column {
Some(c) => {
// check if the specified column to be renamed exists
if !cols.contains(&c[0]) {
return Value::Error {
error: ShellError::UnsupportedInput(
"The specified column does not exist".to_string(),
specified_col_span.unwrap_or(span),
),
};
}
for (idx, val) in cols.iter_mut().enumerate() {
if *val == c[0] {
cols[idx] = c[1].to_string();
break;
}
}
}
None => {
for (idx, val) in columns.iter().enumerate() {
if idx > cols.len() - 1 {
// skip extra new columns names if we already reached the final column
break;
}
cols[idx] = val.clone();
}
}
}
Value::Record { cols, vals, span }
}
x => x,
},
engine_state.ctrlc.clone(),
)
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_examples() {
use crate::test_examples;
test_examples(Rename {})
}
}