diff --git a/build.gradle b/build.gradle index 7733484..36fd331 100644 --- a/build.gradle +++ b/build.gradle @@ -14,6 +14,7 @@ repositories { } dependencies { + compile 'com.moandjiezana.toml:toml4j:0.7.1' testCompile 'junit:junit:4.12' } diff --git a/src/org/nwapw/abacus/config/Configuration.java b/src/org/nwapw/abacus/config/Configuration.java new file mode 100644 index 0000000..d22d50d --- /dev/null +++ b/src/org/nwapw/abacus/config/Configuration.java @@ -0,0 +1,18 @@ +package org.nwapw.abacus.config; + +/** + * Serializable class that will be used to load TOML + * configurations. + */ +public class Configuration { + + /** + * The precision to which the calculator should operator. + */ + public int decimalPrecision; + /** + * The type of number this calculator should use. + */ + public String numberType; + +} diff --git a/src/org/nwapw/abacus/config/ConfigurationObject.java b/src/org/nwapw/abacus/config/ConfigurationObject.java new file mode 100644 index 0000000..c8147a4 --- /dev/null +++ b/src/org/nwapw/abacus/config/ConfigurationObject.java @@ -0,0 +1,146 @@ +package org.nwapw.abacus.config; + +import com.moandjiezana.toml.Toml; +import com.moandjiezana.toml.TomlWriter; +import org.nwapw.abacus.number.NaiveNumber; + +import java.io.File; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.util.HashMap; +import java.util.Map; + +/** + * A configuration object, which essentially + * manages saving, loading, and getting values + * from the configuration. While Configuration is + * the data model, this is the interface with it. + */ +public class ConfigurationObject { + + /** + * The default implementation to use for instantiating numbers. + */ + private static final Class DEFAULT_IMPLEMENTATION = NaiveNumber.class; + /** + * The writer used to store the configuration. + */ + private static final TomlWriter TOML_WRITER = new TomlWriter(); + /** + * The configuration instance being modeled. + */ + private Configuration configuration; + /** + * A map of number names to their implementations, which + * will be provided by plugins. + */ + private Map> numberImplementations; + + /** + * Sets up the ConfigurationObject. + * different constructors do different things, + * but they all lead here. + * @param configuration the configuration to set up with. + */ + private void setup(Configuration configuration){ + this.configuration = configuration; + numberImplementations = new HashMap<>(); + } + + /** + * Creates a default configuration. + * @return the newly created default configuration. + */ + private Configuration getDefaultConfig(){ + configuration = new Configuration(); + configuration.decimalPrecision = -1; + configuration.numberType = "naive"; + return configuration; + } + + /** + * Register a number implementation. + * @param name the name of the number implementation to register the class as. + * @param newClass the class that will be used to instantiate the new number. + * It is required that this class provides a Number(String) constructor. + */ + public void registerImplementation(String name, Class newClass){ + numberImplementations.put(name, newClass); + } + + /** + * Creates a new number with the configured type, passing + * it the given string. + * @param string the string from which the number should be parsed. + * @return the resulting number, or null if an error occurred. + */ + public NaiveNumber numberFromString(String string) { + Class toLoad = + numberImplementations.getOrDefault(configuration.numberType, DEFAULT_IMPLEMENTATION); + try { + return toLoad.getConstructor(String.class).newInstance(string); + } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { + e.printStackTrace(); + } + return null; + } + + /** + * Returns the configured, user-requested precision. + * @return the precision. + */ + public int getPrecision(){ + return configuration.decimalPrecision; + } + + /** + * Saves the ConfigurationObject to the given file. + * @param toFile the file to save ot. + * @return true if the save succeed, false if otherwise. + */ + public boolean save(File toFile){ + if(toFile.getParentFile() != null) toFile.getParentFile().mkdirs(); + try { + TOML_WRITER.write(configuration, toFile); + return true; + } catch (IOException e) { + e.printStackTrace(); + } + return false; + } + + /** + * Creates a new configuration object with the given config. + * @param config the config to use. + */ + public ConfigurationObject(Configuration config){ + setup(config); + } + + /** + * Create a configuration object by attempting to + * load a config from the given path, using the + * default configuration otherwise. + * @param path the path to attempt to load. + */ + public ConfigurationObject(File path){ + Configuration config; + if(!path.exists()) { + config = getDefaultConfig(); + } else { + Toml parse = new Toml(); + parse.read(path); + config = parse.to(Configuration.class); + } + setup(config); + } + + /** + * Creates a new configuration object with the + * default configuration. + */ + public ConfigurationObject(){ + setup(getDefaultConfig()); + } + +} diff --git a/src/org/nwapw/abacus/number/NaiveNumber.java b/src/org/nwapw/abacus/number/NaiveNumber.java index 1a80cd1..96e42dd 100755 --- a/src/org/nwapw/abacus/number/NaiveNumber.java +++ b/src/org/nwapw/abacus/number/NaiveNumber.java @@ -10,6 +10,13 @@ public class NaiveNumber implements NumberInterface { */ private double value; + /** + * Creates a new NaiveNumber with the given string. + * @param value the value, which will be parsed as a double. + */ + public NaiveNumber(String value) { + this(Double.parseDouble(value)); + } /** * Creates a new NaiveNumber with the given value. * @param value the value to use. @@ -28,7 +35,7 @@ public class NaiveNumber implements NumberInterface { public static final NaiveNumber ONE = new NaiveNumber(1); @Override - public int precision() { + public int getMaxPrecision() { return 18; } diff --git a/src/org/nwapw/abacus/number/NumberInterface.java b/src/org/nwapw/abacus/number/NumberInterface.java index f425a30..1f87d11 100755 --- a/src/org/nwapw/abacus/number/NumberInterface.java +++ b/src/org/nwapw/abacus/number/NumberInterface.java @@ -6,10 +6,10 @@ package org.nwapw.abacus.number; public interface NumberInterface { /** - * The precision to which this number operates. + * The maximum precision to which this number operates. * @return the precision. */ - int precision(); + int getMaxPrecision(); /** * Multiplies this number by another, returning diff --git a/src/org/nwapw/abacus/number/PreciseNumber.java b/src/org/nwapw/abacus/number/PreciseNumber.java index 1641cff..8b01622 100755 --- a/src/org/nwapw/abacus/number/PreciseNumber.java +++ b/src/org/nwapw/abacus/number/PreciseNumber.java @@ -1,8 +1,6 @@ package org.nwapw.abacus.number; import java.math.BigDecimal; -import java.math.BigInteger; -import java.math.MathContext; import java.math.RoundingMode; public class PreciseNumber implements NumberInterface{ @@ -43,7 +41,7 @@ public class PreciseNumber implements NumberInterface{ } @Override - public int precision() { + public int getMaxPrecision() { return 54; } @@ -54,7 +52,7 @@ public class PreciseNumber implements NumberInterface{ @Override public NumberInterface divide(NumberInterface divisor) { - return new PreciseNumber(value.divide(((PreciseNumber) divisor).value, this.precision(), RoundingMode.HALF_UP)); + return new PreciseNumber(value.divide(((PreciseNumber) divisor).value, this.getMaxPrecision(), RoundingMode.HALF_UP)); } @Override @@ -109,7 +107,7 @@ public class PreciseNumber implements NumberInterface{ @Override public String toString() { - BigDecimal rounded = value.setScale(precision() - 4, RoundingMode.HALF_UP); + BigDecimal rounded = value.setScale(getMaxPrecision() - 4, RoundingMode.HALF_UP); return rounded.stripTrailingZeros().toPlainString(); } } diff --git a/src/org/nwapw/abacus/plugin/StandardPlugin.java b/src/org/nwapw/abacus/plugin/StandardPlugin.java index 1ae0969..088c877 100755 --- a/src/org/nwapw/abacus/plugin/StandardPlugin.java +++ b/src/org/nwapw/abacus/plugin/StandardPlugin.java @@ -292,7 +292,7 @@ public class StandardPlugin extends Plugin { * @return the maximum error. */ private NumberInterface getMaxError(NumberInterface number){ - return (new NaiveNumber(10)).promoteTo(number.getClass()).intPow(-number.precision()); + return (new NaiveNumber(10)).promoteTo(number.getClass()).intPow(-number.getMaxPrecision()); } }