Repository: nushell/engine-q
Pull request #311 (2021-11-09 01:35:21)

Add `str collect`


Patch:
diff --git a/crates/nu-command/src/default_context.rs b/crates/nu-command/src/default_context.rs
index 9004576..2d65bb5 100644
--- a/crates/nu-command/src/default_context.rs
+++ b/crates/nu-command/src/default_context.rs
@@ -25,7 +25,6 @@ pub fn create_default_context() -> EngineState {
             Alias,
             Benchmark,
             BuildString,
-            CamelCase,
             Cd,
             Collect,
             Cp,
@@ -49,7 +48,6 @@ pub fn create_default_context() -> EngineState {
             FromJson,
             Get,
             Griddle,
-            KebabCase,
             Help,
             Hide,
             If,
@@ -83,7 +81,6 @@ pub fn create_default_context() -> EngineState {
             Mkdir,
             Module,
             Mv,
-            PascalCase,
             ParEach,
             Ps,
             Range,
@@ -92,12 +89,17 @@ pub fn create_default_context() -> EngineState {
             Select,
             Shuffle,
             Size,
-            ScreamingSnakeCase,
-            SnakeCase,
             Split,
             SplitChars,
             SplitColumn,
             SplitRow,
+            Str,
+            StrCamelCase,
+            StrCollect,
+            StrKebabCase,
+            StrPascalCase,
+            StrScreamingSnakeCase,
+            StrSnakeCase,
             Sys,
             Table,
             To,
diff --git a/crates/nu-command/src/strings/str_/case/command.rs b/crates/nu-command/src/strings/str_/case/command.rs
index 80714cb..40c038c 100644
--- a/crates/nu-command/src/strings/str_/case/command.rs
+++ b/crates/nu-command/src/strings/str_/case/command.rs
@@ -6,9 +6,9 @@ use nu_protocol::{
 };
 
 #[derive(Clone)]
-pub struct Case;
+pub struct Str;
 
-impl Command for Case {
+impl Command for Str {
     fn name(&self) -> &str {
         "str"
     }
@@ -18,7 +18,7 @@ impl Command for Case {
     }
 
     fn usage(&self) -> &str {
-        "Converts strings into different kind of cases: camel, kebab, pascal, snake, and screaming snake."
+        "Various commands for working with string data."
     }
 
     fn run(
@@ -29,7 +29,7 @@ impl Command for Case {
         _input: PipelineData,
     ) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
         Ok(Value::String {
-            val: get_full_help(&Case.signature(), &Case.examples(), engine_state),
+            val: get_full_help(&Str.signature(), &Str.examples(), engine_state),
             span: call.head,
         }
         .into_pipeline_data())
@@ -44,6 +44,6 @@ mod test {
     fn test_examples() {
         use crate::test_examples;
 
-        test_examples(Case {})
+        test_examples(Str {})
     }
 }
diff --git a/crates/nu-command/src/strings/str_/case/mod.rs b/crates/nu-command/src/strings/str_/case/mod.rs
index 129674f..0d26d6c 100644
--- a/crates/nu-command/src/strings/str_/case/mod.rs
+++ b/crates/nu-command/src/strings/str_/case/mod.rs
@@ -5,12 +5,12 @@ pub mod pascal_case;
 pub mod screaming_snake_case;
 pub mod snake_case;
 
-pub use camel_case::SubCommand as CamelCase;
-pub use command::Case;
-pub use kebab_case::SubCommand as KebabCase;
-pub use pascal_case::SubCommand as PascalCase;
-pub use screaming_snake_case::SubCommand as ScreamingSnakeCase;
-pub use snake_case::SubCommand as SnakeCase;
+pub use camel_case::SubCommand as StrCamelCase;
+pub use command::Str;
+pub use kebab_case::SubCommand as StrKebabCase;
+pub use pascal_case::SubCommand as StrPascalCase;
+pub use screaming_snake_case::SubCommand as StrScreamingSnakeCase;
+pub use snake_case::SubCommand as StrSnakeCase;
 
 use nu_engine::CallExt;
 
diff --git a/crates/nu-command/src/strings/str_/collect.rs b/crates/nu-command/src/strings/str_/collect.rs
new file mode 100644
index 0000000..156c49f
--- /dev/null
+++ b/crates/nu-command/src/strings/str_/collect.rs
@@ -0,0 +1,95 @@
+use nu_engine::CallExt;
+use nu_protocol::ast::Call;
+use nu_protocol::engine::{Command, EngineState, Stack};
+use nu_protocol::{
+    Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, SyntaxShape, Value,
+};
+
+#[derive(Clone)]
+pub struct StrCollect;
+
+impl Command for StrCollect {
+    fn name(&self) -> &str {
+        "str collect"
+    }
+
+    fn signature(&self) -> Signature {
+        Signature::build("str collect").optional(
+            "separator",
+            SyntaxShape::String,
+            "optional separator to use when creating string",
+        )
+    }
+
+    fn usage(&self) -> &str {
+        "creates a string from the input, optionally using a separator"
+    }
+
+    fn run(
+        &self,
+        engine_state: &EngineState,
+        stack: &mut Stack,
+        call: &Call,
+        input: PipelineData,
+    ) -> Result<PipelineData, ShellError> {
+        let separator: Option<String> = call.opt(engine_state, stack, 0)?;
+
+        #[allow(clippy::needless_collect)]
+        let strings: Vec<Result<String, ShellError>> =
+            input.into_iter().map(|value| value.as_string()).collect();
+        let strings: Result<Vec<_>, _> = strings.into_iter().collect::<Result<_, _>>();
+
+        match strings {
+            Ok(strings) => {
+                let output = if let Some(separator) = separator {
+                    strings.join(&separator)
+                } else {
+                    strings.join("")
+                };
+
+                Ok(Value::String {
+                    val: output,
+                    span: call.head,
+                }
+                .into_pipeline_data())
+            }
+            _ => Err(ShellError::CantConvert(
+                "string".into(),
+                "non-string input".into(),
+                call.head,
+            )),
+        }
+    }
+
+    fn examples(&self) -> Vec<Example> {
+        vec![
+            Example {
+                description: "Create a string from input",
+                example: "['nu', 'shell'] | str collect",
+                result: Some(Value::String {
+                    val: "nushell".to_string(),
+                    span: Span::unknown(),
+                }),
+            },
+            Example {
+                description: "Create a string from input with a separator",
+                example: "['nu', 'shell'] | str collect '-'",
+                result: Some(Value::String {
+                    val: "nu-shell".to_string(),
+                    span: Span::unknown(),
+                }),
+            },
+        ]
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    #[test]
+    fn test_examples() {
+        use crate::test_examples;
+
+        test_examples(StrCollect {})
+    }
+}
diff --git a/crates/nu-command/src/strings/str_/mod.rs b/crates/nu-command/src/strings/str_/mod.rs
index a8f9c53..ee1f107 100644
--- a/crates/nu-command/src/strings/str_/mod.rs
+++ b/crates/nu-command/src/strings/str_/mod.rs
@@ -1,3 +1,5 @@
 mod case;
+mod collect;
 
 pub use case::*;
+pub use collect::*;


Test patch:
diff --git a/crates/nu-command/src/example_test.rs b/crates/nu-command/src/example_test.rs
index d11ada8..7e1f390 100644
--- a/crates/nu-command/src/example_test.rs
+++ b/crates/nu-command/src/example_test.rs
@@ -7,7 +7,7 @@ use nu_protocol::{
 
 use crate::To;
 
-use super::{Case, Date, From, Into, Math, Split};
+use super::{Date, From, Into, Math, Split, Str};
 
 pub fn test_examples(cmd: impl Command + 'static) {
     let examples = cmd.examples();
@@ -17,7 +17,7 @@ pub fn test_examples(cmd: impl Command + 'static) {
         // Base functions that are needed for testing
         // Try to keep this working set small to keep tests running as fast as possible
         let mut working_set = StateWorkingSet::new(&*engine_state);
-        working_set.add_decl(Box::new(Case));
+        working_set.add_decl(Box::new(Str));
         working_set.add_decl(Box::new(From));
         working_set.add_decl(Box::new(To));
         working_set.add_decl(Box::new(Into));