From 5e18f99443d070135b77e16a255471f4e9ddd74d Mon Sep 17 00:00:00 2001 From: dgelessus <dgelessus@users.noreply.github.com> Date: Wed, 13 May 2020 18:20:14 +0200 Subject: [PATCH] Move parameter splitting and validation code into separate objects This allows freely combining splitting, repeating and validation behaviors without having to define a new PositionalParameter subclass for each one. --- .../java/de/prob2/jupyter/CommandUtils.java | 4 +- src/main/java/de/prob2/jupyter/Parameter.java | 63 ++++++++- .../de/prob2/jupyter/PositionalParameter.java | 128 ++---------------- 3 files changed, 74 insertions(+), 121 deletions(-) diff --git a/src/main/java/de/prob2/jupyter/CommandUtils.java b/src/main/java/de/prob2/jupyter/CommandUtils.java index 35713d5..4fe551c 100644 --- a/src/main/java/de/prob2/jupyter/CommandUtils.java +++ b/src/main/java/de/prob2/jupyter/CommandUtils.java @@ -108,7 +108,7 @@ public final class CommandUtils { break; } - final Parameter.SplitResult splitSingleArg = param.split(remainingArgs); + final Parameter.SplitResult splitSingleArg = param.getSplitter().split(remainingArgs); splitArgs.add(param, splitSingleArg.getSplitArg()); remainingArgs = splitSingleArg.getRemainingArgString(); @@ -121,7 +121,7 @@ public final class CommandUtils { } private static <T> void validateSplitParameter(final @NotNull ParsedArguments parsed, final @NotNull SplitArguments splitArgs, final @NotNull Parameter<T> param) { - parsed.put(param, param.validate(splitArgs.get(param))); + parsed.put(param, param.getValidator().validate(param, splitArgs.get(param))); } public static @NotNull ParsedArguments validateSplitArgs(final @NotNull Parameters parameters, final SplitResult split) { diff --git a/src/main/java/de/prob2/jupyter/Parameter.java b/src/main/java/de/prob2/jupyter/Parameter.java index f609eb1..ae7c214 100644 --- a/src/main/java/de/prob2/jupyter/Parameter.java +++ b/src/main/java/de/prob2/jupyter/Parameter.java @@ -1,6 +1,7 @@ package de.prob2.jupyter; import java.util.List; +import java.util.Optional; import com.google.common.base.MoreObjects; @@ -27,28 +28,82 @@ public abstract class Parameter<T> { } } + public interface Splitter { + public static final @NotNull Parameter.Splitter REGULAR = argString -> { + final String[] split = CommandUtils.ARG_SPLIT_PATTERN.split(argString, 2); + return new SplitResult(split[0], split.length > 1 ? split[1] : ""); + }; + public static final @NotNull Parameter.Splitter REMAINDER = argString -> new SplitResult(argString, ""); + + public abstract Parameter.SplitResult split(final @NotNull String argString); + } + + public interface Validator<T> { + public static final @NotNull Parameter.Validator<@NotNull String> EXACTLY_ONE = (param, argValues) -> { + if (argValues.isEmpty()) { + throw new UserErrorException("Missing required parameter " + param.getIdentifier()); + } else if (argValues.size() > 1) { + throw new UserErrorException("Non-repeating parameter " + param.getIdentifier() + " cannot appear more than once"); + } + + return argValues.get(0); + }; + public static final @NotNull Parameter.Validator<@NotNull Optional<String>> ZERO_OR_ONE = (param, argValues) -> { + if (argValues.size() > 1) { + throw new UserErrorException("Non-repeating parameter " + param.getIdentifier() + " cannot appear more than once"); + } + + return argValues.stream().findAny(); + }; + public static final @NotNull Parameter.Validator<@NotNull List<@NotNull String>> ONE_OR_MORE = (param, argValues) -> { + if (argValues.isEmpty()) { + throw new UserErrorException("Missing required parameter " + param.getIdentifier()); + } + + return argValues; + }; + public static final @NotNull Parameter.Validator<@NotNull List<@NotNull String>> ZERO_OR_MORE = (param, argValues) -> argValues; + + public abstract T validate(final @NotNull Parameter<T> param, final @NotNull List<@NotNull String> argValues); + } + private final @NotNull String identifier; + private final boolean repeating; + private final @NotNull Parameter.Splitter splitter; + private final @NotNull Parameter.Validator<T> validator; - protected Parameter(final @NotNull String identifier) { + protected Parameter(final @NotNull String identifier, final boolean repeating, final @NotNull Parameter.Splitter splitter, final @NotNull Parameter.Validator<T> validator) { super(); this.identifier = identifier; + this.repeating = repeating; + this.splitter = splitter; + this.validator = validator; } public @NotNull String getIdentifier() { return this.identifier; } - public abstract boolean isRepeating(); + public boolean isRepeating() { + return this.repeating; + } - public abstract Parameter.SplitResult split(final @NotNull String argString); + public @NotNull Parameter.Splitter getSplitter() { + return this.splitter; + } - public abstract T validate(final @NotNull List<@NotNull String> argValues); + public @NotNull Parameter.Validator<T> getValidator() { + return this.validator; + } @Override public String toString() { return MoreObjects.toStringHelper(this) .add("identifier", this.getIdentifier()) + .add("repeating", this.isRepeating()) + .add("splitter", this.getSplitter()) + .add("validator", this.getValidator()) .toString(); } } diff --git a/src/main/java/de/prob2/jupyter/PositionalParameter.java b/src/main/java/de/prob2/jupyter/PositionalParameter.java index f3d448e..f6f927c 100644 --- a/src/main/java/de/prob2/jupyter/PositionalParameter.java +++ b/src/main/java/de/prob2/jupyter/PositionalParameter.java @@ -5,146 +5,44 @@ import java.util.Optional; import org.jetbrains.annotations.NotNull; -public abstract class PositionalParameter<T> extends Parameter<T> { - public abstract static class ExactlyOne extends PositionalParameter<@NotNull String> { - protected ExactlyOne(final @NotNull String identifier) { - super(identifier); - } - - @Override - public boolean isRepeating() { - return false; - } - - @Override - public @NotNull String validate(final @NotNull List<@NotNull String> argValues) { - if (argValues.isEmpty()) { - throw new UserErrorException("Missing required parameter " + this.getIdentifier()); - } else if (argValues.size() > 1) { - throw new AssertionError("Regular (single) required parameter " + this.getIdentifier() + " has more than one value, this should never happen!"); - } - - return argValues.get(0); - } - } - - public abstract static class ZeroOrOne extends PositionalParameter<@NotNull Optional<String>> { - protected ZeroOrOne(final @NotNull String identifier) { - super(identifier); - } - - @Override - public boolean isRepeating() { - return false; - } - - @Override - public @NotNull Optional<String> validate(final @NotNull List<@NotNull String> argValues) { - if (argValues.size() > 1) { - throw new AssertionError("Regular (single) optional parameter " + this.getIdentifier() + " has more than one value, this should never happen!"); - } - - return argValues.stream().findAny(); - } - } - - public static final class RequiredSingle extends PositionalParameter.ExactlyOne { +public class PositionalParameter<T> extends Parameter<T> { + public static final class RequiredSingle extends PositionalParameter<@NotNull String> { public RequiredSingle(final @NotNull String identifier) { - super(identifier); - } - - @Override - public @NotNull Parameter.SplitResult split(final @NotNull String argString) { - return splitOnce(argString); + super(identifier, false, Parameter.Splitter.REGULAR, Parameter.Validator.EXACTLY_ONE); } } - public static final class OptionalSingle extends PositionalParameter.ZeroOrOne { + public static final class OptionalSingle extends PositionalParameter<@NotNull Optional<String>> { public OptionalSingle(final @NotNull String identifier) { - super(identifier); - } - - @Override - public @NotNull Parameter.SplitResult split(final @NotNull String argString) { - return splitOnce(argString); + super(identifier, false, Parameter.Splitter.REGULAR, Parameter.Validator.ZERO_OR_ONE); } } public static final class RequiredMultiple extends PositionalParameter<@NotNull List<@NotNull String>> { public RequiredMultiple(final @NotNull String identifier) { - super(identifier); - } - - @Override - public boolean isRepeating() { - return true; - } - - @Override - public @NotNull Parameter.SplitResult split(final @NotNull String argString) { - return splitOnce(argString); - } - - @Override - public @NotNull List<@NotNull String> validate(final @NotNull List<@NotNull String> argValues) { - if (argValues.isEmpty()) { - throw new UserErrorException("Missing required parameter " + this.getIdentifier()); - } - - return argValues; + super(identifier, true, Parameter.Splitter.REGULAR, Parameter.Validator.ONE_OR_MORE); } } public static final class OptionalMultiple extends PositionalParameter<@NotNull List<@NotNull String>> { public OptionalMultiple(final @NotNull String identifier) { - super(identifier); - } - - @Override - public boolean isRepeating() { - return true; - } - - @Override - public @NotNull Parameter.SplitResult split(final @NotNull String argString) { - return splitOnce(argString); - } - - @Override - public @NotNull List<@NotNull String> validate(final @NotNull List<@NotNull String> argValues) { - return argValues; + super(identifier, true, Parameter.Splitter.REGULAR, Parameter.Validator.ZERO_OR_MORE); } } - public static final class RequiredRemainder extends PositionalParameter.ExactlyOne { + public static final class RequiredRemainder extends PositionalParameter<@NotNull String> { public RequiredRemainder(final @NotNull String identifier) { - super(identifier); - } - - @Override - public @NotNull Parameter.SplitResult split(final @NotNull String argString) { - return new Parameter.SplitResult(argString, ""); + super(identifier, false, Parameter.Splitter.REMAINDER, Parameter.Validator.EXACTLY_ONE); } } - public static final class OptionalRemainder extends PositionalParameter.ZeroOrOne { + public static final class OptionalRemainder extends PositionalParameter<@NotNull Optional<String>> { public OptionalRemainder(final @NotNull String identifier) { - super(identifier); - } - - @Override - public @NotNull Parameter.SplitResult split(final @NotNull String argString) { - return new Parameter.SplitResult(argString, ""); + super(identifier, false, Parameter.Splitter.REMAINDER, Parameter.Validator.ZERO_OR_ONE); } } - protected PositionalParameter(final @NotNull String identifier) { - super(identifier); - } - - @NotNull - static Parameter.SplitResult splitOnce(final @NotNull String argString) { - final String[] split = CommandUtils.ARG_SPLIT_PATTERN.split(argString, 2); - return new Parameter.SplitResult(split[0], split.length > 1 ? split[1] : ""); + public PositionalParameter(final @NotNull String identifier, final boolean repeating, final @NotNull Parameter.Splitter splitter, final @NotNull Parameter.Validator<T> validator) { + super(identifier, repeating, splitter, validator); } } -- GitLab