Skip to content

Commit bfe802e

Browse files
committed
Add positional argument support to built-in restrictions (#91)
All built-in restrictions should now support positional arguments
1 parent bb680c1 commit bfe802e

File tree

6 files changed

+75
-5
lines changed

6 files changed

+75
-5
lines changed

airline-core/src/main/java/com/github/rvesse/airline/restrictions/common/PartialRestriction.java

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import java.util.TreeSet;
2222

2323
import org.apache.commons.collections4.CollectionUtils;
24+
import org.apache.commons.collections4.IterableUtils;
2425

2526
import com.github.rvesse.airline.help.sections.HelpFormat;
2627
import com.github.rvesse.airline.help.sections.HelpHint;
@@ -43,13 +44,15 @@ public class PartialRestriction extends AbstractCommonRestriction implements Hel
4344
private PartialRestriction(OptionRestriction optionRestriction) {
4445
this.optionRestriction = optionRestriction;
4546
this.argumentsRestriction = optionRestriction instanceof ArgumentsRestriction
46-
? (ArgumentsRestriction) optionRestriction : null;
47+
? (ArgumentsRestriction) optionRestriction
48+
: null;
4749
this.hint = optionRestriction instanceof HelpHint ? (HelpHint) optionRestriction : null;
4850
}
4951

5052
private PartialRestriction(ArgumentsRestriction argumentsRestriction) {
5153
this.optionRestriction = argumentsRestriction instanceof OptionRestriction
52-
? (OptionRestriction) argumentsRestriction : null;
54+
? (OptionRestriction) argumentsRestriction
55+
: null;
5356
this.argumentsRestriction = argumentsRestriction;
5457
this.hint = argumentsRestriction instanceof HelpHint ? (HelpHint) argumentsRestriction : null;
5558
}
@@ -79,8 +82,8 @@ public PartialRestriction(Collection<Integer> indices, ArgumentsRestriction argu
7982
}
8083

8184
private <T> boolean isApplicableToOption(ParseState<T> state, OptionMetadata option) {
82-
int index = CollectionUtils.countMatches(state.getParsedOptions(), new ParsedOptionFinder(option))
83-
% option.getArity();
85+
int index = (int) (IterableUtils.countMatches(state.getParsedOptions(), new ParsedOptionFinder(option))
86+
% option.getArity());
8487
return indices.contains(index);
8588
}
8689

@@ -104,6 +107,9 @@ public <T> void postValidate(ParseState<T> state, OptionMetadata option, Object
104107
this.optionRestriction.postValidate(state, option, value);
105108
}
106109

110+
// NB - Partial restriction make no sense for positional arguments which
111+
// only ever take a single value and thus are not applied
112+
107113
private <T> boolean isApplicableToArgument(ParseState<T> state) {
108114
int index = state.getParsedArguments().size();
109115
return indices.contains(index);

airline-core/src/main/java/com/github/rvesse/airline/restrictions/common/PathRestriction.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import com.github.rvesse.airline.help.sections.HelpHint;
2222
import com.github.rvesse.airline.model.ArgumentsMetadata;
2323
import com.github.rvesse.airline.model.OptionMetadata;
24+
import com.github.rvesse.airline.model.PositionalArgumentMetadata;
2425
import com.github.rvesse.airline.parser.ParseState;
2526
import com.github.rvesse.airline.parser.errors.ParseRestrictionViolatedException;
2627
import com.github.rvesse.airline.restrictions.AbstractCommonRestriction;
@@ -169,6 +170,12 @@ public <T> void preValidate(ParseState<T> state, ArgumentsMetadata arguments, St
169170
this.validate(String.format("Argument '%s'", AbstractCommonRestriction.getArgumentTitle(state, arguments)),
170171
value);
171172
}
173+
174+
@Override
175+
public <T> void preValidate(ParseState<T> state, PositionalArgumentMetadata arguments, String value) {
176+
this.validate(String.format("Positional Argument %d ('%s')", arguments.getZeroBasedPosition(), arguments.getTitle()),
177+
value);
178+
}
172179

173180
@Override
174181
public String getPreamble() {

airline-core/src/main/java/com/github/rvesse/airline/restrictions/common/PatternRestriction.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import com.github.rvesse.airline.help.sections.HelpHint;
2424
import com.github.rvesse.airline.model.ArgumentsMetadata;
2525
import com.github.rvesse.airline.model.OptionMetadata;
26+
import com.github.rvesse.airline.model.PositionalArgumentMetadata;
2627
import com.github.rvesse.airline.parser.ParseState;
2728
import com.github.rvesse.airline.parser.errors.ParseRestrictionViolatedException;
2829
import com.github.rvesse.airline.restrictions.AbstractCommonRestriction;
@@ -69,6 +70,15 @@ public <T> void preValidate(ParseState<T> state, ArgumentsMetadata arguments, St
6970
AbstractCommonRestriction.getArgumentTitle(state, arguments), value, this.pattern.toString(),
7071
StringUtils.isNotBlank(this.description) ? this.description : "");
7172
}
73+
74+
@Override
75+
public <T> void preValidate(ParseState<T> state, PositionalArgumentMetadata arguments, String value) {
76+
if (!this.pattern.matcher(value).find())
77+
throw new ParseRestrictionViolatedException(
78+
"Positional Argument %d ('%s') was given value '%s' which does not match the regular expression '%s'. %s",
79+
arguments.getZeroBasedPosition(), arguments.getTitle(), value, this.pattern.toString(),
80+
StringUtils.isNotBlank(this.description) ? this.description : "");
81+
}
7282

7383
@Override
7484
public String getPreamble() {

airline-core/src/main/java/com/github/rvesse/airline/restrictions/common/PortRestriction.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import com.github.rvesse.airline.help.sections.HelpHint;
2525
import com.github.rvesse.airline.model.ArgumentsMetadata;
2626
import com.github.rvesse.airline.model.OptionMetadata;
27+
import com.github.rvesse.airline.model.PositionalArgumentMetadata;
2728
import com.github.rvesse.airline.parser.ParseState;
2829
import com.github.rvesse.airline.parser.errors.ParseInvalidRestrictionException;
2930
import com.github.rvesse.airline.parser.errors.ParseRestrictionViolatedException;
@@ -65,6 +66,10 @@ protected void invalidOptionPort(OptionMetadata option, Object value) {
6566
protected void invalidArgumentsPort(ArgumentsMetadata arguments, String title, Object value) {
6667
invalidPort(String.format("Argument '%s'", title), value);
6768
}
69+
70+
protected void invalidArgumentsPort(PositionalArgumentMetadata arguments, String title, Object value) {
71+
invalidPort(String.format("Positional argument %d ('%s')", arguments.getZeroBasedPosition(), title), value);
72+
}
6873

6974
protected void invalidPort(String title, Object value) {
7075
throw new ParseRestrictionViolatedException(
@@ -92,6 +97,27 @@ public <T> void postValidate(ParseState<T> state, ArgumentsMetadata arguments, O
9297
arguments.getJavaType());
9398
}
9499
}
100+
101+
@Override
102+
public <T> void postValidate(ParseState<T> state, PositionalArgumentMetadata arguments, Object value) {
103+
if (acceptablePorts.isEmpty())
104+
return;
105+
106+
String title = arguments.getTitle();
107+
if (value instanceof Long) {
108+
if (!isValid(((Long) value).longValue()))
109+
invalidArgumentsPort(arguments, title, value);
110+
} else if (value instanceof Integer) {
111+
if (!isValid(((Integer) value).intValue()))
112+
invalidArgumentsPort(arguments, title, value);
113+
} else if (value instanceof Short) {
114+
if (!isValid(((Short) value).shortValue()))
115+
invalidArgumentsPort(arguments, title, value);
116+
} else {
117+
throw new ParseInvalidRestrictionException("Cannot apply a @Port restriction to an option of type %s",
118+
arguments.getJavaType());
119+
}
120+
}
95121

96122
private boolean isValid(long port) {
97123
if (port < MIN_PORT || port > MAX_PORT)

airline-core/src/main/java/com/github/rvesse/airline/restrictions/common/PositiveNegativeRestriction.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import com.github.rvesse.airline.help.sections.HelpHint;
2020
import com.github.rvesse.airline.model.ArgumentsMetadata;
2121
import com.github.rvesse.airline.model.OptionMetadata;
22+
import com.github.rvesse.airline.model.PositionalArgumentMetadata;
2223
import com.github.rvesse.airline.parser.ParseState;
2324
import com.github.rvesse.airline.parser.errors.ParseRestrictionViolatedException;
2425
import com.github.rvesse.airline.restrictions.AbstractCommonRestriction;
@@ -111,11 +112,20 @@ public <T> void postValidate(ParseState<T> state, OptionMetadata option, Object
111112
@Override
112113
public <T> void postValidate(ParseState<T> state, ArgumentsMetadata arguments, Object value) {
113114
if (!this.isValid(value)) {
114-
throw new ParseRestrictionViolatedException("Option '%s' must have a %s value (%s) but got %s",
115+
throw new ParseRestrictionViolatedException("Argument '%s' must have a %s value (%s) but got %s",
115116
AbstractCommonRestriction.getArgumentTitle(state, arguments), this.type, this.range, value);
116117
}
117118
}
118119

120+
@Override
121+
public <T> void postValidate(ParseState<T> state, PositionalArgumentMetadata arguments, Object value) {
122+
if (!this.isValid(value)) {
123+
throw new ParseRestrictionViolatedException(
124+
"Positional argument %d ('%s') must have a %s value (%s) but got %s",
125+
arguments.getZeroBasedPosition(), arguments.getTitle(), this.type, this.range, value);
126+
}
127+
}
128+
119129
@Override
120130
public String getPreamble() {
121131
return null;

airline-core/src/main/java/com/github/rvesse/airline/restrictions/common/RangeRestriction.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import com.github.rvesse.airline.help.sections.HelpHint;
2222
import com.github.rvesse.airline.model.ArgumentsMetadata;
2323
import com.github.rvesse.airline.model.OptionMetadata;
24+
import com.github.rvesse.airline.model.PositionalArgumentMetadata;
2425
import com.github.rvesse.airline.parser.ParseState;
2526
import com.github.rvesse.airline.parser.errors.ParseInvalidRestrictionException;
2627
import com.github.rvesse.airline.parser.errors.ParseOptionOutOfRangeException;
@@ -83,6 +84,16 @@ public <T> void postValidate(ParseState<T> state, ArgumentsMetadata arguments, O
8384
if (!inRange(value))
8485
throw new ParseOptionOutOfRangeException(getArgumentTitle(state, arguments), value, min, minInclusive, max, maxInclusive);
8586
}
87+
88+
@Override
89+
public <T> void postValidate(ParseState<T> state, PositionalArgumentMetadata arguments, Object value) {
90+
// Not enforced if no range provided
91+
if (this.min == null && this.max == null)
92+
return;
93+
94+
if (!inRange(value))
95+
throw new ParseOptionOutOfRangeException(arguments.getTitle(), value, min, minInclusive, max, maxInclusive);
96+
}
8697

8798
protected boolean inRange(Object value) {
8899
if (this.min != null) {

0 commit comments

Comments
 (0)