Support values with quotes in keyvalue config

This commit is contained in:
Mike Bierlee 2022-10-11 21:32:33 +03:00
parent 0b0b3108b1
commit 99a536a544
2 changed files with 56 additions and 11 deletions

View file

@ -12,7 +12,7 @@
module mirage.java; module mirage.java;
import mirage.config : ConfigDictionary; import mirage.config : ConfigDictionary;
import mirage.keyvalue : KeyValueConfigFactory, SupportHashtagComments, SupportSemicolonComments, SupportSections; import mirage.keyvalue : KeyValueConfigFactory, SupportHashtagComments, SupportSemicolonComments, SupportSections, NormalizeQuotedValues;
/** /**
* Creates configuration files from Java properties. * Creates configuration files from Java properties.
@ -20,7 +20,8 @@ import mirage.keyvalue : KeyValueConfigFactory, SupportHashtagComments, SupportS
class JavaPropertiesFactory : KeyValueConfigFactory!( class JavaPropertiesFactory : KeyValueConfigFactory!(
SupportHashtagComments.yes, SupportHashtagComments.yes,
SupportSemicolonComments.no, SupportSemicolonComments.no,
SupportSections.no SupportSections.no,
NormalizeQuotedValues.no
) { ) {
} }
@ -115,4 +116,15 @@ version (unittest) {
assert(config.get("server") == "localhost"); assert(config.get("server") == "localhost");
} }
@("Quotes in values are preserved")
unittest {
auto config = parseJavaProperties("
one=\"two\"
three='four'
");
assert(config.get("one") == "\"two\"");
assert(config.get("three") == "'four'");
}
} }

View file

@ -22,6 +22,7 @@ import std.typecons : Flag;
alias SupportHashtagComments = Flag!"SupportHashtagComments"; alias SupportHashtagComments = Flag!"SupportHashtagComments";
alias SupportSemicolonComments = Flag!"SupportSemicolonComments"; alias SupportSemicolonComments = Flag!"SupportSemicolonComments";
alias SupportSections = Flag!"SupportSections"; alias SupportSections = Flag!"SupportSections";
alias NormalizeQuotedValues = Flag!"NormalizeQuotedValues";
/** /**
* A generic reusable key/value config factory that can be configured to parse * A generic reusable key/value config factory that can be configured to parse
@ -30,7 +31,8 @@ alias SupportSections = Flag!"SupportSections";
class KeyValueConfigFactory( class KeyValueConfigFactory(
SupportHashtagComments supportHashtagComments = SupportHashtagComments.no, SupportHashtagComments supportHashtagComments = SupportHashtagComments.no,
SupportSemicolonComments supportSemicolonComments = SupportSemicolonComments.no, SupportSemicolonComments supportSemicolonComments = SupportSemicolonComments.no,
SupportSections supportSections = SupportSections.no SupportSections supportSections = SupportSections.no,
NormalizeQuotedValues normalizeQuotedValues = NormalizeQuotedValues.no
) : ConfigFactory { ) : ConfigFactory {
/** /**
* Parse a configuration file following the configured key/value conventions. * Parse a configuration file following the configured key/value conventions.
@ -83,8 +85,14 @@ class KeyValueConfigFactory(
.to!string ~ "): " ~ processedLine); .to!string ~ "): " ~ processedLine);
enforce!ConfigCreationException(parts.length == 2, "Missing value assignment (L" ~ index.to!string ~ "): " ~ processedLine); enforce!ConfigCreationException(parts.length == 2, "Missing value assignment (L" ~ index.to!string ~ "): " ~ processedLine);
auto value = parts[1].strip;
if (normalizeQuotedValues && (value.startsWith('"') || value.startsWith('\''))
&& (value.endsWith('"') || value.endsWith('\''))) {
value = value[1 .. $ - 1];
}
auto key = [section, parts[0].strip].join('.'); auto key = [section, parts[0].strip].join('.');
properties.set(key, parts[1].strip); properties.set(key, value);
} }
return properties; return properties;
@ -111,7 +119,8 @@ version (unittest) {
@("Parse and ignore comments") @("Parse and ignore comments")
unittest { unittest {
auto config = new KeyValueConfigFactory!(SupportHashtagComments.yes, auto config = new KeyValueConfigFactory!(
SupportHashtagComments.yes,
SupportSemicolonComments.yes SupportSemicolonComments.yes
)().parseConfig(" )().parseConfig("
# this is a comment # this is a comment
@ -131,8 +140,7 @@ version (unittest) {
@("Fail to parse when value assignment is missing") @("Fail to parse when value assignment is missing")
unittest { unittest {
assertThrown!ConfigCreationException(new TestKeyValueConfigFactory() assertThrown!ConfigCreationException(new TestKeyValueConfigFactory()
.parseConfig( .parseConfig("answertolife"));
"answertolife"));
} }
@("Substitute env vars") @("Substitute env vars")
@ -164,8 +172,10 @@ version (unittest) {
@("Remove end-of-line comments") @("Remove end-of-line comments")
unittest { unittest {
auto config = new KeyValueConfigFactory!(SupportHashtagComments.yes, auto config = new KeyValueConfigFactory!(
SupportSemicolonComments.yes)().parseConfig(" SupportHashtagComments.yes,
SupportSemicolonComments.yes
)().parseConfig("
server=localhost #todo: change me. default=localhost when not set. server=localhost #todo: change me. default=localhost when not set.
port=9876; I think this port = right? port=9876; I think this port = right?
"); ");
@ -176,9 +186,11 @@ version (unittest) {
@("Support sections when enabled") @("Support sections when enabled")
unittest { unittest {
auto config = new KeyValueConfigFactory!(SupportHashtagComments.no, auto config = new KeyValueConfigFactory!(
SupportHashtagComments.no,
SupportSemicolonComments.yes, SupportSemicolonComments.yes,
SupportSections.yes)().parseConfig(" SupportSections.yes
)().parseConfig("
applicationName = test me! applicationName = test me!
[server] [server]
@ -202,4 +214,25 @@ version (unittest) {
assert(config.get("server.middleware.protocolServer") == "netty"); assert(config.get("server.middleware.protocolServer") == "netty");
assert(config.get("database.driver.id") == "PostgresDriver"); assert(config.get("database.driver.id") == "PostgresDriver");
} }
@("Values with quotes are normalized and return the value within")
unittest {
auto config = new KeyValueConfigFactory!(
SupportHashtagComments.yes,
SupportSemicolonComments.no,
SupportSections.no,
NormalizeQuotedValues.yes
)().parseConfig("
baboon = \"ape\"
monkey = 'ape'
human = ape
excessiveWhitespace = ' '
");
assert(config.get("baboon") == "ape");
assert(config.get("monkey") == "ape");
assert(config.get("human") == "ape");
assert(config.get("excessiveWhitespace") == " ");
}
} }