mirror of
https://github.com/mbierlee/mirage-config.git
synced 2024-11-15 04:44:01 +01:00
Add support for multiline values
This commit is contained in:
parent
b0895cc13f
commit
86a2fa0f9f
4
TODO.md
4
TODO.md
|
@ -6,13 +6,13 @@
|
||||||
- Config manip
|
- Config manip
|
||||||
- Env and config var substitution
|
- Env and config var substitution
|
||||||
- Escaping
|
- Escaping
|
||||||
|
- Generic
|
||||||
|
- Base64 decoding of values
|
||||||
- Java properties
|
- Java properties
|
||||||
- Add unicode escaping
|
- Add unicode escaping
|
||||||
- Support multi-line values with backslash
|
|
||||||
- Add escaping of key/value separator = and :
|
- Add escaping of key/value separator = and :
|
||||||
- INI config
|
- INI config
|
||||||
- Case insensitive properties and sections
|
- Case insensitive properties and sections
|
||||||
- Escape characters
|
- Escape characters
|
||||||
- Support multi-line values with backslash
|
|
||||||
- TOML
|
- TOML
|
||||||
- Add support for the standard (https://github.com/toml-lang/toml)
|
- Add support for the standard (https://github.com/toml-lang/toml)
|
|
@ -14,7 +14,7 @@ module mirage.ini;
|
||||||
import mirage.config : ConfigDictionary;
|
import mirage.config : ConfigDictionary;
|
||||||
import mirage.keyvalue : KeyValueConfigFactory, SupportHashtagComments, SupportSemicolonComments,
|
import mirage.keyvalue : KeyValueConfigFactory, SupportHashtagComments, SupportSemicolonComments,
|
||||||
SupportExclamationComments, SupportSections, NormalizeQuotedValues, SupportEqualsSeparator,
|
SupportExclamationComments, SupportSections, NormalizeQuotedValues, SupportEqualsSeparator,
|
||||||
SupportColonSeparator, SupportKeysWithoutValues;
|
SupportColonSeparator, SupportKeysWithoutValues, SupportMultilineValues;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates configuration dictionaries from INI files.
|
* Creates configuration dictionaries from INI files.
|
||||||
|
@ -30,7 +30,8 @@ class IniConfigFactory : KeyValueConfigFactory!(
|
||||||
NormalizeQuotedValues.yes,
|
NormalizeQuotedValues.yes,
|
||||||
SupportEqualsSeparator.yes,
|
SupportEqualsSeparator.yes,
|
||||||
SupportColonSeparator.yes,
|
SupportColonSeparator.yes,
|
||||||
SupportKeysWithoutValues.no
|
SupportKeysWithoutValues.no,
|
||||||
|
SupportMultilineValues.yes
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ module mirage.java;
|
||||||
import mirage.config : ConfigDictionary;
|
import mirage.config : ConfigDictionary;
|
||||||
import mirage.keyvalue : KeyValueConfigFactory, SupportHashtagComments, SupportSemicolonComments,
|
import mirage.keyvalue : KeyValueConfigFactory, SupportHashtagComments, SupportSemicolonComments,
|
||||||
SupportExclamationComments, SupportSections, NormalizeQuotedValues, SupportEqualsSeparator,
|
SupportExclamationComments, SupportSections, NormalizeQuotedValues, SupportEqualsSeparator,
|
||||||
SupportColonSeparator, SupportKeysWithoutValues;
|
SupportColonSeparator, SupportKeysWithoutValues, SupportMultilineValues;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates configuration dictionaries from Java properties.
|
* Creates configuration dictionaries from Java properties.
|
||||||
|
@ -31,7 +31,8 @@ class JavaPropertiesFactory : KeyValueConfigFactory!(
|
||||||
NormalizeQuotedValues.no,
|
NormalizeQuotedValues.no,
|
||||||
SupportEqualsSeparator.yes,
|
SupportEqualsSeparator.yes,
|
||||||
SupportColonSeparator.yes,
|
SupportColonSeparator.yes,
|
||||||
SupportKeysWithoutValues.yes
|
SupportKeysWithoutValues.yes,
|
||||||
|
SupportMultilineValues.yes
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,7 @@ alias NormalizeQuotedValues = Flag!"NormalizeQuotedValues";
|
||||||
alias SupportEqualsSeparator = Flag!"SupportEqualsSeparator";
|
alias SupportEqualsSeparator = Flag!"SupportEqualsSeparator";
|
||||||
alias SupportColonSeparator = Flag!"SupportColonSeparator";
|
alias SupportColonSeparator = Flag!"SupportColonSeparator";
|
||||||
alias SupportKeysWithoutValues = Flag!"SupportKeysWithoutValues";
|
alias SupportKeysWithoutValues = Flag!"SupportKeysWithoutValues";
|
||||||
|
alias SupportMultilineValues = Flag!"SupportMultilineValues";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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
|
||||||
|
@ -40,7 +41,8 @@ class KeyValueConfigFactory(
|
||||||
NormalizeQuotedValues normalizeQuotedValues = NormalizeQuotedValues.no,
|
NormalizeQuotedValues normalizeQuotedValues = NormalizeQuotedValues.no,
|
||||||
SupportEqualsSeparator supportEqualsSeparator = SupportEqualsSeparator.no,
|
SupportEqualsSeparator supportEqualsSeparator = SupportEqualsSeparator.no,
|
||||||
SupportColonSeparator supportColonSeparator = SupportColonSeparator.no,
|
SupportColonSeparator supportColonSeparator = SupportColonSeparator.no,
|
||||||
SupportKeysWithoutValues supportKeysWithoutValues = SupportKeysWithoutValues.no
|
SupportKeysWithoutValues supportKeysWithoutValues = SupportKeysWithoutValues.no,
|
||||||
|
SupportMultilineValues supportMultilineValues = SupportMultilineValues.no
|
||||||
) : ConfigFactory {
|
) : ConfigFactory {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -57,6 +59,9 @@ class KeyValueConfigFactory(
|
||||||
auto lines = contents.lineSplitter().array;
|
auto lines = contents.lineSplitter().array;
|
||||||
auto properties = new ConfigDictionary();
|
auto properties = new ConfigDictionary();
|
||||||
auto section = "";
|
auto section = "";
|
||||||
|
string key = null;
|
||||||
|
string valueBuffer = "";
|
||||||
|
|
||||||
foreach (size_t index, string line; lines) {
|
foreach (size_t index, string line; lines) {
|
||||||
auto processedLine = line;
|
auto processedLine = line;
|
||||||
|
|
||||||
|
@ -75,7 +80,9 @@ class KeyValueConfigFactory(
|
||||||
|
|
||||||
processedLine = processedLine.strip;
|
processedLine = processedLine.strip;
|
||||||
|
|
||||||
if (supportSections && processedLine.startsWith('[') && processedLine.endsWith(']')) {
|
if (supportSections &&
|
||||||
|
key is null &&
|
||||||
|
processedLine.startsWith('[') && processedLine.endsWith(']')) {
|
||||||
auto parsedSection = processedLine[1 .. $ - 1];
|
auto parsedSection = processedLine[1 .. $ - 1];
|
||||||
if (parsedSection.startsWith('.')) {
|
if (parsedSection.startsWith('.')) {
|
||||||
section ~= parsedSection;
|
section ~= parsedSection;
|
||||||
|
@ -90,31 +97,45 @@ class KeyValueConfigFactory(
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
char keyValueSplitter;
|
string value;
|
||||||
if (supportEqualsSeparator && processedLine.indexOf('=') >= 0) {
|
|
||||||
keyValueSplitter = '=';
|
if (key is null) {
|
||||||
} else if (supportColonSeparator && processedLine.indexOf(':') >= 0) {
|
char keyValueSplitter;
|
||||||
keyValueSplitter = ':';
|
if (supportEqualsSeparator && processedLine.indexOf('=') >= 0) {
|
||||||
|
keyValueSplitter = '=';
|
||||||
|
} else if (supportColonSeparator && processedLine.indexOf(':') >= 0) {
|
||||||
|
keyValueSplitter = ':';
|
||||||
|
}
|
||||||
|
|
||||||
|
auto parts = processedLine.split(keyValueSplitter);
|
||||||
|
|
||||||
|
enforce!ConfigCreationException(parts.length <= 2, "Line has too many equals signs and cannot be parsed (L" ~ index
|
||||||
|
.to!string ~ "): " ~ processedLine);
|
||||||
|
enforce!ConfigCreationException(supportKeysWithoutValues || parts.length == 2, "Missing value assignment (L" ~ index
|
||||||
|
.to!string ~ "): " ~ processedLine);
|
||||||
|
|
||||||
|
key = [section, parts[0].strip].join('.');
|
||||||
|
value = supportKeysWithoutValues && parts.length == 1 ? "" : parts[1].strip;
|
||||||
|
} else {
|
||||||
|
value = processedLine;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto parts = processedLine.split(keyValueSplitter);
|
if (supportMultilineValues && value.endsWith('\\')) {
|
||||||
|
valueBuffer ~= value[0 .. $ - 1];
|
||||||
enforce!ConfigCreationException(parts.length <= 2, "Line has too many equals signs and cannot be parsed (L" ~ index
|
continue;
|
||||||
.to!string ~ "): " ~ processedLine);
|
}
|
||||||
enforce!ConfigCreationException(supportKeysWithoutValues || parts.length == 2, "Missing value assignment (L" ~ index
|
|
||||||
.to!string ~ "): " ~ processedLine);
|
|
||||||
|
|
||||||
auto value = supportKeysWithoutValues && parts.length == 1 ? "" : parts[1].strip;
|
|
||||||
|
|
||||||
|
auto fullValue = valueBuffer ~ value;
|
||||||
if (normalizeQuotedValues &&
|
if (normalizeQuotedValues &&
|
||||||
value.length > 1 &&
|
fullValue.length > 1 &&
|
||||||
(value.startsWith('"') || value.startsWith('\'')) &&
|
(fullValue.startsWith('"') || fullValue.startsWith('\'')) &&
|
||||||
(value.endsWith('"') || value.endsWith('\''))) {
|
(fullValue.endsWith('"') || fullValue.endsWith('\''))) {
|
||||||
value = value[1 .. $ - 1];
|
fullValue = fullValue[1 .. $ - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
auto key = [section, parts[0].strip].join('.');
|
properties.set(key, fullValue);
|
||||||
properties.set(key, value);
|
key = null;
|
||||||
|
valueBuffer = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
return properties;
|
return properties;
|
||||||
|
@ -133,7 +154,8 @@ version (unittest) {
|
||||||
NormalizeQuotedValues.no,
|
NormalizeQuotedValues.no,
|
||||||
SupportEqualsSeparator.yes,
|
SupportEqualsSeparator.yes,
|
||||||
SupportColonSeparator.no,
|
SupportColonSeparator.no,
|
||||||
SupportKeysWithoutValues.no
|
SupportKeysWithoutValues.no,
|
||||||
|
SupportMultilineValues.no
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -325,4 +347,55 @@ version (unittest) {
|
||||||
assertThrown!ConfigCreationException(new KeyValueConfigFactory!()().parseConfig("a=b")); // No separator is configured
|
assertThrown!ConfigCreationException(new KeyValueConfigFactory!()().parseConfig("a=b")); // No separator is configured
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@("Support multiline values")
|
||||||
|
unittest {
|
||||||
|
auto config = new KeyValueConfigFactory!(
|
||||||
|
SupportHashtagComments.yes,
|
||||||
|
SupportSemicolonComments.no,
|
||||||
|
SupportExclamationComments.no,
|
||||||
|
SupportSections.yes,
|
||||||
|
NormalizeQuotedValues.yes,
|
||||||
|
SupportEqualsSeparator.yes,
|
||||||
|
SupportColonSeparator.no,
|
||||||
|
SupportKeysWithoutValues.yes,
|
||||||
|
SupportMultilineValues.yes
|
||||||
|
)().parseConfig("
|
||||||
|
sentence = the quick \\
|
||||||
|
'brown fox' \\ # comments
|
||||||
|
[jump]\\
|
||||||
|
\\
|
||||||
|
ed over \\ #are not part of the
|
||||||
|
the lazy \\
|
||||||
|
'[dog]' #value
|
||||||
|
|
||||||
|
not part of the sentence
|
||||||
|
");
|
||||||
|
|
||||||
|
assert(config.get("sentence") == "the quick 'brown fox' [jump]ed over the lazy '[dog]'");
|
||||||
|
}
|
||||||
|
|
||||||
|
@("Normalize multiline values with quotes")
|
||||||
|
unittest {
|
||||||
|
auto config = new KeyValueConfigFactory!(
|
||||||
|
SupportHashtagComments.no,
|
||||||
|
SupportSemicolonComments.no,
|
||||||
|
SupportExclamationComments.no,
|
||||||
|
SupportSections.no,
|
||||||
|
NormalizeQuotedValues.yes,
|
||||||
|
SupportEqualsSeparator.yes,
|
||||||
|
SupportColonSeparator.no,
|
||||||
|
SupportKeysWithoutValues.no,
|
||||||
|
SupportMultilineValues.yes
|
||||||
|
)().parseConfig("
|
||||||
|
doubles = \"Well then there I was \\
|
||||||
|
doing my thing.\"
|
||||||
|
singles = 'When suddenly \\
|
||||||
|
a shark bit me \\
|
||||||
|
from the sky'
|
||||||
|
");
|
||||||
|
|
||||||
|
assert(config.get("doubles") == "Well then there I was doing my thing.");
|
||||||
|
assert(config.get("singles") == "When suddenly a shark bit me from the sky");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue