Skip to content

Commit 2eaba1b

Browse files
authored
update!: change defaults to not empty list but null if not specified (#8)
1 parent ad21c5d commit 2eaba1b

File tree

7 files changed

+275
-187
lines changed

7 files changed

+275
-187
lines changed

src/main/java/com/github/sttk/cliargs/CliArgs.java

+11-2
Original file line numberDiff line numberDiff line change
@@ -105,13 +105,22 @@ public record StoreKeyIsDuplicated(String storeKey) {}
105105

106106
/**
107107
* Is the exception reason which indicates that an option configuration
108-
* contradicts that the option must be an array ({@code .isArray == true})
108+
* contradicts that the option is an array ({@code .isArray == true})
109109
* though it has no option argument ({@code .hasArg == false}).
110110
*
111111
* @param storeKey A store key.
112112
*/
113113
public record ConfigIsArrayButHasNoArg(String storeKey) {}
114114

115+
/**
116+
* Is the exception reason which indicates that an option configuration
117+
* contradicts that the option is not an array ({@code .isArray == false})
118+
* but default value ({@code .defaults} is an array.
119+
*
120+
* @param storeKey A store key.
121+
*/
122+
public record ConfigIsNotArrayButDefaultsIsArray(String storeKey) {}
123+
115124
/**
116125
* Is the exception reason which indicates that an opiton configuration
117126
* contradicts that the option has default value(s)
@@ -219,7 +228,7 @@ public Result parse() {
219228
* of which {@code storeKey} or the first element of {@code names} is
220229
* {@code "*"}.
221230
*
222-
* @param optCfgs An array of {@code OptCfg} objects.
231+
* @param optCfgs An array of {@link OptCfg} objects.
223232
* @return A {@link Result} object that contains the parsed result.
224233
*/
225234
public Result parseWith(OptCfg[] optCfgs) {

src/main/java/com/github/sttk/cliargs/OptCfg.java

+53-26
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
import java.math.BigInteger;
2323
import java.util.List;
2424
import java.util.ArrayList;
25-
2625
import com.github.sttk.exception.ReasonedException;
2726

2827
/**
@@ -145,11 +144,11 @@ public <T> OptCfg(
145144
) {
146145
var init = new Init<T>();
147146
init.storeKey = storeKey;
148-
init.names = unmodifiableList(names);
147+
init.names = names;
149148
init.hasArg = hasArg;
150149
init.isArray = isArray;
151150
init.type = type;
152-
init.defaults = unmodifiableList(defaults);
151+
init.defaults = defaults;
153152
init.desc = desc;
154153
init.argInHelp = argInHelp;
155154
init.converter = converter;
@@ -162,7 +161,8 @@ public <T> OptCfg(
162161
this.hasArg = init.hasArg;
163162
this.isArray = init.isArray;
164163
this.type = init.type;
165-
this.defaults = unmodifiableList(init.defaults);
164+
this.defaults = (init.defaults == null) ? null :
165+
unmodifiableList(init.defaults);
166166
this.desc = init.desc;
167167
this.argInHelp = init.argInHelp;
168168
this.converter = init.converter;
@@ -201,14 +201,14 @@ public <T> OptCfg(NamedParam<T> ...params) {
201201
this.hasArg = init.hasArg;
202202
this.isArray = init.isArray;
203203
this.type = init.type;
204-
this.defaults = unmodifiableList(init.defaults);
204+
this.defaults = (init.defaults == null) ? null :
205+
unmodifiableList(init.defaults);
205206
this.desc = init.desc;
206207
this.argInHelp = init.argInHelp;
207208
this.converter = init.converter;
208209
this.postparser = init.postparser;
209210
}
210211

211-
@SuppressWarnings("unchecked")
212212
private void fillmissing(Init<?> init) {
213213
if (isEmpty(init.storeKey)) {
214214
if (! isEmpty(init.names)) {
@@ -224,38 +224,65 @@ private void fillmissing(Init<?> init) {
224224
}
225225
}
226226

227+
if (init.names == null) {
228+
init.names = emptyList();
229+
}
230+
227231
if (init.type != null && ! init.hasArg) {
228-
init.hasArg = true;
232+
if (init.type != boolean.class && init.type != Boolean.class) {
233+
init.hasArg = true;
234+
}
229235
}
230236

231237
if (init.type != null && init.converter == null) {
232-
var type = init.type;
233-
if (type.equals(int.class) || type.equals(Integer.class)) {
234-
init.converter = (Converter)new IntConverter();
235-
} else if (type.equals(double.class) || type.equals(Double.class)) {
236-
init.converter = (Converter)new DoubleConverter();
237-
} else if (type.equals(long.class) || type.equals(Long.class)) {
238-
init.converter = (Converter)new LongConverter();
239-
} else if (type.equals(BigDecimal.class)) {
240-
init.converter = (Converter)new BigDecimalConverter();
241-
} else if (type.equals(BigInteger.class)) {
242-
init.converter = (Converter)new BigIntConverter();
243-
} else if (type.equals(float.class) || type.equals(Float.class)) {
244-
init.converter = (Converter)new FloatConverter();
245-
} else if (type.equals(short.class) || type.equals(Short.class)) {
246-
init.converter = (Converter)new ShortConverter();
247-
} else if (type.equals(byte.class) || type.equals(Byte.class)) {
248-
init.converter = (Converter)new ByteConverter();
238+
var converter = findConverter(init.type);
239+
if (converter != null) {
240+
setInitConverter(init, converter);
249241
}
250242
}
251243
}
252244

245+
@SuppressWarnings({"rawtypes", "unchecked"})
246+
private void setInitConverter(Init init, Converter<?> converter) {
247+
init.converter = (Converter) converter;
248+
}
249+
250+
@SuppressWarnings("unchecked")
251+
static <T> Converter<T> findConverter(Class<T> type) {
252+
if (type.equals(int.class) || type.equals(Integer.class)) {
253+
var c = (Converter<T>) new IntConverter();
254+
return c;
255+
} else if (type.equals(double.class) || type.equals(Double.class)) {
256+
var c = (Converter<T>) new DoubleConverter();
257+
return c;
258+
} else if (type.equals(long.class) || type.equals(Long.class)) {
259+
var c = (Converter<T>) new LongConverter();
260+
return c;
261+
} else if (type.equals(BigDecimal.class)) {
262+
var c = (Converter<T>) new BigDecimalConverter();
263+
return c;
264+
} else if (type.equals(BigInteger.class)) {
265+
var c = (Converter<T>) new BigIntConverter();
266+
return c;
267+
} else if (type.equals(float.class) || type.equals(Float.class)) {
268+
var c = (Converter<T>) new FloatConverter();
269+
return c;
270+
} else if (type.equals(short.class) || type.equals(Short.class)) {
271+
var c = (Converter<T>) new ShortConverter();
272+
return c;
273+
} else if (type.equals(byte.class) || type.equals(Byte.class)) {
274+
var c = (Converter<T>) new ByteConverter();
275+
return c;
276+
}
277+
return null;
278+
}
279+
253280
private static class Init<T> {
254281
String storeKey;
255-
List<String> names = emptyList();
282+
List<String> names;
256283
boolean hasArg;
257284
boolean isArray;
258-
List<T> defaults = emptyList();
285+
List<T> defaults;
259286
Class<T> type;
260287
String desc;
261288
String argInHelp;

src/main/java/com/github/sttk/cliargs/ParseWith.java

+23-13
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import com.github.sttk.cliargs.CliArgs.StoreKeyIsDuplicated;
1616
import com.github.sttk.cliargs.CliArgs.ConfigIsArrayButHasNoArg;
1717
import com.github.sttk.cliargs.CliArgs.ConfigHasDefaultsButHasNoArg;
18+
import com.github.sttk.cliargs.CliArgs.ConfigIsNotArrayButDefaultsIsArray;
1819
import com.github.sttk.cliargs.CliArgs.OptionNameIsDuplicated;
1920
import com.github.sttk.cliargs.CliArgs.UnconfiguredOption;
2021
import com.github.sttk.cliargs.CliArgs.OptionTakesNoArg;
@@ -68,12 +69,21 @@ static Result parse(OptCfg[] optCfgs, String cmdName, String ...cliArgs) {
6869
var cmd = new Cmd(cmdName, emptyList(), emptyMap());
6970
return new Result(cmd, optCfgs, exc);
7071
}
71-
if (! isEmpty(cfg.defaults)) {
72+
if (cfg.defaults != null) {
7273
var reason = new ConfigHasDefaultsButHasNoArg(storeKey);
7374
var exc = new ReasonedException(reason);
7475
var cmd = new Cmd(cmdName, emptyList(), emptyMap());
7576
return new Result(cmd, optCfgs, exc);
7677
}
78+
} else {
79+
if (! cfg.isArray && cfg.defaults != null) {
80+
if (cfg.defaults.isEmpty() || cfg.defaults.size() > 1) {
81+
var reason = new ConfigIsNotArrayButDefaultsIsArray(cfg.storeKey);
82+
var exc = new ReasonedException(reason);
83+
var cmd = new Cmd(cmdName, emptyList(), emptyMap());
84+
return new Result(cmd, optCfgs, exc);
85+
}
86+
}
7787
}
7888

7989
for (var nm : cfg.names) {
@@ -152,17 +162,17 @@ static Result parse(OptCfg[] optCfgs, String cmdName, String ...cliArgs) {
152162
list = new ArrayList<>();
153163
opts.put(storeKey, list);
154164
}
155-
if (cfg.converter != null) {
156-
try {
157-
list.add(cfg.converter.convert(arg, name, storeKey));
158-
} catch (ReasonedException e) {
159-
throw e;
160-
} catch (Exception e) {
161-
var reason = new FailToConvertOptionArg(arg, name, storeKey);
162-
throw new ReasonedException(reason, e);
163-
}
164-
} else {
165-
if (arg != null) {
165+
if (cfg.hasArg) {
166+
if (cfg.converter != null) {
167+
try {
168+
list.add(cfg.converter.convert(arg, name, storeKey));
169+
} catch (ReasonedException e) {
170+
throw e;
171+
} catch (Exception e) {
172+
var reason = new FailToConvertOptionArg(arg, name, storeKey);
173+
throw new ReasonedException(reason, e);
174+
}
175+
} else {
166176
list.add(arg);
167177
}
168178
}
@@ -179,7 +189,7 @@ static Result parse(OptCfg[] optCfgs, String cmdName, String ...cliArgs) {
179189
@SuppressWarnings("unchecked")
180190
var list = (List<Object>)opts.get(cfg.storeKey);
181191

182-
if (! isEmpty(cfg.defaults)) {
192+
if (cfg.defaults != null) {
183193
if (list == null) {
184194
list = new ArrayList<>();
185195
opts.put(cfg.storeKey, list);

src/test/java/com/github/sttk/cliargs/CmdTest.java

+14-24
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,9 @@ void testConstructor_nameAndArgsAndOpts() {
2525
assertThat(cmd.getName()).isEqualTo("foo");
2626
assertThat(cmd.getArgs()).containsExactly("a0", "a1", "a2");
2727

28-
@SuppressWarnings("unchecked")
29-
var o0 = (List<Integer>) cmd.getOptArgs("o0");
30-
@SuppressWarnings("unchecked")
31-
var o1 = (List<?>) cmd.getOptArgs("o1");
32-
@SuppressWarnings("unchecked")
33-
var o2 = (List<?>) cmd.getOptArgs("o2");
28+
List<Integer> o0 = cmd.getOptArgs("o0");
29+
List<?> o1 = cmd.getOptArgs("o1");
30+
List<?> o2 = cmd.getOptArgs("o2");
3431
assertThat(o0).containsExactly(123, 456);
3532
assertThat(o1).isEmpty();
3633
assertThat(o2).isEmpty();
@@ -60,12 +57,9 @@ void testGetOptArg() {
6057

6158
var cmd = new Cmd("foo", args, opts);
6259

63-
@SuppressWarnings("unchecked")
64-
var o0 = (Integer) cmd.getOptArg("o0");
65-
@SuppressWarnings("unchecked")
66-
var o1 = (Integer) cmd.getOptArg("o1");
67-
@SuppressWarnings("unchecked")
68-
var o2 = (Integer) cmd.getOptArg("o2");
60+
Integer o0 = cmd.getOptArg("o0");
61+
Integer o1 = cmd.getOptArg("o1");
62+
Integer o2 = cmd.getOptArg("o2");
6963
assertThat(o0).isEqualTo(123);
7064
assertThat(o1).isNull();
7165
assertThat(o2).isNull();
@@ -81,18 +75,16 @@ void testGetOptArgs_returnedListIsUnmodifiable() {
8175

8276
var cmd = new Cmd("foo", args, opts);
8377

84-
@SuppressWarnings("unchecked")
85-
var o0 = (List<Integer>) cmd.getOptArgs("o0");
86-
@SuppressWarnings("unchecked")
87-
var o1 = (List<String>) cmd.getOptArgs("o1");
88-
@SuppressWarnings("unchecked")
89-
var o2 = (List<Object>) cmd.getOptArgs("o2");
78+
List<Integer> o0 = cmd.getOptArgs("o0");
79+
List<String> o1 = cmd.getOptArgs("o1");
80+
List<Object> o2 = cmd.getOptArgs("o2");
9081
assertThat(o0).containsExactly(123, 456);
9182
assertThat(o1).isEmpty();
9283
assertThat(o2).isEmpty();
9384

9485
try {
9586
o0.add(789);
87+
fail();
9688
} catch (UnsupportedOperationException e) {}
9789
}
9890

@@ -106,19 +98,17 @@ void testGetArgs_returnedListIsUnmodifiable() {
10698

10799
var cmd = new Cmd("foo", args, opts);
108100

109-
@SuppressWarnings("unchecked")
110-
var o0 = (List<Integer>) cmd.getOptArgs("o0");
111-
@SuppressWarnings("unchecked")
112-
var o1 = (List<String>) cmd.getOptArgs("o1");
113-
@SuppressWarnings("unchecked")
114-
var o2 = (List<Object>) cmd.getOptArgs("o2");
101+
List<Integer> o0 = cmd.getOptArgs("o0");
102+
List<String> o1 = cmd.getOptArgs("o1");
103+
List<Object> o2 = cmd.getOptArgs("o2");
115104
assertThat(o0).containsExactly(123, 456);
116105
assertThat(o1).isEmpty();
117106
assertThat(o2).isEmpty();
118107

119108
var a = cmd.getArgs();
120109
try {
121110
a.add("xxx");
111+
fail();
122112
} catch (UnsupportedOperationException e) {}
123113
}
124114
}

0 commit comments

Comments
 (0)