summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdrien Hopkins <masterofnumbers17@gmail.com>2019-11-08 20:49:15 -0500
committerAdrien Hopkins <masterofnumbers17@gmail.com>2019-11-08 20:49:15 -0500
commit7bf4824a0619a79cb10faf8f83146b96e51341d2 (patch)
treea0c3c716c1ef71c2fc4480881190b94dd515ea67
parentdd662ac39be68f8d305989be6cd9550879668a5c (diff)
parent8ec94bea790cc010c29cd8de86e47117ff331979 (diff)
Merge branch 'feature-unit-names' into develop
-rw-r--r--src/org/unitConverter/unit/BaseUnit.java63
-rw-r--r--src/org/unitConverter/unit/FunctionalUnit.java45
-rw-r--r--src/org/unitConverter/unit/LinearUnit.java62
-rw-r--r--src/org/unitConverter/unit/Unit.java342
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."));
}
}