Skip to content

Commit 511a7e2

Browse files
ericbottardEric Bottard
authored and
Eric Bottard
committed
SHL-170: Allow space-text for values
1 parent 4962d02 commit 511a7e2

File tree

3 files changed

+71
-30
lines changed

3 files changed

+71
-30
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,4 @@ target/
1313
/*.iml
1414
/*.ipr
1515
/*.iws
16+
out

src/main/java/org/springframework/shell/core/SimpleParser.java

Lines changed: 47 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -216,22 +216,14 @@ public ParseResult parse(final String rawInput) {
216216

217217
// Ensure the user specified a value if the value is mandatory or
218218
// key and value must appear in pair
219-
boolean mandatory = !StringUtils.hasText(value) && cliOption.mandatory();
220-
boolean specifiedKey = !StringUtils.hasText(value) && options.containsKey(sourcedFrom);
221-
boolean specifiedKeyWithoutValue = false;
222-
if (specifiedKey) {
223-
value = cliOption.specifiedDefaultValue();
224-
if ("__NULL__".equals(value)) {
225-
specifiedKeyWithoutValue = true;
226-
}
227-
}
228-
if (mandatory || specifiedKeyWithoutValue) {
229-
if ("".equals(cliOption.key()[0])) {
230-
StringBuilder message = new StringBuilder("You should specify a default option ");
231-
if (cliOption.key().length > 1) {
232-
message.append("(otherwise known as option '").append(cliOption.key()[1]).append("') ");
233-
}
234-
message.append("for this command");
219+
boolean mandatory = cliOption.mandatory();
220+
boolean specifiedKey = options.containsKey(sourcedFrom);
221+
boolean specifiedKeyWithoutValue = specifiedKey && "".equals(value);
222+
if (mandatory && (!specifiedKey || specifiedKeyWithoutValue)) {
223+
if (isDefaultOption(cliOption)) {
224+
StringBuilder message = new StringBuilder("You should specify ");
225+
message.append(optionAliases(cliOption));
226+
message.append(" for this command");
235227
LOGGER.warning(message.toString());
236228
}
237229
else {
@@ -241,12 +233,10 @@ public ParseResult parse(final String rawInput) {
241233
}
242234

243235
// Accept a default if the user specified the option, but didn't provide a value
244-
if ("".equals(value)) {
236+
if (specifiedKeyWithoutValue) {
245237
value = cliOption.specifiedDefaultValue();
246-
}
247-
238+
} else if (!specifiedKey) {
248239
// Accept a default if the user didn't specify the option at all
249-
if (value == null) {
250240
value = cliOption.unspecifiedDefaultValue();
251241
}
252242

@@ -336,6 +326,42 @@ private void resetCompletionInvocations() {
336326
successiveCompletionRequests = 1;
337327
}
338328

329+
/**
330+
* Return true if the given option is the 'default' option, that is, one of its key is the empty String.
331+
*/
332+
private boolean isDefaultOption(CliOption option) {
333+
for (String key : option.key()) {
334+
if ("".equals(key)) {
335+
return true;
336+
}
337+
}
338+
return false;
339+
}
340+
341+
/**
342+
* Return a plain string description of the available aliases for a given option.
343+
*/
344+
private CharSequence optionAliases(CliOption option) {
345+
StringBuilder result = new StringBuilder();
346+
if (isDefaultOption(option)) {
347+
result.append("a default option");
348+
}
349+
if (option.key().length > 1) {
350+
result.append(", otherwise known as ");
351+
}
352+
boolean comma = false;
353+
for (String key : option.key()) {
354+
if (!"".equals(key)) {
355+
if (comma) {
356+
result.append(", ");
357+
}
358+
result.append("'").append(key).append("'");
359+
comma = true;
360+
}
361+
}
362+
return result;
363+
}
364+
339365
private void reportTokenizingException(String commandKey, TokenizingException te) {
340366
StringBuilder caret = new StringBuilder();
341367
for (int i = 0; i < te.getOffendingOffset() + commandKey.length() + 1; i++) {
@@ -364,7 +390,7 @@ private void printHintMessage(final Set<CliOption> cliOptions, Map<String, Strin
364390
boolean found = false;
365391
for (String key : keys) {
366392
if (options.containsKey(key)) {
367-
if (!StringUtils.hasText(options.get(key))) {
393+
if (!StringUtils.hasLength(options.get(key))) {
368394
valueBuilder.append(key);
369395
valueBuilder.append("' for this command");
370396
hintForOptions = false;

src/test/java/org/springframework/shell/core/SimpleParserTests.java

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,7 @@
1616

1717
package org.springframework.shell.core;
1818

19-
import static org.hamcrest.Matchers.containsString;
20-
import static org.hamcrest.Matchers.empty;
21-
import static org.hamcrest.Matchers.endsWith;
22-
import static org.hamcrest.Matchers.equalTo;
23-
import static org.hamcrest.Matchers.hasItem;
24-
import static org.hamcrest.Matchers.is;
25-
import static org.hamcrest.Matchers.not;
26-
import static org.hamcrest.Matchers.nullValue;
27-
import static org.hamcrest.Matchers.startsWith;
19+
import static org.hamcrest.Matchers.*;
2820
import static org.junit.Assert.assertThat;
2921

3022
import java.util.ArrayList;
@@ -58,6 +50,28 @@ public class SimpleParserTests {
5850

5951
private ArrayList<Completion> candidates = new ArrayList<Completion>();
6052

53+
@Test
54+
public void testSHL170_ValueMadeOfSpacesOK() {
55+
parser.add(new MyCommands());
56+
parser.add(new StringConverter());
57+
58+
// A value made of space(s) is ok
59+
ParseResult result = parser.parse("bar --option1 ' '");
60+
assertThat(result.getMethod().getName(), equalTo("bar"));
61+
assertThat(result.getArguments(), arrayContaining((Object) " "));
62+
63+
// Ok too with a literal TAB
64+
result = parser.parse("bar --option1 '\t'");
65+
assertThat(result.getMethod().getName(), equalTo("bar"));
66+
assertThat(result.getArguments(), arrayContaining((Object)"\t"));
67+
68+
// Also Ok when Shell itself does the escaping
69+
result = parser.parse("bar --option1 '\\t'");
70+
assertThat(result.getMethod().getName(), equalTo("bar"));
71+
assertThat(result.getArguments(), arrayContaining((Object)"\t"));
72+
73+
}
74+
6175
@Test
6276
public void testSimpleCommandNameCompletion() {
6377
parser.add(new MyCommands());

0 commit comments

Comments
 (0)