ArgumentImpl.java
/*
* Copyright (c) 2016, Stein Eldar Johnsen
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package net.morimekta.terminal.args.impl;
import net.morimekta.terminal.args.ArgException;
import net.morimekta.terminal.args.Argument;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.regex.Pattern;
import static java.util.Objects.requireNonNull;
import static net.morimekta.terminal.args.impl.OptionUtils.requireValidArgumentName;
import static net.morimekta.terminal.args.impl.OptionUtils.requireValidUsage;
/**
* An argument is a non-optioned CLI argument. Instead of having to match the
* option name, it may use a predicate to test the value before applying.
*/
public class ArgumentImpl extends BaseArg implements Argument {
public static BuilderImpl argument(String name,
String usage,
Consumer<String> consumer) {
return new BuilderImpl(
requireValidArgumentName(name),
requireValidUsage(usage),
requireNonNull(consumer, "consumer == null"));
}
public static class BuilderImpl implements Argument.Builder {
private final String name;
private final String usage;
private final Consumer<String> consumer;
private String defaultValue;
private Predicate<String> predicate;
private boolean repeated;
private boolean required;
private boolean hidden;
public BuilderImpl(String name, String usage, Consumer<String> consumer) {
this.name = name;
this.usage = usage;
this.consumer = consumer;
}
@Override
public Argument build() {
return new ArgumentImpl(name, usage, consumer, defaultValue, predicate, repeated, required, hidden);
}
@Override
public BuilderImpl defaultValue(Object defaultValue) {
this.defaultValue = String.valueOf(defaultValue);
return this;
}
@Override
public BuilderImpl when(Predicate<String> predicate) {
requireNonNull(predicate, "predicate == null");
if (this.predicate != null) {
throw new IllegalStateException("Predicate already set for argument '" + name + "'");
}
this.predicate = requireNonNull(predicate, "predicate == null");
return this;
}
@Override
public BuilderImpl when(Pattern pattern) {
requireNonNull(pattern, "pattern == null");
if (this.predicate != null) {
throw new IllegalStateException("Predicate already set for argument '" + name + "'");
}
this.predicate = str -> pattern.matcher(str).matches();
return this;
}
@Override
public BuilderImpl whenNot(Pattern pattern) {
requireNonNull(pattern, "pattern == null");
if (this.predicate != null) {
throw new IllegalStateException("Predicate already set for argument '" + name + "'");
}
this.predicate = str -> !pattern.matcher(str).matches();
return this;
}
@Override
public BuilderImpl repeated() {
this.repeated = true;
return this;
}
@Override
public BuilderImpl required() {
this.required = true;
return this;
}
@Override
public BuilderImpl hidden() {
this.hidden = true;
return this;
}
}
@Override
public String getSingleLineUsage() {
StringBuilder sb = new StringBuilder();
if (!isRequired()) {
sb.append("[");
} else if (isRepeated()) {
sb.append("(");
}
sb.append(getName());
if (isRepeated()) {
sb.append(" ...");
}
if (!isRequired()) {
sb.append("]");
} else if (isRepeated()) {
sb.append(")");
}
return sb.toString();
}
@Override
public String getPrefix() {
return getName();
}
@Override
public void validate() throws ArgException {
if (isRequired() && !applied) {
throw new ArgException("Argument %s is required", getName());
}
}
@Override
public int apply(List<String> args) {
if (applied && !isRepeated()) {
return 0;
}
String cur = args.get(0);
if (!predicate.test(cur)) {
return 0;
}
applied = true;
consumer.accept(cur);
return 1;
}
// --- PRIVATE ---
private final Consumer<String> consumer;
private final Predicate<String> predicate;
private boolean applied;
private ArgumentImpl(String name,
String usage,
Consumer<String> consumer,
String defaultValue,
Predicate<String> predicate,
boolean repeated,
boolean required,
boolean hidden) {
super(name, usage, defaultValue, repeated, required, hidden);
this.consumer = consumer;
this.predicate = predicate == null ? s -> true : predicate;
}
}