From 089e42a2bfac910b571f92a645c5de1143ef139d Mon Sep 17 00:00:00 2001 From: Mike Bierlee Date: Tue, 11 Oct 2022 21:07:08 +0300 Subject: [PATCH] Support ini-like sections in keyvalue config --- source/mirage/java.d | 5 ++-- source/mirage/keyvalue.d | 65 ++++++++++++++++++++++++++++++---------- source/mirage/package.d | 3 +- 3 files changed, 55 insertions(+), 18 deletions(-) diff --git a/source/mirage/java.d b/source/mirage/java.d index 9e84684..7e99e5a 100644 --- a/source/mirage/java.d +++ b/source/mirage/java.d @@ -12,14 +12,15 @@ module mirage.java; import mirage.config : ConfigDictionary; -import mirage.keyvalue : KeyValueConfigFactory, SupportHashtagComments, SupportSemicolonComments; +import mirage.keyvalue : KeyValueConfigFactory, SupportHashtagComments, SupportSemicolonComments, SupportSections; /** * Creates configuration files from Java properties. */ class JavaPropertiesFactory : KeyValueConfigFactory!( SupportHashtagComments.yes, - SupportSemicolonComments.no + SupportSemicolonComments.no, + SupportSections.no ) { } diff --git a/source/mirage/keyvalue.d b/source/mirage/keyvalue.d index cef42f2..7dca02f 100644 --- a/source/mirage/keyvalue.d +++ b/source/mirage/keyvalue.d @@ -13,14 +13,15 @@ module mirage.keyvalue; import mirage.config : ConfigFactory, ConfigDictionary, ConfigNode, ValueNode, ObjectNode, ConfigCreationException; -import std.string : lineSplitter, strip, startsWith, split, indexOf; +import std.string : lineSplitter, strip, startsWith, endsWith, split, indexOf; import std.array : array; import std.exception : enforce; import std.conv : to; import std.typecons : Flag; -alias SupportHashtagComments = Flag!"supportHashtagComment"; -alias SupportSemicolonComments = Flag!"supportSemicolonComments"; +alias SupportHashtagComments = Flag!"SupportHashtagComments"; +alias SupportSemicolonComments = Flag!"SupportSemicolonComments"; +alias SupportSections = Flag!"SupportSections"; /** * A generic reusable key/value config factory that can be configured to parse @@ -28,7 +29,8 @@ alias SupportSemicolonComments = Flag!"supportSemicolonComments"; */ class KeyValueConfigFactory( SupportHashtagComments supportHashtagComments = SupportHashtagComments.no, - SupportSemicolonComments supportSemicolonComments = SupportSemicolonComments.no + SupportSemicolonComments supportSemicolonComments = SupportSemicolonComments.no, + SupportSections supportSections = SupportSections.no ) : ConfigFactory { /** * Parse a configuration file following the configured key/value conventions. @@ -41,33 +43,41 @@ class KeyValueConfigFactory( enforce!ConfigCreationException(contents !is null, "Contents cannot be null."); auto lines = contents.lineSplitter().array; auto properties = new ConfigDictionary(); + auto section = ""; foreach (size_t index, string line; lines) { - auto normalizedLine = line; + auto processedLine = line; if (supportHashtagComments) { - auto commentPosition = normalizedLine.indexOf('#'); + auto commentPosition = processedLine.indexOf('#'); if (commentPosition >= 0) { - normalizedLine = normalizedLine[0 .. commentPosition]; + processedLine = processedLine[0 .. commentPosition]; } } if (supportSemicolonComments) { - auto commentPosition = normalizedLine.indexOf(';'); + auto commentPosition = processedLine.indexOf(';'); if (commentPosition >= 0) { - normalizedLine = normalizedLine[0 .. commentPosition]; + processedLine = processedLine[0 .. commentPosition]; } } - normalizedLine = normalizedLine.strip; - if (normalizedLine.length == 0) { + processedLine = processedLine.strip; + + if (supportSections && processedLine.startsWith('[') && processedLine.endsWith(']')) { + section = processedLine[1 .. $ - 1] ~ '.'; continue; } - auto parts = normalizedLine.split('='); + if (processedLine.length == 0) { + continue; + } + + auto parts = processedLine.split('='); enforce!ConfigCreationException(parts.length <= 2, "Line has too many equals signs and cannot be parsed (L" ~ index - .to!string ~ "): " ~ normalizedLine); - enforce!ConfigCreationException(parts.length == 2, "Missing value assignment (L" ~ index.to!string ~ "): " ~ normalizedLine); - properties.set(parts[0].strip, parts[1].strip); + .to!string ~ "): " ~ processedLine); + enforce!ConfigCreationException(parts.length == 2, "Missing value assignment (L" ~ index.to!string ~ "): " ~ processedLine); + + properties.set(section ~ parts[0].strip, parts[1].strip); } return properties; @@ -156,4 +166,29 @@ version (unittest) { assert(config.get("server") == "localhost"); assert(config.get("port") == "9876"); } + + @("Support sections when enabled") + unittest { + auto config = new KeyValueConfigFactory!(SupportHashtagComments.no, + SupportSemicolonComments.yes, + SupportSections.yes)().parseConfig(" + applicationName = test me! + + [server] + host=localhost + port=2873 + + [server.middleware] ; Stuff that handles the http protocol + protocolServer = netty + + [database.driver] + id=PostgresDriver + "); + + assert(config.get("applicationName") == "test me!"); + assert(config.get("server.host") == "localhost"); + assert(config.get("server.port") == "2873"); + assert(config.get("server.middleware.protocolServer") == "netty"); + assert(config.get("database.driver.id") == "PostgresDriver"); + } } diff --git a/source/mirage/package.d b/source/mirage/package.d index 554d096..49f840c 100644 --- a/source/mirage/package.d +++ b/source/mirage/package.d @@ -10,5 +10,6 @@ module mirage; public import mirage.config; +public import mirage.java; public import mirage.json; -public import mirage.java; \ No newline at end of file +public import mirage.keyvalue; \ No newline at end of file