All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.rinde.rinsim.cli.Option Maven / Gradle / Ivy

There is a newer version: 4.4.6
Show newest version
/*
 * Copyright (C) 2011-2015 Rinde van Lon, iMinds-DistriNet, KU Leuven
 *
 * Licensed 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 com.github.rinde.rinsim.cli;

import static com.google.common.base.Preconditions.checkArgument;

import com.google.common.base.Joiner;
import com.google.common.base.Optional;

/**
 * Represents an option in a command-line interface.
 * @author Rinde van Lon
 */
public abstract class Option {

  /**
   * This is the regular expression to which all option names must conform to:
   * [a-zA-Z][a-zA-Z\\-\\.]*.
   */
  public static final String NAME_REGEX = "[a-zA-Z][a-zA-Z\\-\\.]*";

  /**
   * The short option prefix: '-'.
   */
  public static final String SHORT_PREFIX = "-";

  /**
   * The long option prefix: '--'.
   */
  public static final String LONG_PREFIX = "--";

  final String shortName;
  final Optional longName;
  final String description;
  final boolean isArgOptional;
  final boolean isHelpOption;

  Option(Builder b, boolean help) {
    shortName = b.shortName;
    longName = b.longName;
    description = b.description;
    isArgOptional = b.isArgOptional;
    isHelpOption = help;
  }

  /**
   * @return The short name of this option.
   */
  public String getShortName() {
    return shortName;
  }

  /**
   * @return An {@link Optional} containing the long name of this option or
   *         {@link Optional#absent()} if this option has no long name.
   */
  public Optional getLongName() {
    return longName;
  }

  /**
   * @return An {@link Optional} containing the {@link ArgumentParser} of this
   *         option or {@link Optional#absent()} if this option doesn't require
   *         an argument.
   */
  public Optional> getArgument() {
    return Optional.absent();
  }

  /**
   * @return The description of this option, displayed in the help menu.
   */
  public String getDescription() {
    return description;
  }

  /**
   * @return true if this option has an argument and it is
   *         optional, false otherwise.
   */
  public boolean isArgOptional() {
    return isArgOptional;
  }

  @Override
  public String toString() {
    if (longName.isPresent()) {
      return Joiner.on("").join(SHORT_PREFIX, shortName, ",", LONG_PREFIX,
          longName.get());
    }
    return SHORT_PREFIX + shortName;
  }

  boolean isHelpOption() {
    return isHelpOption;
  }

  /**
   * Create a builder for building {@link OptionNoArg} instances.
   * @param shortName he short name to use, must conform to this regular
   *          expression: {@link #NAME_REGEX}.
   * @return A new builder instance.
   */
  public static NoArgBuilder builder(String shortName) {
    return new NoArgBuilder(shortName);
  }

  static NoArgBuilder builder(OptionNoArg opt) {
    return new NoArgBuilder(opt);
  }

  /**
   * Create a builder for building {@link OptionArg} instances.
   * @param shortName The short name to use, must conform to this regular
   *          expression: {@link #NAME_REGEX}.
   * @param argumentParser The {@link ArgumentParser} defines the type of
   *          argument that the resulting option expects.
   * @param  The type of argument that the resulting {@link OptionArg} will
   *          expect.
   * @return A new builder instance.
   */
  public static  ArgBuilder builder(String shortName,
      ArgumentParser argumentParser) {
    return new ArgBuilder<>(shortName, argumentParser);
  }

  static  ArgBuilder builder(OptionArg opt) {
    return new ArgBuilder<>(opt);
  }

  /**
   * An {@link Option} that optionally requires an argument of type
   * T.
   * @param  The type of the argument.
   * @author Rinde van Lon
   */
  public static class OptionArg extends Option {
    final ArgumentParser argumentType;

    OptionArg(ArgBuilder b, boolean help) {
      super(b, help);
      argumentType = b.argumentType;
    }

    @Override
    public Optional> getArgument() {
      return Optional.> of(argumentType);
    }
  }

  /**
   * An {@link Option} that does not support any arguments.
   * @author Rinde van Lon
   */
  public static class OptionNoArg extends Option {
    OptionNoArg(NoArgBuilder b, boolean help) {
      super(b, help);
    }
  }

  /**
   * A builder for creating {@link OptionNoArg} instances.
   * @author Rinde van Lon
   */
  public static class NoArgBuilder extends Builder {
    NoArgBuilder(String sn) {
      super(sn);
    }

    NoArgBuilder(OptionNoArg opt) {
      super(opt);
    }

    /**
     * @return A new {@link OptionNoArg} instance.
     */
    public OptionNoArg build() {
      return new OptionNoArg(this, false);
    }

    OptionNoArg buildHelpOption() {
      return new OptionNoArg(this, true);
    }

    @Override
    protected NoArgBuilder self() {
      return this;
    }
  }

  /**
   * A builder for creating {@link OptionArg} instances.
   * @param  The type of the argument that options that are created by this
   *          builder require.
   * @author Rinde van Lon
   */
  public static class ArgBuilder extends Builder> {
    ArgumentParser argumentType;

    ArgBuilder(String sn, ArgumentParser argType) {
      super(sn);
      argumentType = argType;
    }

    ArgBuilder(OptionArg opt) {
      super(opt);
      argumentType = opt.argumentType;
    }

    /**
     * Calling this method will make the argument of the option optional.
     * @return This, as per the builder pattern.
     */
    public ArgBuilder setOptionalArgument() {
      isArgOptional = true;
      return self();
    }

    /**
     * @return A new {@link OptionArg} instance.
     */
    public OptionArg build() {
      return new OptionArg<>(this, false);
    }

    @Override
    protected ArgBuilder self() {
      return this;
    }
  }

  /**
   * Builder of {@link Option} instances.
   * @param  Value type
   * @author Rinde van Lon
   */
  abstract static class Builder> {
    String shortName;
    Optional longName;
    String description;
    boolean isArgOptional;

    Builder(String sn) {
      checkOptionName(sn);
      shortName = sn;
      longName = Optional.absent();
      description = "";
      isArgOptional = false;
    }

    Builder(Option opt) {
      shortName = opt.shortName;
      longName = opt.longName;
      description = opt.description;
      isArgOptional = opt.isArgOptional;
    }

    /**
     * Should return 'this', the builder.
     * @return 'this'.
     */
    protected abstract T self();

    /**
     * Set the short name of the option. The name must conform to this regular
     * expression: {@link #NAME_REGEX}. Any previous value is overridden.
     * @param sn The short name to use.
     * @return This, as per the builder pattern.
     */
    public T shortName(String sn) {
      checkOptionName(sn);
      shortName = sn;
      return self();
    }

    /**
     * Set the long name of the option. The name must conform to this regular
     * expression: {@link #NAME_REGEX}. Any previous value is overridden.
     * @param ln The long name to use.
     * @return This, as per the builder pattern.
     */
    public T longName(String ln) {
      checkOptionName(ln);
      longName = Optional.of(ln);
      return self();
    }

    /**
     * Sets the description of the option, to be displayed in the help menu.
     * @param desc The description, if multiple strings are supplied they are
     *          concatenated.
     * @return This, as per the builder pattern.
     */
    public T description(Object... desc) {
      description = Joiner.on("").join(desc);
      return self();
    }

    static void checkOptionName(String name) {
      checkArgument(name.matches(NAME_REGEX),
          "%s is not a valid option name, it must conform to %s.", name,
          NAME_REGEX);
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy