Use args structs to better extract multiple arguments

This commit is contained in:
Odin Dutton 2019-08-20 13:15:05 +10:00
parent 9951691023
commit 31790a9906
4 changed files with 55 additions and 57 deletions

View File

@ -4,6 +4,11 @@ use crate::errors::ShellError;
use crate::object::base::select_fields; use crate::object::base::select_fields;
use crate::prelude::*; use crate::prelude::*;
#[derive(Deserialize)]
struct PickArgs {
rest: Vec<Tagged<String>>,
}
pub struct Pick; pub struct Pick;
impl WholeStreamCommand for Pick { impl WholeStreamCommand for Pick {
@ -12,7 +17,7 @@ impl WholeStreamCommand for Pick {
args: CommandArgs, args: CommandArgs,
registry: &CommandRegistry, registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> { ) -> Result<OutputStream, ShellError> {
pick(args, registry) args.process(registry, pick)?.run()
} }
fn name(&self) -> &str { fn name(&self) -> &str {
@ -20,22 +25,15 @@ impl WholeStreamCommand for Pick {
} }
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
Signature::build("pick").required("fields", SyntaxType::Any) Signature::build("pick").rest()
} }
} }
fn pick(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> { fn pick(
let args = args.evaluate_once(registry)?; PickArgs { rest: fields }: PickArgs,
let (input, args) = args.parts(); RunnableContext { input, .. }: RunnableContext,
) -> Result<OutputStream, ShellError> {
let fields: Result<Vec<String>, _> = args let fields: Vec<_> = fields.iter().map(|f| f.item.clone()).collect();
.positional
.iter()
.flatten()
.map(|a| a.as_string())
.collect();
let fields = fields?;
let objects = input let objects = input
.values .values

View File

@ -3,6 +3,11 @@ use crate::errors::ShellError;
use crate::object::base::reject_fields; use crate::object::base::reject_fields;
use crate::prelude::*; use crate::prelude::*;
#[derive(Deserialize)]
pub struct RejectArgs {
rest: Vec<Tagged<String>>,
}
pub struct Reject; pub struct Reject;
impl WholeStreamCommand for Reject { impl WholeStreamCommand for Reject {
@ -11,7 +16,7 @@ impl WholeStreamCommand for Reject {
args: CommandArgs, args: CommandArgs,
registry: &CommandRegistry, registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> { ) -> Result<OutputStream, ShellError> {
reject(args, registry) args.process(registry, reject)?.run()
} }
fn name(&self) -> &str { fn name(&self) -> &str {
@ -19,22 +24,15 @@ impl WholeStreamCommand for Reject {
} }
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
Signature::build("reject").required("fields", SyntaxType::Any) Signature::build("reject").rest()
} }
} }
fn reject(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> { fn reject(
let args = args.evaluate_once(registry)?; RejectArgs { rest: fields }: RejectArgs,
let (input, args) = args.parts(); RunnableContext { input, .. }: RunnableContext,
) -> Result<OutputStream, ShellError> {
let fields: Result<Vec<String>, _> = args let fields: Vec<_> = fields.iter().map(|f| f.item.clone()).collect();
.positional
.iter()
.flatten()
.map(|a| a.as_string())
.collect();
let fields = fields?;
let stream = input let stream = input
.values .values

View File

@ -4,6 +4,11 @@ use crate::object::{Primitive, TaggedDictBuilder, Value};
use crate::prelude::*; use crate::prelude::*;
use log::trace; use log::trace;
#[derive(Deserialize)]
struct SplitColumnArgs {
rest: Vec<Tagged<String>>,
}
pub struct SplitColumn; pub struct SplitColumn;
impl WholeStreamCommand for SplitColumn { impl WholeStreamCommand for SplitColumn {
@ -12,7 +17,7 @@ impl WholeStreamCommand for SplitColumn {
args: CommandArgs, args: CommandArgs,
registry: &CommandRegistry, registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> { ) -> Result<OutputStream, ShellError> {
split_column(args, registry) args.process(registry, split_column)?.run()
} }
fn name(&self) -> &str { fn name(&self) -> &str {
@ -20,26 +25,25 @@ impl WholeStreamCommand for SplitColumn {
} }
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
// TODO: Signature?
// TODO: Improve error. Old error had extra info: // TODO: Improve error. Old error had extra info:
// //
// needs parameter (e.g. split-column ",") // needs parameter (e.g. split-column ",")
Signature::build("split-column").required("delimeter", SyntaxType::Any) Signature::build("split-column").rest()
} }
} }
fn split_column(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> { fn split_column(
let args = args.evaluate_once(registry)?; SplitColumnArgs { rest: positional }: SplitColumnArgs,
let span = args.name_span(); RunnableContext { input, name, .. }: RunnableContext,
let (input, args) = args.parts(); ) -> Result<OutputStream, ShellError> {
let positional: Vec<_> = args.positional.iter().flatten().cloned().collect();
Ok(input Ok(input
.values .values
.map(move |v| match v.item { .map(move |v| match v.item {
Value::Primitive(Primitive::String(ref s)) => { Value::Primitive(Primitive::String(ref s)) => {
let splitter = positional[0].as_string().unwrap().replace("\\n", "\n"); let positional: Vec<_> = positional.iter().map(|f| f.item.clone()).collect();
// TODO: Require at least 1 positional argument.
let splitter = positional[0].replace("\\n", "\n");
trace!("splitting with {:?}", splitter); trace!("splitting with {:?}", splitter);
let split_result: Vec<_> = s.split(&splitter).filter(|s| s.trim() != "").collect(); let split_result: Vec<_> = s.split(&splitter).filter(|s| s.trim() != "").collect();
@ -61,16 +65,13 @@ fn split_column(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputS
} else if split_result.len() == (positional.len() - 1) { } else if split_result.len() == (positional.len() - 1) {
let mut dict = TaggedDictBuilder::new(v.tag()); let mut dict = TaggedDictBuilder::new(v.tag());
for (&k, v) in split_result.iter().zip(positional.iter().skip(1)) { for (&k, v) in split_result.iter().zip(positional.iter().skip(1)) {
dict.insert( dict.insert(v, Value::Primitive(Primitive::String(k.into())));
v.as_string().unwrap(),
Value::Primitive(Primitive::String(k.into())),
);
} }
ReturnSuccess::value(dict.into_tagged_value()) ReturnSuccess::value(dict.into_tagged_value())
} else { } else {
let mut dict = TaggedDictBuilder::new(v.tag()); let mut dict = TaggedDictBuilder::new(v.tag());
for k in positional.iter().skip(1) { for k in positional.iter().skip(1) {
dict.insert(k.as_string().unwrap().trim(), Primitive::String("".into())); dict.insert(k.trim(), Primitive::String("".into()));
} }
ReturnSuccess::value(dict.into_tagged_value()) ReturnSuccess::value(dict.into_tagged_value())
} }
@ -78,7 +79,7 @@ fn split_column(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputS
_ => Err(ShellError::labeled_error_with_secondary( _ => Err(ShellError::labeled_error_with_secondary(
"Expected a string from pipeline", "Expected a string from pipeline",
"requires string input", "requires string input",
span, name,
"value originates from here", "value originates from here",
v.span(), v.span(),
)), )),

View File

@ -4,6 +4,11 @@ use crate::object::{Primitive, Value};
use crate::prelude::*; use crate::prelude::*;
use log::trace; use log::trace;
#[derive(Deserialize)]
struct SplitRowArgs {
rest: Vec<Tagged<String>>,
}
pub struct SplitRow; pub struct SplitRow;
impl WholeStreamCommand for SplitRow { impl WholeStreamCommand for SplitRow {
@ -12,7 +17,7 @@ impl WholeStreamCommand for SplitRow {
args: CommandArgs, args: CommandArgs,
registry: &CommandRegistry, registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> { ) -> Result<OutputStream, ShellError> {
split_row(args, registry) args.process(registry, split_row)?.run()
} }
fn name(&self) -> &str { fn name(&self) -> &str {
@ -20,26 +25,22 @@ impl WholeStreamCommand for SplitRow {
} }
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
// TODO: Signature?
// TODO: Improve error. Old error had extra info: // TODO: Improve error. Old error had extra info:
// //
// needs parameter (e.g. split-row ",") // needs parameter (e.g. split-row ",")
Signature::build("split-row").required("delimeter", SyntaxType::Any) Signature::build("split-row").rest()
} }
} }
fn split_row(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> { fn split_row(
let args = args.evaluate_once(registry)?; SplitRowArgs { rest: positional }: SplitRowArgs,
let span = args.name_span(); RunnableContext { input, name, .. }: RunnableContext,
let (input, args) = args.parts(); ) -> Result<OutputStream, ShellError> {
let positional: Vec<Tagged<Value>> = args.positional.iter().flatten().cloned().collect();
let stream = input let stream = input
.values .values
.map(move |v| match v.item { .map(move |v| match v.item {
Value::Primitive(Primitive::String(ref s)) => { Value::Primitive(Primitive::String(ref s)) => {
let splitter = positional[0].as_string().unwrap().replace("\\n", "\n"); let splitter = positional[0].item.replace("\\n", "\n");
trace!("splitting with {:?}", splitter); trace!("splitting with {:?}", splitter);
let split_result: Vec<_> = s.split(&splitter).filter(|s| s.trim() != "").collect(); let split_result: Vec<_> = s.split(&splitter).filter(|s| s.trim() != "").collect();
@ -58,7 +59,7 @@ fn split_row(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStre
result.push_back(Err(ShellError::labeled_error_with_secondary( result.push_back(Err(ShellError::labeled_error_with_secondary(
"Expected a string from pipeline", "Expected a string from pipeline",
"requires string input", "requires string input",
span, name,
"value originates from here", "value originates from here",
v.span(), v.span(),
))); )));