Had previously fixed AbstractConfigObject.merge() in the same way. For this
patch, factor out the code from AbstractConfigObject and use it everywhere.
Add some tests for merges with substitutions involved.
Also write some docs for ConfigMergeable explaining the easy way
to do it wrong.
This separates ConfigObject, which is:
- a tree of maps
- that can contain ConfigValueType.NULL
from Config, which is:
- a one-level map from path to non-map values
- which never returns a ConfigValueType.NULL
Share implementation of this with the Properties parser;
it makes the Properties parser somewhat less efficient due
to creating the intermediate Path objects, but should not matter.
This was causing at least a couple bugs; in one test, a properties file
was being parsed with conf syntax; and includes suddenly could not
be missing if the parent file could not be missing.
The spec described parsing this as a 1-element path but
the implementation parsed it as 2 elements which is probably
a better behavior because it's less surprising. The simple
rule is now "only quoted periods are special".
The AbstractConfigObject.merge() method was wrong; it merged in the
wrong order, which produced incorrect results. But there was a test
verifying that the results were wrong! So it's OK right?
Anyway, fix the test, fix the code, be sure it's crystal clear in spec.
fromProperties() now parses paths with a strict "split on period"
It now handles more than one level of nested object.
It's now defined that if a properties file defines both an
object and a string at the same key, the object wins.
Preserves the memory size vs. disk size distinction (powers of two vs. ten)
But specifies that it will be in bytes, for consistency with getMilliseconds
and clarity in general.
Introduce ConfigIncluder pluggable includer interface.
Move all the parse-something logic from Config, Loader,
ConfigImpl, Parser into the Parseable abstraction.
Value concatenation is supposed to provide an illusion that
you can just type long unquoted sentences, but really they
are a series of tokens. Be sure we don't weirdly reformat
any numbers that happen to appear in unquoted text.