nu_command/strings/str_/case/
upcase.rs

1use nu_engine::command_prelude::*;
2
3#[derive(Clone)]
4pub struct StrUpcase;
5
6impl Command for StrUpcase {
7    fn name(&self) -> &str {
8        "str upcase"
9    }
10
11    fn signature(&self) -> Signature {
12        Signature::build("str upcase")
13            .input_output_types(vec![
14                (Type::String, Type::String),
15                (
16                    Type::List(Box::new(Type::String)),
17                    Type::List(Box::new(Type::String)),
18                ),
19                (Type::table(), Type::table()),
20                (Type::record(), Type::record()),
21            ])
22            .allow_variants_without_examples(true)
23            .rest(
24                "rest",
25                SyntaxShape::CellPath,
26                "For a data structure input, convert strings at the given cell paths.",
27            )
28            .category(Category::Strings)
29    }
30
31    fn description(&self) -> &str {
32        "Make text uppercase."
33    }
34
35    fn search_terms(&self) -> Vec<&str> {
36        vec!["uppercase", "upper case"]
37    }
38
39    fn is_const(&self) -> bool {
40        true
41    }
42
43    fn run(
44        &self,
45        engine_state: &EngineState,
46        stack: &mut Stack,
47        call: &Call,
48        input: PipelineData,
49    ) -> Result<PipelineData, ShellError> {
50        let column_paths: Vec<CellPath> = call.rest(engine_state, stack, 0)?;
51        operate(engine_state, call, input, column_paths)
52    }
53
54    fn run_const(
55        &self,
56        working_set: &StateWorkingSet,
57        call: &Call,
58        input: PipelineData,
59    ) -> Result<PipelineData, ShellError> {
60        let column_paths: Vec<CellPath> = call.rest_const(working_set, 0)?;
61        operate(working_set.permanent(), call, input, column_paths)
62    }
63
64    fn examples(&self) -> Vec<Example<'_>> {
65        vec![Example {
66            description: "Upcase contents",
67            example: "'nu' | str upcase",
68            result: Some(Value::test_string("NU")),
69        }]
70    }
71}
72
73fn operate(
74    engine_state: &EngineState,
75    call: &Call,
76    input: PipelineData,
77    column_paths: Vec<CellPath>,
78) -> Result<PipelineData, ShellError> {
79    let head = call.head;
80    input.map(
81        move |v| {
82            if column_paths.is_empty() {
83                action(&v, head)
84            } else {
85                let mut ret = v;
86                for path in &column_paths {
87                    let r =
88                        ret.update_cell_path(&path.members, Box::new(move |old| action(old, head)));
89                    if let Err(error) = r {
90                        return Value::error(error, head);
91                    }
92                }
93                ret
94            }
95        },
96        engine_state.signals(),
97    )
98}
99
100fn action(input: &Value, head: Span) -> Value {
101    match input {
102        Value::String { val: s, .. } => Value::string(s.to_uppercase(), head),
103        Value::Error { .. } => input.clone(),
104        _ => Value::error(
105            ShellError::OnlySupportsThisInputType {
106                exp_input_type: "string".into(),
107                wrong_type: input.get_type().to_string(),
108                dst_span: head,
109                src_span: input.span(),
110            },
111            head,
112        ),
113    }
114}
115
116#[cfg(test)]
117mod tests {
118    use super::*;
119    use super::{StrUpcase, action};
120
121    #[test]
122    fn test_examples() {
123        use crate::test_examples;
124
125        test_examples(StrUpcase {})
126    }
127
128    #[test]
129    fn upcases() {
130        let word = Value::test_string("andres");
131
132        let actual = action(&word, Span::test_data());
133        let expected = Value::test_string("ANDRES");
134        assert_eq!(actual, expected);
135    }
136}