module substitution; import std.file : slurp; import std.meta : AliasSeq; import std.traits : Parameters; version (unittest) { import unit_threaded; } public: /*********************************** * Loads a substitution dictonary from a file. */ void loadSubstitutionFile(alias slurpFun = slurp)(string fileName) if (is(Parameters!(slurpFun!(string, string)) == AliasSeq!(string, const char[]))) { import std.algorithm.iteration : each; map = (string[string]).init; slurpFun!(string, string)(fileName, `"%s" = "%s"`).each!(pair => map[pair[0]] = pair[1]); } /// @safe unittest { import std.typecons : Tuple, tuple; static Tuple!(string, string)[] mockSlurpEmpty(Type1, Type2)(string filename, in char[] format) { return []; } loadSubstitutionFile!mockSlurpEmpty(""); map.length.shouldEqual(0); static Tuple!(string, string)[] mockSlurpEmptyEntry(Type1, Type2)(string filename, in char[] format) { return [tuple("", "")]; } loadSubstitutionFile!mockSlurpEmptyEntry(""); "".shouldBeIn(map); map.length.shouldEqual(1); map[""].shouldEqual(""); static Tuple!(string, string)[] mockSlurpSingleEntry(Type1, Type2)(string filename, in char[] format) { return [tuple("foo", "bar")]; } loadSubstitutionFile!mockSlurpSingleEntry(""); "foo".shouldBeIn(map); map.length.shouldEqual(1); map["foo"].shouldEqual("bar"); static Tuple!(string, string)[] mockSlurpMultipleEntries(Type1, Type2)( string filename, in char[] format) { return [tuple("", ""), tuple("0", "1"), tuple("Text in", "wird durch diesen ersetzt")]; } loadSubstitutionFile!mockSlurpMultipleEntries(""); "".shouldBeIn(map); "0".shouldBeIn(map); "Text in".shouldBeIn(map); map.length.shouldEqual(3); map[""].shouldEqual(""); map["0"].shouldEqual("1"); map["Text in"].shouldEqual("wird durch diesen ersetzt"); } /*********************************** * Substitutes a string with its corresponding replacement, if one is available. * Otherwise just returns the original string. */ auto substitute(string s) @safe nothrow { return s in map ? map[s] : s; } /// @safe unittest { map[""] = ""; "".substitute.shouldEqual(""); map["a"] = "b"; "a".substitute.shouldEqual("b"); map["Regensburg Danziger Freiheit"] = "Danziger Freiheit"; "Regensburg Danziger Freiheit".substitute.shouldEqual("Danziger Freiheit"); map["Regensburg Danziger Freiheit"] = "Anderer Test"; "Regensburg Danziger Freiheit".substitute.shouldEqual("Anderer Test"); "z".substitute.shouldEqual("z"); "Regensburg Hauptbahnhof".substitute.shouldEqual("Regensburg Hauptbahnhof"); } private: string[string] map;