diff options
author | Adrien Hopkins <masterofnumbers17@gmail.com> | 2019-11-08 20:49:15 -0500 |
---|---|---|
committer | Adrien Hopkins <masterofnumbers17@gmail.com> | 2019-11-08 20:49:15 -0500 |
commit | 7bf4824a0619a79cb10faf8f83146b96e51341d2 (patch) | |
tree | a0c3c716c1ef71c2fc4480881190b94dd515ea67 | |
parent | dd662ac39be68f8d305989be6cd9550879668a5c (diff) | |
parent | 8ec94bea790cc010c29cd8de86e47117ff331979 (diff) |
Merge branch 'feature-unit-names' into develop
-rw-r--r-- | src/org/unitConverter/unit/BaseUnit.java | 63 | ||||
-rw-r--r-- | src/org/unitConverter/unit/FunctionalUnit.java | 45 | ||||
-rw-r--r-- | src/org/unitConverter/unit/LinearUnit.java | 62 | ||||
-rw-r--r-- | src/org/unitConverter/unit/Unit.java | 342 |
4 files changed, 447 insertions, 65 deletions
diff --git a/src/org/unitConverter/unit/BaseUnit.java b/src/org/unitConverter/unit/BaseUnit.java index 8f44861..e9ef3fa 100644 --- a/src/org/unitConverter/unit/BaseUnit.java +++ b/src/org/unitConverter/unit/BaseUnit.java @@ -16,10 +16,15 @@ */ package org.unitConverter.unit; +import java.util.HashSet; import java.util.Objects; +import java.util.Set; /** * A unit that other units are defined by. + * <p> + * Note that BaseUnits <b>must</b> have names and symbols. This is because they are used for toString code. Therefore, + * the Optionals provided by {@link #getPrimaryName} and {@link #getSymbol} will always contain a value. * * @author Adrien Hopkins * @since 2019-10-16 @@ -38,19 +43,34 @@ public final class BaseUnit extends Unit { * @since 2019-10-16 */ public static BaseUnit valueOf(final BaseDimension dimension, final String name, final String symbol) { - return new BaseUnit(dimension, name, symbol); + return new BaseUnit(dimension, name, symbol, new HashSet<>()); + } + + /** + * Gets a base unit from the dimension it measures, its name and its symbol. + * + * @param dimension + * dimension measured by this unit + * @param name + * name of unit + * @param symbol + * symbol of unit + * @return base unit + * @since 2019-10-21 + */ + public static BaseUnit valueOf(final BaseDimension dimension, final String name, final String symbol, + final Set<String> otherNames) { + return new BaseUnit(dimension, name, symbol, otherNames); } private final BaseDimension dimension; - private final String name; - private final String symbol; /** * Creates the {@code BaseUnit}. * * @param dimension * dimension of unit - * @param name + * @param primaryName * name of unit * @param symbol * symbol of unit @@ -58,11 +78,10 @@ public final class BaseUnit extends Unit { * if any argument is null * @since 2019-10-16 */ - private BaseUnit(final BaseDimension dimension, final String name, final String symbol) { - super(); + private BaseUnit(final BaseDimension dimension, final String primaryName, final String symbol, + final Set<String> otherNames) { + super(primaryName, symbol, otherNames); this.dimension = Objects.requireNonNull(dimension, "dimension must not be null."); - this.name = Objects.requireNonNull(name, "name must not be null."); - this.symbol = Objects.requireNonNull(symbol, "symbol must not be null."); } /** @@ -94,24 +113,20 @@ public final class BaseUnit extends Unit { return this.dimension; } - /** - * @return name - * @since 2019-10-16 - */ - public final String getName() { - return this.name; - } - - /** - * @return symbol - * @since 2019-10-16 - */ - public final String getSymbol() { - return this.symbol; + @Override + public String toString() { + return this.getPrimaryName().orElse("Unnamed unit") + + (this.getSymbol().isPresent() ? String.format(" (%s)", this.getSymbol().get()) : ""); } @Override - public String toString() { - return String.format("%s (%s)", this.getName(), this.getSymbol()); + public BaseUnit withName(final NameSymbol ns) { + Objects.requireNonNull(ns, "ns must not be null."); + if (!ns.getPrimaryName().isPresent()) + throw new IllegalArgumentException("BaseUnits must have primary names."); + if (!ns.getSymbol().isPresent()) + throw new IllegalArgumentException("BaseUnits must have symbols."); + return BaseUnit.valueOf(this.getBaseDimension(), ns.getPrimaryName().get(), ns.getSymbol().get(), + ns.getOtherNames()); } } diff --git a/src/org/unitConverter/unit/FunctionalUnit.java b/src/org/unitConverter/unit/FunctionalUnit.java index 7ddd876..e2ab6e7 100644 --- a/src/org/unitConverter/unit/FunctionalUnit.java +++ b/src/org/unitConverter/unit/FunctionalUnit.java @@ -29,7 +29,21 @@ import org.unitConverter.math.ObjectProduct; */ final class FunctionalUnit extends Unit { /** - * Returns a unit from its base and the functions it uses to convert to and from its base. + * A function that accepts a value expressed in the unit's base and returns that value expressed in this unit. + * + * @since 2019-05-22 + */ + private final DoubleUnaryOperator converterFrom; + + /** + * A function that accepts a value expressed in the unit and returns that value expressed in the unit's base. + * + * @since 2019-05-22 + */ + private final DoubleUnaryOperator converterTo; + + /** + * Creates the {@code FunctionalUnit}. * * @param base * unit's base @@ -39,31 +53,18 @@ final class FunctionalUnit extends Unit { * @param converterTo * function that accepts a value expressed in the unit and returns that value expressed in the unit's * base. - * @return a unit that uses the provided functions to convert. - * @since 2019-05-22 * @throws NullPointerException * if any argument is null + * @since 2019-05-22 */ - public static FunctionalUnit valueOf(final ObjectProduct<BaseUnit> base, final DoubleUnaryOperator converterFrom, + public FunctionalUnit(final ObjectProduct<BaseUnit> base, final DoubleUnaryOperator converterFrom, final DoubleUnaryOperator converterTo) { - return new FunctionalUnit(base, converterFrom, converterTo); + super(base, NameSymbol.EMPTY); + this.converterFrom = Objects.requireNonNull(converterFrom, "converterFrom must not be null."); + this.converterTo = Objects.requireNonNull(converterTo, "converterTo must not be null."); } /** - * A function that accepts a value expressed in the unit's base and returns that value expressed in this unit. - * - * @since 2019-05-22 - */ - private final DoubleUnaryOperator converterFrom; - - /** - * A function that accepts a value expressed in the unit and returns that value expressed in the unit's base. - * - * @since 2019-05-22 - */ - private final DoubleUnaryOperator converterTo; - - /** * Creates the {@code FunctionalUnit}. * * @param base @@ -78,9 +79,9 @@ final class FunctionalUnit extends Unit { * if any argument is null * @since 2019-05-22 */ - private FunctionalUnit(final ObjectProduct<BaseUnit> base, final DoubleUnaryOperator converterFrom, - final DoubleUnaryOperator converterTo) { - super(base); + public FunctionalUnit(final ObjectProduct<BaseUnit> base, final DoubleUnaryOperator converterFrom, + final DoubleUnaryOperator converterTo, final NameSymbol ns) { + super(base, ns); this.converterFrom = Objects.requireNonNull(converterFrom, "converterFrom must not be null."); this.converterTo = Objects.requireNonNull(converterTo, "converterTo must not be null."); } diff --git a/src/org/unitConverter/unit/LinearUnit.java b/src/org/unitConverter/unit/LinearUnit.java index 1918d6b..7b7338b 100644 --- a/src/org/unitConverter/unit/LinearUnit.java +++ b/src/org/unitConverter/unit/LinearUnit.java @@ -38,9 +38,32 @@ public final class LinearUnit extends Unit { * value to convert * @return value expressed as a {@code LinearUnit} * @since 2019-10-16 + * @throws NullPointerException + * if unit is null */ public static LinearUnit fromUnitValue(final Unit unit, final double value) { - return new LinearUnit(unit.getBase(), unit.convertToBase(value)); + return new LinearUnit(Objects.requireNonNull(unit, "unit must not be null.").getBase(), + unit.convertToBase(value), NameSymbol.EMPTY); + } + + /** + * Gets a {@code LinearUnit} from a unit and a value. For example, converts '59 °F' to a linear unit with the value + * of '288.15 K' + * + * @param unit + * unit to convert + * @param value + * value to convert + * @param ns + * name(s) and symbol of unit + * @return value expressed as a {@code LinearUnit} + * @since 2019-10-21 + * @throws NullPointerException + * if unit or ns is null + */ + public static LinearUnit fromUnitValue(final Unit unit, final double value, final NameSymbol ns) { + return new LinearUnit(Objects.requireNonNull(unit, "unit must not be null.").getBase(), + unit.convertToBase(value), ns); } /** @@ -53,9 +76,31 @@ public final class LinearUnit extends Unit { * number to multiply base by * @return product of base and conversion factor * @since 2019-10-16 + * @throws NullPointerException + * if unitBase is null */ public static LinearUnit valueOf(final ObjectProduct<BaseUnit> unitBase, final double conversionFactor) { - return new LinearUnit(unitBase, conversionFactor); + return new LinearUnit(unitBase, conversionFactor, NameSymbol.EMPTY); + } + + /** + * Gets a {@code LinearUnit} from a unit base and a conversion factor. In other words, gets the product of + * {@code unitBase} and {@code conversionFactor}, expressed as a {@code LinearUnit}. + * + * @param unitBase + * unit base to multiply by + * @param conversionFactor + * number to multiply base by + * @param ns + * name(s) and symbol of unit + * @return product of base and conversion factor + * @since 2019-10-21 + * @throws NullPointerException + * if unitBase is null + */ + public static LinearUnit valueOf(final ObjectProduct<BaseUnit> unitBase, final double conversionFactor, + final NameSymbol ns) { + return new LinearUnit(unitBase, conversionFactor, ns); } /** @@ -78,8 +123,8 @@ public final class LinearUnit extends Unit { * conversion factor between base and unit * @since 2019-10-16 */ - private LinearUnit(final ObjectProduct<BaseUnit> unitBase, final double conversionFactor) { - super(unitBase); + private LinearUnit(final ObjectProduct<BaseUnit> unitBase, final double conversionFactor, final NameSymbol ns) { + super(unitBase, ns); this.conversionFactor = conversionFactor; } @@ -270,7 +315,14 @@ public final class LinearUnit extends Unit { // returns a definition of the unit @Override public String toString() { - return Double.toString(this.conversionFactor) + " * " + this.getBase().toString(BaseUnit::getSymbol); + return this.getPrimaryName().orElse("Unnamed unit") + + (this.getSymbol().isPresent() ? String.format(" (%s)", this.getSymbol().get()) : "") + ", " + + Double.toString(this.conversionFactor) + " * " + this.getBase().toString(u -> u.getSymbol().get()); + } + + @Override + public LinearUnit withName(final NameSymbol ns) { + return valueOf(this.getBase(), this.getConversionFactor(), ns); } /** diff --git a/src/org/unitConverter/unit/Unit.java b/src/org/unitConverter/unit/Unit.java index 7971a41..d848ea1 100644 --- a/src/org/unitConverter/unit/Unit.java +++ b/src/org/unitConverter/unit/Unit.java @@ -16,9 +16,14 @@ */ package org.unitConverter.unit; +import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; import java.util.Objects; +import java.util.Optional; +import java.util.Set; import java.util.function.DoubleUnaryOperator; import org.unitConverter.math.ObjectProduct; @@ -31,6 +36,222 @@ import org.unitConverter.math.ObjectProduct; */ public abstract class Unit { /** + * A class that can be used to specify names and a symbol for a unit. + * + * @author Adrien Hopkins + * @since 2019-10-21 + */ + public static final class NameSymbol { + public static final NameSymbol EMPTY = new NameSymbol(Optional.empty(), Optional.empty(), new HashSet<>()); + + /** + * Gets a {@code NameSymbol} with a primary name, a symbol and no other names. + * + * @param name + * name to use + * @param symbol + * symbol to use + * @return NameSymbol instance + * @since 2019-10-21 + * @throws NullPointerException + * if name or symbol is null + */ + public static final NameSymbol of(final String name, final String symbol) { + return new NameSymbol(Optional.of(name), Optional.of(symbol), new HashSet<>()); + } + + /** + * Gets a {@code NameSymbol} with a primary name, a symbol and additional names. + * + * @param name + * name to use + * @param symbol + * symbol to use + * @param otherNames + * other names to use + * @return NameSymbol instance + * @since 2019-10-21 + * @throws NullPointerException + * if any argument is null + */ + public static final NameSymbol of(final String name, final String symbol, final Set<String> otherNames) { + return new NameSymbol(Optional.of(name), Optional.of(symbol), + new HashSet<>(Objects.requireNonNull(otherNames, "otherNames must not be null."))); + } + + /** + * h * Gets a {@code NameSymbol} with a primary name, a symbol and additional names. + * + * @param name + * name to use + * @param symbol + * symbol to use + * @param otherNames + * other names to use + * @return NameSymbol instance + * @since 2019-10-21 + * @throws NullPointerException + * if any argument is null + */ + public static final NameSymbol of(final String name, final String symbol, final String... otherNames) { + return new NameSymbol(Optional.of(name), Optional.of(symbol), + new HashSet<>(Arrays.asList(Objects.requireNonNull(otherNames, "otherNames must not be null.")))); + } + + /** + * Gets a {@code NameSymbol} with a primary name, a symbol and an additional name. + * + * @param name + * name to use + * @param symbol + * symbol to use + * @param otherNames + * other names to use + * @param name2 + * alternate name + * @return NameSymbol instance + * @since 2019-10-21 + * @throws NullPointerException + * if any argument is null + */ + public static final NameSymbol of(final String name, final String symbol, final String name2) { + final Set<String> otherNames = new HashSet<>(); + otherNames.add(Objects.requireNonNull(name2, "name2 must not be null.")); + return new NameSymbol(Optional.of(name), Optional.of(symbol), otherNames); + } + + /** + * Gets a {@code NameSymbol} with a primary name, a symbol and additional names. + * + * @param name + * name to use + * @param symbol + * symbol to use + * @param otherNames + * other names to use + * @param name2 + * alternate name + * @param name3 + * alternate name + * @return NameSymbol instance + * @since 2019-10-21 + * @throws NullPointerException + * if any argument is null + */ + public static final NameSymbol of(final String name, final String symbol, final String name2, + final String name3) { + final Set<String> otherNames = new HashSet<>(); + otherNames.add(Objects.requireNonNull(name2, "name2 must not be null.")); + otherNames.add(Objects.requireNonNull(name3, "name3 must not be null.")); + return new NameSymbol(Optional.of(name), Optional.of(symbol), otherNames); + } + + /** + * Gets a {@code NameSymbol} with a primary name, a symbol and additional names. + * + * @param name + * name to use + * @param symbol + * symbol to use + * @param otherNames + * other names to use + * @param name2 + * alternate name + * @param name3 + * alternate name + * @param name4 + * alternate name + * @return NameSymbol instance + * @since 2019-10-21 + * @throws NullPointerException + * if any argument is null + */ + public static final NameSymbol of(final String name, final String symbol, final String name2, + final String name3, final String name4) { + final Set<String> otherNames = new HashSet<>(); + otherNames.add(Objects.requireNonNull(name2, "name2 must not be null.")); + otherNames.add(Objects.requireNonNull(name3, "name3 must not be null.")); + otherNames.add(Objects.requireNonNull(name4, "name4 must not be null.")); + return new NameSymbol(Optional.of(name), Optional.of(symbol), otherNames); + } + + /** + * Gets a {@code NameSymbol} with a primary name, no symbol, and no other names. + * + * @param name + * name to use + * @return NameSymbol instance + * @since 2019-10-21 + * @throws NullPointerException + * if name is null + */ + public static final NameSymbol ofName(final String name) { + return new NameSymbol(Optional.of(name), Optional.empty(), new HashSet<>()); + } + + /** + * Gets a {@code NameSymbol} with a symbol and no names. + * + * @param symbol + * symbol to use + * @return NameSymbol instance + * @since 2019-10-21 + * @throws NullPointerException + * if symbol is null + */ + public static final NameSymbol ofSymbol(final String symbol) { + return new NameSymbol(Optional.empty(), Optional.of(symbol), new HashSet<>()); + } + + private final Optional<String> primaryName; + private final Optional<String> symbol; + + private final Set<String> otherNames; + + /** + * Creates the {@code NameSymbol}. + * + * @param primaryName + * primary name of unit + * @param symbol + * symbol used to represent unit + * @param otherNames + * other names and/or spellings + * @since 2019-10-21 + */ + private NameSymbol(final Optional<String> primaryName, final Optional<String> symbol, + final Set<String> otherNames) { + this.primaryName = primaryName; + this.symbol = symbol; + this.otherNames = Collections.unmodifiableSet(otherNames); + } + + /** + * @return otherNames + * @since 2019-10-21 + */ + public final Set<String> getOtherNames() { + return this.otherNames; + } + + /** + * @return primaryName + * @since 2019-10-21 + */ + public final Optional<String> getPrimaryName() { + return this.primaryName; + } + + /** + * @return symbol + * @since 2019-10-21 + */ + public final Optional<String> getSymbol() { + return this.symbol; + } + } + + /** * Returns a unit from its base and the functions it uses to convert to and from its base. * * <p> @@ -54,7 +275,36 @@ public abstract class Unit { */ public static final Unit fromConversionFunctions(final ObjectProduct<BaseUnit> base, final DoubleUnaryOperator converterFrom, final DoubleUnaryOperator converterTo) { - return FunctionalUnit.valueOf(base, converterFrom, converterTo); + return new FunctionalUnit(base, converterFrom, converterTo); + } + + /** + * Returns a unit from its base and the functions it uses to convert to and from its base. + * + * <p> + * For example, to get a unit representing the degree Celsius, the following code can be used: + * + * {@code Unit.fromConversionFunctions(SI.KELVIN, tempK -> tempK - 273.15, tempC -> tempC + 273.15);} + * </p> + * + * @param base + * unit's base + * @param converterFrom + * function that accepts a value expressed in the unit's base and returns that value expressed in this + * unit. + * @param converterTo + * function that accepts a value expressed in the unit and returns that value expressed in the unit's + * base. + * @param ns + * names and symbol of unit + * @return a unit that uses the provided functions to convert. + * @since 2019-05-22 + * @throws NullPointerException + * if any argument is null + */ + public static final Unit fromConversionFunctions(final ObjectProduct<BaseUnit> base, + final DoubleUnaryOperator converterFrom, final DoubleUnaryOperator converterTo, final NameSymbol ns) { + return new FunctionalUnit(base, converterFrom, converterTo, ns); } /** @@ -65,6 +315,21 @@ public abstract class Unit { private final ObjectProduct<BaseUnit> unitBase; /** + * The primary name used by this unit. + */ + private final Optional<String> primaryName; + + /** + * A short symbol used to represent this unit. + */ + private final Optional<String> symbol; + + /** + * A set of any additional names and/or spellings that the unit uses. + */ + private final Set<String> otherNames; + + /** * Cache storing the result of getDimension() * * @since 2019-10-16 @@ -72,27 +337,37 @@ public abstract class Unit { private transient ObjectProduct<BaseDimension> dimension = null; /** - * A constructor that constructs {@code BaseUnit} instances. + * Creates the {@code AbstractUnit}. * + * @param unitBase + * base of unit + * @param ns + * names and symbol of unit * @since 2019-10-16 + * @throws NullPointerException + * if unitBase or ns is null */ - Unit() { - if (this instanceof BaseUnit) { - this.unitBase = ObjectProduct.oneOf((BaseUnit) this); - } else - throw new AssertionError(); + protected Unit(final ObjectProduct<BaseUnit> unitBase, final NameSymbol ns) { + this.unitBase = Objects.requireNonNull(unitBase, "unitBase must not be null."); + this.primaryName = Objects.requireNonNull(ns, "ns must not be null.").getPrimaryName(); + this.symbol = ns.getSymbol(); + this.otherNames = ns.getOtherNames(); } /** - * Creates the {@code AbstractUnit}. + * A constructor that constructs {@code BaseUnit} instances. * - * @param unitBase * @since 2019-10-16 - * @throws NullPointerException - * if unitBase is null */ - protected Unit(final ObjectProduct<BaseUnit> unitBase) { - this.unitBase = Objects.requireNonNull(unitBase, "unitBase must not be null."); + Unit(final String primaryName, final String symbol, final Set<String> otherNames) { + if (this instanceof BaseUnit) { + this.unitBase = ObjectProduct.oneOf((BaseUnit) this); + } else + throw new AssertionError(); + this.primaryName = Optional.of(primaryName); + this.symbol = Optional.of(symbol); + this.otherNames = Collections.unmodifiableSet( + new HashSet<>(Objects.requireNonNull(otherNames, "additionalNames must not be null."))); } /** @@ -208,8 +483,47 @@ public abstract class Unit { return this.dimension; } + /** + * @return additionalNames + * @since 2019-10-21 + */ + public final Set<String> getOtherNames() { + return this.otherNames; + } + + /** + * @return primaryName + * @since 2019-10-21 + */ + public final Optional<String> getPrimaryName() { + return this.primaryName; + } + + /** + * @return symbol + * @since 2019-10-21 + */ + public final Optional<String> getSymbol() { + return this.symbol; + } + @Override public String toString() { - return "Unit derived from base " + this.getBase().toString(); + return this.getPrimaryName().orElse("Unnamed unit") + + (this.getSymbol().isPresent() ? String.format(" (%s)", this.getSymbol().get()) : "") + + ", derived from " + this.getBase().toString(); + } + + /** + * @param ns + * name(s) and symbol to use + * @return a copy of this unit with provided name(s) and symbol + * @since 2019-10-21 + * @throws NullPointerException + * if ns is null + */ + public Unit withName(final NameSymbol ns) { + return fromConversionFunctions(this.getBase(), this::convertFromBase, this::convertToBase, + Objects.requireNonNull(ns, "ns must not be null.")); } } |