forked from extern/nushell
into cellpath command (#7417)
# Description Address part of feature request #7337, add a small command `into cellpath` to allow string -> cellpath auto-conversion, with this change, we could run ``` let p = 'ls.use_ls_colors' $env.config | upsert ($p | nito cellpath) false ``` <img width="710" alt="image" src="https://user-images.githubusercontent.com/85712372/206782818-3024b34f-150b-482d-aebc-9426ef6a1cf9.png"> Note - This pr only covers `String` -> `CellPath`, any other conversions should be considered as expected? # Tests + Formatting Don't forget to add tests that cover your changes. Make sure you've run and fixed any issues with these commands: - [x] `cargo fmt --all -- --check` to check standard code formatting (`cargo fmt --all` applies these changes) - [x] `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A clippy::needless_collect` to check that you're using the standard code style - [x] `cargo test --workspace` to check that all tests pass # After Submitting If your PR had any user-facing changes, update [the documentation](https://github.com/nushell/nushell.github.io) after the PR is merged, if necessary. This will help us keep the docs up to date.
This commit is contained in:
parent
fa6bb147ea
commit
f0e93c2fa9
121
crates/nu-command/src/conversions/into/cellpath.rs
Normal file
121
crates/nu-command/src/conversions/into/cellpath.rs
Normal file
@ -0,0 +1,121 @@
|
||||
use nu_protocol::ast::{CellPath, PathMember};
|
||||
|
||||
use nu_protocol::{
|
||||
ast::Call,
|
||||
engine::{Command, EngineState, Stack},
|
||||
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, Type, Value,
|
||||
};
|
||||
#[derive(Clone)]
|
||||
pub struct SubCommand;
|
||||
|
||||
impl Command for SubCommand {
|
||||
fn name(&self) -> &str {
|
||||
"into cellpath"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("into cellpath")
|
||||
.input_output_types(vec![(Type::String, Type::CellPath)])
|
||||
.category(Category::Conversions)
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Convert value to a cellpath."
|
||||
}
|
||||
|
||||
fn search_terms(&self) -> Vec<&str> {
|
||||
vec!["convert"]
|
||||
}
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
engine_state: &EngineState,
|
||||
_stack: &mut Stack,
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
||||
into_cellpath(engine_state, call, input)
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![
|
||||
Example {
|
||||
description: "Convert from string to cellpath",
|
||||
example: " 'config.show_banner' | into cellpath",
|
||||
result: Some(Value::CellPath {
|
||||
val: CellPath {
|
||||
members: vec![
|
||||
PathMember::String {
|
||||
val: "config".to_string(),
|
||||
span: Span::new(1, 21),
|
||||
},
|
||||
PathMember::String {
|
||||
val: "show_banner".to_string(),
|
||||
span: Span::new(1, 21),
|
||||
},
|
||||
],
|
||||
},
|
||||
span: Span::new(1, 21),
|
||||
}),
|
||||
},
|
||||
Example {
|
||||
description: "Convert from string to cellpath",
|
||||
example: " 'a' | into cellpath",
|
||||
result: Some(Value::CellPath {
|
||||
val: CellPath {
|
||||
members: vec![PathMember::String {
|
||||
val: "a".to_string(),
|
||||
span: Span::new(38, 41),
|
||||
}],
|
||||
},
|
||||
span: Span::new(1, 2),
|
||||
}),
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
fn into_cellpath(
|
||||
_: &EngineState,
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let input = input.into_value(call.head);
|
||||
let res = match input {
|
||||
Value::String { val, span } => parse_string_into_cellapth(val, span),
|
||||
other => Value::Error {
|
||||
error: ShellError::UnsupportedInput(
|
||||
"'into cellpath' does not support this input".into(),
|
||||
other.span().unwrap_or(call.head),
|
||||
),
|
||||
},
|
||||
};
|
||||
Ok(res.into_pipeline_data())
|
||||
}
|
||||
|
||||
fn parse_string_into_cellapth(val: String, span: Span) -> Value {
|
||||
let parts = val.split('.').collect::<Vec<&str>>();
|
||||
let mut cellpath: Vec<PathMember> = vec![];
|
||||
for part in parts {
|
||||
cellpath.push(PathMember::String {
|
||||
val: part.to_string(),
|
||||
span,
|
||||
})
|
||||
}
|
||||
Value::CellPath {
|
||||
val: CellPath { members: cellpath },
|
||||
span,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_examples() {
|
||||
use crate::test_examples;
|
||||
|
||||
test_examples(SubCommand {})
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
mod binary;
|
||||
mod bool;
|
||||
mod cellpath;
|
||||
mod command;
|
||||
mod datetime;
|
||||
mod decimal;
|
||||
@ -12,6 +13,7 @@ mod string;
|
||||
pub use self::bool::SubCommand as IntoBool;
|
||||
pub use self::filesize::SubCommand as IntoFilesize;
|
||||
pub use binary::SubCommand as IntoBinary;
|
||||
pub use cellpath::SubCommand as IntoCellPath;
|
||||
pub use command::Into;
|
||||
pub use datetime::SubCommand as IntoDatetime;
|
||||
pub use decimal::SubCommand as IntoDecimal;
|
||||
|
@ -370,6 +370,7 @@ pub fn create_default_context() -> EngineState {
|
||||
IntoDuration,
|
||||
IntoFilesize,
|
||||
IntoInt,
|
||||
IntoCellPath,
|
||||
IntoRecord,
|
||||
IntoString,
|
||||
};
|
||||
|
14
crates/nu-command/tests/commands/into_cellpath.rs
Normal file
14
crates/nu-command/tests/commands/into_cellpath.rs
Normal file
@ -0,0 +1,14 @@
|
||||
use nu_test_support::{nu, pipeline};
|
||||
|
||||
#[test]
|
||||
fn into_pathcell_string() {
|
||||
let actual = nu!(
|
||||
cwd: ".", pipeline(
|
||||
r#"
|
||||
'nu.is.awesome' | into cellpath
|
||||
"#
|
||||
));
|
||||
dbg!(&actual.out);
|
||||
|
||||
assert!(actual.out.contains("nu.is.awesome"));
|
||||
}
|
@ -34,6 +34,7 @@ mod headers;
|
||||
mod help;
|
||||
mod histogram;
|
||||
mod insert;
|
||||
mod into_cellpath;
|
||||
mod into_filesize;
|
||||
mod into_int;
|
||||
mod last;
|
||||
|
21
src/tests.rs
21
src/tests.rs
@ -25,6 +25,8 @@ use tempfile::NamedTempFile;
|
||||
|
||||
pub type TestResult = Result<(), Box<dyn std::error::Error>>;
|
||||
|
||||
const DEFAULT_CONFIG: &str = "./crates/nu-utils/src/sample_config/default_config.nu";
|
||||
|
||||
pub fn run_test_with_env(input: &str, expected: &str, env: &HashMap<&str, &str>) -> TestResult {
|
||||
let mut file = NamedTempFile::new()?;
|
||||
let name = file.path();
|
||||
@ -54,6 +56,25 @@ pub fn run_test(input: &str, expected: &str) -> TestResult {
|
||||
run_cmd_and_assert(cmd, expected)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub fn run_test_with_default_config(input: &str, expected: &str) -> TestResult {
|
||||
let mut file = NamedTempFile::new()?;
|
||||
let name = file.path();
|
||||
|
||||
let mut cmd = Command::cargo_bin("nu")?;
|
||||
cmd.arg("--config");
|
||||
cmd.arg(DEFAULT_CONFIG);
|
||||
cmd.arg(name);
|
||||
cmd.env(
|
||||
"PWD",
|
||||
std::env::current_dir().expect("Can't get current dir"),
|
||||
);
|
||||
|
||||
writeln!(file, "{}", input)?;
|
||||
|
||||
run_cmd_and_assert(cmd, expected)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
fn run_cmd_and_assert(mut cmd: Command, expected: &str) -> TestResult {
|
||||
let output = cmd.output()?;
|
||||
|
@ -1,5 +1,7 @@
|
||||
use crate::tests::{run_test, TestResult};
|
||||
|
||||
use super::run_test_with_default_config;
|
||||
|
||||
#[test]
|
||||
fn shorthand_env_1() -> TestResult {
|
||||
run_test(r#"FOO=BAZ $env.FOO"#, "BAZ")
|
||||
@ -22,3 +24,11 @@ fn convert_non_string_env_var_to_nothing() -> TestResult {
|
||||
"nothing",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn convert_string_to_env_var_cellpath() -> TestResult {
|
||||
run_test_with_default_config(
|
||||
r#"let p = 'ls.use_ls_colors'; $env.config | upsert ($p | into cellpath) false | get ls.use_ls_colors"#,
|
||||
"false",
|
||||
)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user