Yet more ununwraps (#1150)

This commit is contained in:
Jonathan Turner 2020-01-02 20:07:17 +13:00 committed by GitHub
parent 5e31851070
commit 3e3cb15f3d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 135 additions and 76 deletions

View file

@ -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())
} }
} }

View file

@ -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)

View file

@ -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,

View file

@ -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]

View file

@ -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),

View file

@ -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)
} }

View file

@ -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(())
} }
} }