mirror of
https://github.com/nushell/nushell
synced 2024-12-27 05:23:11 +00:00
Yet more ununwraps (#1150)
This commit is contained in:
parent
5e31851070
commit
3e3cb15f3d
7 changed files with 135 additions and 76 deletions
|
@ -103,11 +103,11 @@ impl TestRegistry {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SignatureRegistry for TestRegistry {
|
impl SignatureRegistry for TestRegistry {
|
||||||
fn has(&self, name: &str) -> bool {
|
fn has(&self, name: &str) -> Result<bool, ShellError> {
|
||||||
self.signatures.contains_key(name)
|
Ok(self.signatures.contains_key(name))
|
||||||
}
|
}
|
||||||
fn get(&self, name: &str) -> Option<Signature> {
|
fn get(&self, name: &str) -> Result<Option<Signature>, ShellError> {
|
||||||
self.signatures.get(name).cloned()
|
Ok(self.signatures.get(name).cloned())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -127,8 +127,8 @@ impl ExpandExpression for SyntaxShape {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait SignatureRegistry {
|
pub trait SignatureRegistry {
|
||||||
fn has(&self, name: &str) -> bool;
|
fn has(&self, name: &str) -> Result<bool, ShellError>;
|
||||||
fn get(&self, name: &str) -> Option<Signature>;
|
fn get(&self, name: &str) -> Result<Option<Signature>, ShellError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Getters, new)]
|
#[derive(Getters, new)]
|
||||||
|
@ -673,16 +673,26 @@ impl FallibleColorSyntax for CommandHeadShape {
|
||||||
UnspannedAtomicToken::Word { text } => {
|
UnspannedAtomicToken::Word { text } => {
|
||||||
let name = text.slice(context.source);
|
let name = text.slice(context.source);
|
||||||
|
|
||||||
if context.registry.has(name) {
|
if context.registry.has(name)? {
|
||||||
// If the registry has the command, color it as an internal command
|
// If the registry has the command, color it as an internal command
|
||||||
token_nodes.color_shape(FlatShape::InternalCommand.spanned(text));
|
token_nodes.color_shape(FlatShape::InternalCommand.spanned(text));
|
||||||
let signature = context.registry.get(name).ok_or_else(|| {
|
let signature = context
|
||||||
ShellError::labeled_error(
|
.registry
|
||||||
"Internal error: could not load signature from registry",
|
.get(name)
|
||||||
"could not load from registry",
|
.map_err(|_| {
|
||||||
text,
|
ShellError::labeled_error(
|
||||||
)
|
"Internal error: could not load signature from registry",
|
||||||
})?;
|
"could not load from registry",
|
||||||
|
text,
|
||||||
|
)
|
||||||
|
})?
|
||||||
|
.ok_or_else(|| {
|
||||||
|
ShellError::labeled_error(
|
||||||
|
"Internal error: could not load signature from registry",
|
||||||
|
"could not load from registry",
|
||||||
|
text,
|
||||||
|
)
|
||||||
|
})?;
|
||||||
Ok(CommandHeadKind::Internal(signature))
|
Ok(CommandHeadKind::Internal(signature))
|
||||||
} else {
|
} else {
|
||||||
// Otherwise, color it as an external command
|
// Otherwise, color it as an external command
|
||||||
|
@ -721,10 +731,14 @@ impl ExpandSyntax for CommandHeadShape {
|
||||||
},
|
},
|
||||||
UnspannedToken::Bare => {
|
UnspannedToken::Bare => {
|
||||||
let name = token_span.slice(context.source);
|
let name = token_span.slice(context.source);
|
||||||
if context.registry.has(name) {
|
if context.registry.has(name)? {
|
||||||
let signature = context.registry.get(name).ok_or_else(|| {
|
let signature = context
|
||||||
ParseError::internal_error(name.spanned(token_span))
|
.registry
|
||||||
})?;
|
.get(name)
|
||||||
|
.map_err(|_| ParseError::internal_error(name.spanned(token_span)))?
|
||||||
|
.ok_or_else(|| {
|
||||||
|
ParseError::internal_error(name.spanned(token_span))
|
||||||
|
})?;
|
||||||
CommandSignature::Internal(signature.spanned(token_span))
|
CommandSignature::Internal(signature.spanned(token_span))
|
||||||
} else {
|
} else {
|
||||||
CommandSignature::External(token_span)
|
CommandSignature::External(token_span)
|
||||||
|
|
|
@ -26,7 +26,7 @@ pub(crate) async fn run_internal_command(
|
||||||
|
|
||||||
let result = {
|
let result = {
|
||||||
context.run_command(
|
context.run_command(
|
||||||
internal_command,
|
internal_command?,
|
||||||
command.name_tag.clone(),
|
command.name_tag.clone(),
|
||||||
command.args.clone(),
|
command.args.clone(),
|
||||||
&source,
|
&source,
|
||||||
|
|
|
@ -156,6 +156,7 @@ mod tests {
|
||||||
use crate::commands::group_by::group;
|
use crate::commands::group_by::group;
|
||||||
use crate::commands::split_by::split;
|
use crate::commands::split_by::split;
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
|
use nu_errors::ShellError;
|
||||||
use nu_protocol::{UntaggedValue, Value};
|
use nu_protocol::{UntaggedValue, Value};
|
||||||
use nu_source::*;
|
use nu_source::*;
|
||||||
|
|
||||||
|
@ -171,9 +172,9 @@ mod tests {
|
||||||
UntaggedValue::table(list).into_untagged_value()
|
UntaggedValue::table(list).into_untagged_value()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn nu_releases_grouped_by_date() -> Value {
|
fn nu_releases_grouped_by_date() -> Result<Value, ShellError> {
|
||||||
let key = String::from("date").tagged_unknown();
|
let key = String::from("date").tagged_unknown();
|
||||||
group(&key, nu_releases_commiters(), Tag::unknown()).unwrap()
|
group(&key, nu_releases_commiters(), Tag::unknown())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn nu_releases_commiters() -> Vec<Value> {
|
fn nu_releases_commiters() -> Vec<Value> {
|
||||||
|
@ -209,11 +210,11 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn splits_inner_tables_by_key() {
|
fn splits_inner_tables_by_key() -> Result<(), ShellError> {
|
||||||
let for_key = String::from("country").tagged_unknown();
|
let for_key = String::from("country").tagged_unknown();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
split(&for_key, &nu_releases_grouped_by_date(), Tag::unknown()).unwrap(),
|
split(&for_key, &nu_releases_grouped_by_date()?, Tag::unknown())?,
|
||||||
UntaggedValue::row(indexmap! {
|
UntaggedValue::row(indexmap! {
|
||||||
"EC".into() => row(indexmap! {
|
"EC".into() => row(indexmap! {
|
||||||
"August 23-2019".into() => table(&[
|
"August 23-2019".into() => table(&[
|
||||||
|
@ -250,6 +251,8 @@ mod tests {
|
||||||
})
|
})
|
||||||
}).into_untagged_value()
|
}).into_untagged_value()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -39,12 +39,28 @@ pub fn value_to_json_value(v: &Value) -> Result<serde_json::Value, ShellError> {
|
||||||
UntaggedValue::Primitive(Primitive::Date(d)) => serde_json::Value::String(d.to_string()),
|
UntaggedValue::Primitive(Primitive::Date(d)) => serde_json::Value::String(d.to_string()),
|
||||||
UntaggedValue::Primitive(Primitive::EndOfStream) => serde_json::Value::Null,
|
UntaggedValue::Primitive(Primitive::EndOfStream) => serde_json::Value::Null,
|
||||||
UntaggedValue::Primitive(Primitive::BeginningOfStream) => serde_json::Value::Null,
|
UntaggedValue::Primitive(Primitive::BeginningOfStream) => serde_json::Value::Null,
|
||||||
UntaggedValue::Primitive(Primitive::Decimal(f)) => serde_json::Value::Number(
|
UntaggedValue::Primitive(Primitive::Decimal(f)) => {
|
||||||
serde_json::Number::from_f64(
|
if let Some(f) = f.to_f64() {
|
||||||
f.to_f64().expect("TODO: What about really big decimals?"),
|
if let Some(num) = serde_json::Number::from_f64(
|
||||||
)
|
f.to_f64().expect("TODO: What about really big decimals?"),
|
||||||
.unwrap(),
|
) {
|
||||||
),
|
serde_json::Value::Number(num)
|
||||||
|
} else {
|
||||||
|
return Err(ShellError::labeled_error(
|
||||||
|
"Could not convert value to decimal number",
|
||||||
|
"could not convert to decimal",
|
||||||
|
&v.tag,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Err(ShellError::labeled_error(
|
||||||
|
"Could not convert value to decimal number",
|
||||||
|
"could not convert to decimal",
|
||||||
|
&v.tag,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
UntaggedValue::Primitive(Primitive::Int(i)) => {
|
UntaggedValue::Primitive(Primitive::Int(i)) => {
|
||||||
serde_json::Value::Number(serde_json::Number::from(CoerceInto::<i64>::coerce_into(
|
serde_json::Value::Number(serde_json::Number::from(CoerceInto::<i64>::coerce_into(
|
||||||
i.tagged(&v.tag),
|
i.tagged(&v.tag),
|
||||||
|
|
|
@ -17,13 +17,25 @@ pub struct CommandRegistry {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SignatureRegistry for CommandRegistry {
|
impl SignatureRegistry for CommandRegistry {
|
||||||
fn has(&self, name: &str) -> bool {
|
fn has(&self, name: &str) -> Result<bool, ShellError> {
|
||||||
let registry = self.registry.lock().unwrap();
|
if let Ok(registry) = self.registry.lock() {
|
||||||
registry.contains_key(name)
|
Ok(registry.contains_key(name))
|
||||||
|
} else {
|
||||||
|
Err(ShellError::untagged_runtime_error(format!(
|
||||||
|
"Could not load from registry: {}",
|
||||||
|
name
|
||||||
|
)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
fn get(&self, name: &str) -> Option<Signature> {
|
fn get(&self, name: &str) -> Result<Option<Signature>, ShellError> {
|
||||||
let registry = self.registry.lock().unwrap();
|
if let Ok(registry) = self.registry.lock() {
|
||||||
registry.get(name).map(|command| command.signature())
|
Ok(registry.get(name).map(|command| command.signature()))
|
||||||
|
} else {
|
||||||
|
Err(ShellError::untagged_runtime_error(format!(
|
||||||
|
"Could not get from registry: {}",
|
||||||
|
name
|
||||||
|
)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,8 +60,10 @@ impl CommandRegistry {
|
||||||
registry.get(name).cloned()
|
registry.get(name).cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn expect_command(&self, name: &str) -> Arc<Command> {
|
pub(crate) fn expect_command(&self, name: &str) -> Result<Arc<Command>, ShellError> {
|
||||||
self.get_command(name).unwrap()
|
self.get_command(name).ok_or_else(|| {
|
||||||
|
ShellError::untagged_runtime_error(format!("Could not load command: {}", name))
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn has(&self, name: &str) -> bool {
|
pub(crate) fn has(&self, name: &str) -> bool {
|
||||||
|
@ -171,7 +185,7 @@ impl Context {
|
||||||
self.registry.get_command(name)
|
self.registry.get_command(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn expect_command(&self, name: &str) -> Arc<Command> {
|
pub(crate) fn expect_command(&self, name: &str) -> Result<Arc<Command>, ShellError> {
|
||||||
self.registry.expect_command(name)
|
self.registry.expect_command(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -224,25 +224,28 @@ mod tests {
|
||||||
move |(_obj_source, _column_path_tried, _err)| ShellError::unimplemented(reason)
|
move |(_obj_source, _column_path_tried, _err)| ShellError::unimplemented(reason)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn column_path(paths: &[Value]) -> Tagged<ColumnPathValue> {
|
fn column_path(paths: &[Value]) -> Result<Tagged<ColumnPathValue>, ShellError> {
|
||||||
as_column_path(&table(paths)).unwrap()
|
as_column_path(&table(paths))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn gets_matching_field_from_a_row() {
|
fn gets_matching_field_from_a_row() -> Result<(), ShellError> {
|
||||||
let row = UntaggedValue::row(indexmap! {
|
let row = UntaggedValue::row(indexmap! {
|
||||||
"amigos".into() => table(&[string("andres"),string("jonathan"),string("yehuda")])
|
"amigos".into() => table(&[string("andres"),string("jonathan"),string("yehuda")])
|
||||||
})
|
})
|
||||||
.into_untagged_value();
|
.into_untagged_value();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
row.get_data_by_key("amigos".spanned_unknown()).unwrap(),
|
row.get_data_by_key("amigos".spanned_unknown())
|
||||||
|
.ok_or_else(|| ShellError::unexpected("Failure during testing"))?,
|
||||||
table(&[string("andres"), string("jonathan"), string("yehuda")])
|
table(&[string("andres"), string("jonathan"), string("yehuda")])
|
||||||
);
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn gets_matching_field_from_nested_rows_inside_a_row() {
|
fn gets_matching_field_from_nested_rows_inside_a_row() -> Result<(), ShellError> {
|
||||||
let field_path = column_path(&[string("package"), string("version")]);
|
let field_path = column_path(&[string("package"), string("version")]);
|
||||||
|
|
||||||
let (version, tag) = string("0.4.0").into_parts();
|
let (version, tag) = string("0.4.0").into_parts();
|
||||||
|
@ -256,16 +259,19 @@ mod tests {
|
||||||
});
|
});
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
*value
|
*value.into_value(tag).get_data_by_column_path(
|
||||||
.into_value(tag)
|
&field_path?.item,
|
||||||
.get_data_by_column_path(&field_path, Box::new(error_callback("package.version")))
|
Box::new(error_callback("package.version"))
|
||||||
.unwrap(),
|
)?,
|
||||||
version
|
version
|
||||||
)
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn gets_first_matching_field_from_rows_with_same_field_inside_a_table() {
|
fn gets_first_matching_field_from_rows_with_same_field_inside_a_table() -> Result<(), ShellError>
|
||||||
|
{
|
||||||
let field_path = column_path(&[string("package"), string("authors"), string("name")]);
|
let field_path = column_path(&[string("package"), string("authors"), string("name")]);
|
||||||
|
|
||||||
let (_, tag) = string("Andrés N. Robalino").into_parts();
|
let (_, tag) = string("Andrés N. Robalino").into_parts();
|
||||||
|
@ -283,23 +289,22 @@ mod tests {
|
||||||
});
|
});
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
value
|
value.into_value(tag).get_data_by_column_path(
|
||||||
.into_value(tag)
|
&field_path?.item,
|
||||||
.get_data_by_column_path(
|
Box::new(error_callback("package.authors.name"))
|
||||||
&field_path,
|
)?,
|
||||||
Box::new(error_callback("package.authors.name"))
|
|
||||||
)
|
|
||||||
.unwrap(),
|
|
||||||
table(&[
|
table(&[
|
||||||
string("Andrés N. Robalino"),
|
string("Andrés N. Robalino"),
|
||||||
string("Jonathan Turner"),
|
string("Jonathan Turner"),
|
||||||
string("Yehuda Katz")
|
string("Yehuda Katz")
|
||||||
])
|
])
|
||||||
)
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn column_path_that_contains_just_a_number_gets_a_row_from_a_table() {
|
fn column_path_that_contains_just_a_number_gets_a_row_from_a_table() -> Result<(), ShellError> {
|
||||||
let field_path = column_path(&[string("package"), string("authors"), int(0)]);
|
let field_path = column_path(&[string("package"), string("authors"), int(0)]);
|
||||||
|
|
||||||
let (_, tag) = string("Andrés N. Robalino").into_parts();
|
let (_, tag) = string("Andrés N. Robalino").into_parts();
|
||||||
|
@ -317,18 +322,20 @@ mod tests {
|
||||||
});
|
});
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
*value
|
*value.into_value(tag).get_data_by_column_path(
|
||||||
.into_value(tag)
|
&field_path?.item,
|
||||||
.get_data_by_column_path(&field_path, Box::new(error_callback("package.authors.0")))
|
Box::new(error_callback("package.authors.0"))
|
||||||
.unwrap(),
|
)?,
|
||||||
UntaggedValue::row(indexmap! {
|
UntaggedValue::row(indexmap! {
|
||||||
"name".into() => string("Andrés N. Robalino")
|
"name".into() => string("Andrés N. Robalino")
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn column_path_that_contains_just_a_number_gets_a_row_from_a_row() {
|
fn column_path_that_contains_just_a_number_gets_a_row_from_a_row() -> Result<(), ShellError> {
|
||||||
let field_path = column_path(&[string("package"), string("authors"), string("0")]);
|
let field_path = column_path(&[string("package"), string("authors"), string("0")]);
|
||||||
|
|
||||||
let (_, tag) = string("Andrés N. Robalino").into_parts();
|
let (_, tag) = string("Andrés N. Robalino").into_parts();
|
||||||
|
@ -346,21 +353,20 @@ mod tests {
|
||||||
});
|
});
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
*value
|
*value.into_value(tag).get_data_by_column_path(
|
||||||
.into_value(tag)
|
&field_path?.item,
|
||||||
.get_data_by_column_path(
|
Box::new(error_callback("package.authors.\"0\""))
|
||||||
&field_path,
|
)?,
|
||||||
Box::new(error_callback("package.authors.\"0\""))
|
|
||||||
)
|
|
||||||
.unwrap(),
|
|
||||||
UntaggedValue::row(indexmap! {
|
UntaggedValue::row(indexmap! {
|
||||||
"name".into() => string("Andrés N. Robalino")
|
"name".into() => string("Andrés N. Robalino")
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn replaces_matching_field_from_a_row() {
|
fn replaces_matching_field_from_a_row() -> Result<(), ShellError> {
|
||||||
let field_path = column_path(&[string("amigos")]);
|
let field_path = column_path(&[string("amigos")]);
|
||||||
|
|
||||||
let sample = UntaggedValue::row(indexmap! {
|
let sample = UntaggedValue::row(indexmap! {
|
||||||
|
@ -375,14 +381,16 @@ mod tests {
|
||||||
|
|
||||||
let actual = sample
|
let actual = sample
|
||||||
.into_untagged_value()
|
.into_untagged_value()
|
||||||
.replace_data_at_column_path(&field_path, replacement)
|
.replace_data_at_column_path(&field_path?.item, replacement)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(actual, row(indexmap! {"amigos".into() => string("jonas")}));
|
assert_eq!(actual, row(indexmap! {"amigos".into() => string("jonas")}));
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn replaces_matching_field_from_nested_rows_inside_a_row() {
|
fn replaces_matching_field_from_nested_rows_inside_a_row() -> Result<(), ShellError> {
|
||||||
let field_path = column_path(&[
|
let field_path = column_path(&[
|
||||||
string("package"),
|
string("package"),
|
||||||
string("authors"),
|
string("authors"),
|
||||||
|
@ -404,7 +412,7 @@ mod tests {
|
||||||
|
|
||||||
let actual = sample
|
let actual = sample
|
||||||
.into_value(tag.clone())
|
.into_value(tag.clone())
|
||||||
.replace_data_at_column_path(&field_path, replacement.clone())
|
.replace_data_at_column_path(&field_path?.item, replacement.clone())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -417,9 +425,11 @@ mod tests {
|
||||||
"los.3.caballeros".into() => replacement})})})
|
"los.3.caballeros".into() => replacement})})})
|
||||||
.into_value(tag)
|
.into_value(tag)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn replaces_matching_field_from_rows_inside_a_table() {
|
fn replaces_matching_field_from_rows_inside_a_table() -> Result<(), ShellError> {
|
||||||
let field_path = column_path(&[
|
let field_path = column_path(&[
|
||||||
string("shell_policy"),
|
string("shell_policy"),
|
||||||
string("releases"),
|
string("releases"),
|
||||||
|
@ -456,7 +466,7 @@ mod tests {
|
||||||
|
|
||||||
let actual = sample
|
let actual = sample
|
||||||
.into_value(tag.clone())
|
.into_value(tag.clone())
|
||||||
.replace_data_at_column_path(&field_path, replacement.clone())
|
.replace_data_at_column_path(&field_path?.item, replacement.clone())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -481,5 +491,7 @@ mod tests {
|
||||||
})
|
})
|
||||||
}).into_value(&tag)
|
}).into_value(&tag)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue