dlangui/3rdparty/inilike/package.d

194 lines
5.8 KiB
D

/**
* Reading and writing ini-like files used in some Unix systems and Freedesktop specifications.
* ini-like is informal name for the file format that look like this:
* ---
# Comment
[Group name]
Key=Value
# Comment inside group
AnotherKey=Value
[Another group]
Key=English value
Key[fr_FR]=Francais value
* ---
* Authors:
* $(LINK2 https://github.com/FreeSlave, Roman Chistokhodov)
* Copyright:
* Roman Chistokhodov, 2015-2016
* License:
* $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
* See_Also:
* $(LINK2 http://standards.freedesktop.org/desktop-entry-spec/latest/index.html, Desktop Entry Specification)
*/
module inilike;
public import inilike.common;
public import inilike.range;
public import inilike.file;
unittest
{
import std.exception;
final class DesktopEntry : IniLikeGroup
{
this() {
super("Desktop Entry");
}
protected:
@trusted override void validateKey(string key, string value) const {
if (!isValidDesktopFileKey(key)) {
throw new IniLikeEntryException("key is invalid", groupName(), key, value);
}
}
}
final class DesktopFile : IniLikeFile
{
//Options to manage .ini like file reading
static struct DesktopReadOptions
{
IniLikeFile.ReadOptions baseOptions;
alias baseOptions this;
bool skipExtensionGroups;
bool ignoreUnknownGroups;
bool skipUnknownGroups;
}
@trusted this(IniLikeReader)(IniLikeReader reader, DesktopReadOptions options = DesktopReadOptions.init)
{
_options = options;
super(reader, null, options.baseOptions);
enforce(_desktopEntry !is null, new IniLikeReadException("No \"Desktop Entry\" group", 0));
}
@safe override bool removeGroup(string groupName) nothrow {
if (groupName == "Desktop Entry") {
return false;
}
return super.removeGroup(groupName);
}
protected:
@trusted override IniLikeGroup createGroupByName(string groupName)
{
if (groupName == "Desktop Entry") {
_desktopEntry = new DesktopEntry();
return _desktopEntry;
} else if (groupName.startsWith("X-")) {
if (_options.skipExtensionGroups) {
return null;
}
return createEmptyGroup(groupName);
} else {
if (_options.ignoreUnknownGroups) {
if (_options.skipUnknownGroups) {
return null;
} else {
return createEmptyGroup(groupName);
}
} else {
throw new IniLikeException("Unknown group");
}
}
}
inout(DesktopEntry) desktopEntry() inout {
return _desktopEntry;
}
private:
DesktopEntry _desktopEntry;
DesktopReadOptions _options;
}
string contents =
`# First comment
[Desktop Entry]
Key=Value
# Comment in group`;
DesktopFile.DesktopReadOptions options;
auto df = new DesktopFile(iniLikeStringReader(contents), options);
assert(!df.removeGroup("Desktop Entry"));
assert(!df.removeGroup("NonExistent"));
assert(df.group("Desktop Entry") !is null);
assert(df.desktopEntry() !is null);
assert(equal(df.desktopEntry().byIniLine(), [IniLikeLine.fromKeyValue("Key", "Value"), IniLikeLine.fromComment("# Comment in group")]));
assert(equal(df.leadingComments(), ["# First comment"]));
assertThrown(df.desktopEntry().writeEntry("$Invalid", "Valid value"));
IniLikeEntryException entryException;
try {
df.desktopEntry().writeEntry("$Invalid", "Valid value");
} catch(IniLikeEntryException e) {
entryException = e;
}
assert(entryException !is null);
df.desktopEntry().writeEntry("$Invalid", "Valid value", IniLikeGroup.InvalidKeyPolicy.save);
assert(df.desktopEntry().value("$Invalid") == "Valid value");
assert(df.desktopEntry().appendValue("Another$Invalid", "Valid value", IniLikeGroup.InvalidKeyPolicy.skip).isNull());
assert(df.desktopEntry().setValue("Another$Invalid", "Valid value", IniLikeGroup.InvalidKeyPolicy.skip) is null);
assert(df.desktopEntry().value("Another$Invalid") is null);
contents =
`[X-SomeGroup]
Key=Value`;
auto thrown = collectException!IniLikeReadException(new DesktopFile(iniLikeStringReader(contents)));
assert(thrown !is null);
assert(thrown.lineNumber == 0);
contents =
`[Desktop Entry]
Valid=Key
$=Invalid`;
thrown = collectException!IniLikeReadException(new DesktopFile(iniLikeStringReader(contents)));
assert(thrown !is null);
assert(thrown.entryException !is null);
assert(thrown.entryException.key == "$");
assert(thrown.entryException.value == "Invalid");
options = DesktopFile.DesktopReadOptions.init;
options.invalidKeyPolicy = IniLikeGroup.InvalidKeyPolicy.skip;
assertNotThrown(new DesktopFile(iniLikeStringReader(contents), options));
contents =
`[Desktop Entry]
Name=Name
[Unknown]
Key=Value`;
assertThrown(new DesktopFile(iniLikeStringReader(contents)));
options = DesktopFile.DesktopReadOptions.init;
options.ignoreUnknownGroups = true;
assertNotThrown(df = new DesktopFile(iniLikeStringReader(contents), options));
assert(df.group("Unknown") !is null);
options.skipUnknownGroups = true;
df = new DesktopFile(iniLikeStringReader(contents), options);
assert(df.group("Unknown") is null);
contents =
`[Desktop Entry]
Name=Name1
[X-Extension]
Name=Name2`;
options = DesktopFile.DesktopReadOptions.init;
options.skipExtensionGroups = true;
df = new DesktopFile(iniLikeStringReader(contents), options);
assert(df.group("X-Extension") is null);
}