Construct empty IniLikeFile, i.e. without any groups or values
Read from file.
Read from range of inilike.range.IniLikeReader. Note: All exceptions thrown within constructor are turning into IniLikeReadException.
Add comment for group. This function is called only in constructor and can be reimplemented in derived classes.
Create new group using groupName.
Add key/value pair for group. This function is called only in constructor and can be reimplemented in derived classes.
Add leading comment. This will be appended to the list of leadingComments. Note: # will be prepended automatically if line is not empty and does not have # at the start. The last new line character will be removed if present. Others will be replaced with whitespaces.
Range of groups in order how they were defined in file.
Remove all coments met before groups.
Create iniLikeGroup by groupName. This function is called only in constructor and can be reimplemented in derived classes, e.g. to insert additional checks or create specific derived class depending on groupName. Returned value is later passed to addCommentForGroup and addKeyValueForGroup methods as currentGroup. Reimplemented method also is allowed to return null. Default implementation just returns empty IniLikeGroup with name set to groupName.
File path where the object was loaded from.
Get group by name.
Leading comments.
Prepend leading comment (e.g. for setting shebang line).
Remove group by name. Do nothing if group with such name does not exist.
Use Output range or delegate to retrieve strings line by line. Those strings can be written to the file or be showed in text area. Note: returned strings don't have trailing newline character.
Save object to the file using .ini-like format.
Save object to string using .ini like format.
Can be used in derived classes to create instance of IniLikeGroup.
1 import std.file; 2 import std.path; 3 4 string contents = 5 `# The first comment 6 [First Entry] 7 # Comment 8 GenericName=File manager 9 GenericName[ru]=Файловый менеджер 10 NeedUnescape=yes\\i\tneed 11 NeedUnescape[ru]=да\\я\tнуждаюсь 12 # Another comment 13 [Another Group] 14 Name=Commander 15 Comment=Manage files 16 # The last comment`; 17 18 auto ilf = new IniLikeFile(iniLikeStringReader(contents), "contents.ini"); 19 assert(ilf.fileName() == "contents.ini"); 20 assert(equal(ilf.leadingComments(), ["# The first comment"])); 21 assert(ilf.group("First Entry")); 22 assert(ilf.group("Another Group")); 23 assert(ilf.saveToString() == contents); 24 25 string tempFile = buildPath(tempDir(), "inilike-unittest-tempfile"); 26 try { 27 assertNotThrown!IniLikeReadException(ilf.saveToFile(tempFile)); 28 auto fileContents = cast(string)std.file.read(tempFile); 29 static if( __VERSION__ < 2067 ) { 30 assert(equal(fileContents.splitLines, contents.splitLines), "Contents should be preserved as is"); 31 } else { 32 assert(equal(fileContents.lineSplitter, contents.lineSplitter), "Contents should be preserved as is"); 33 } 34 35 IniLikeFile filf; 36 assertNotThrown!IniLikeReadException(filf = new IniLikeFile(tempFile)); 37 assert(filf.fileName() == tempFile); 38 remove(tempFile); 39 } catch(Exception e) { 40 //environmental error in unittests 41 } 42 43 auto firstEntry = ilf.group("First Entry"); 44 45 assert(!firstEntry.contains("NonExistent")); 46 assert(firstEntry.contains("GenericName")); 47 assert(firstEntry.contains("GenericName[ru]")); 48 assert(firstEntry["GenericName"] == "File manager"); 49 assert(firstEntry.value("GenericName") == "File manager"); 50 51 assert(firstEntry.value("NeedUnescape") == `yes\\i\tneed`); 52 assert(firstEntry.readEntry("NeedUnescape") == "yes\\i\tneed"); 53 assert(firstEntry.localizedValue("NeedUnescape", "ru") == `да\\я\tнуждаюсь`); 54 assert(firstEntry.readEntry("NeedUnescape", "ru") == "да\\я\tнуждаюсь"); 55 56 firstEntry.writeEntry("NeedEscape", "i\rneed\nescape"); 57 assert(firstEntry.value("NeedEscape") == `i\rneed\nescape`); 58 firstEntry.writeEntry("NeedEscape", "мне\rнужно\nэкранирование"); 59 assert(firstEntry.localizedValue("NeedEscape", "ru") == `мне\rнужно\nэкранирование`); 60 61 firstEntry["GenericName"] = "Manager of files"; 62 assert(firstEntry["GenericName"] == "Manager of files"); 63 firstEntry["Authors"] = "Unknown"; 64 assert(firstEntry["Authors"] == "Unknown"); 65 66 assert(firstEntry.localizedValue("GenericName", "ru") == "Файловый менеджер"); 67 firstEntry.setLocalizedValue("GenericName", "ru", "Менеджер файлов"); 68 assert(firstEntry.localizedValue("GenericName", "ru") == "Менеджер файлов"); 69 firstEntry.setLocalizedValue("Authors", "ru", "Неизвестны"); 70 assert(firstEntry.localizedValue("Authors", "ru") == "Неизвестны"); 71 72 firstEntry.removeEntry("GenericName"); 73 assert(!firstEntry.contains("GenericName")); 74 firstEntry.removeEntry("GenericName", "ru"); 75 assert(!firstEntry.contains("GenericName[ru]")); 76 firstEntry["GenericName"] = "File Manager"; 77 assert(firstEntry["GenericName"] == "File Manager"); 78 79 assert(ilf.group("Another Group")["Name"] == "Commander"); 80 assert(equal(ilf.group("Another Group").byKeyValue(), [ keyValueTuple("Name", "Commander"), keyValueTuple("Comment", "Manage files") ])); 81 82 assert(ilf.group("Another Group").appendComment("The lastest comment")); 83 assert(ilf.group("Another Group").prependComment("The first comment")); 84 85 assert(equal( 86 ilf.group("Another Group").byIniLine(), 87 [IniLikeLine.fromComment("#The first comment"), IniLikeLine.fromKeyValue("Name", "Commander"), IniLikeLine.fromKeyValue("Comment", "Manage files"), IniLikeLine.fromComment("# The last comment"), IniLikeLine.fromComment("#The lastest comment")] 88 )); 89 90 assert(equal(ilf.byGroup().map!(g => g.groupName), ["First Entry", "Another Group"])); 91 92 assert(!ilf.removeGroup("NonExistent Group")); 93 94 assert(ilf.removeGroup("Another Group")); 95 assert(!ilf.group("Another Group")); 96 assert(equal(ilf.byGroup().map!(g => g.groupName), ["First Entry"])); 97 98 ilf.addGroup("Another Group"); 99 assert(ilf.group("Another Group")); 100 assert(ilf.group("Another Group").byIniLine().empty); 101 assert(ilf.group("Another Group").byKeyValue().empty); 102 103 ilf.addGroup("Other Group"); 104 assert(equal(ilf.byGroup().map!(g => g.groupName), ["First Entry", "Another Group", "Other Group"])); 105 106 assertThrown!IniLikeException(ilf.addGroup("")); 107 108 const IniLikeFile cilf = ilf; 109 static assert(is(typeof(cilf.byGroup()))); 110 static assert(is(typeof(cilf.group("First Entry").byKeyValue()))); 111 static assert(is(typeof(cilf.group("First Entry").byIniLine()))); 112 113 contents = 114 `[Group] 115 GenericName=File manager 116 [Group] 117 GenericName=Commander`; 118 119 auto shouldThrow = collectException!IniLikeReadException(new IniLikeFile(iniLikeStringReader(contents), "config.ini")); 120 assert(shouldThrow !is null, "Duplicate groups should throw"); 121 assert(shouldThrow.lineNumber == 3); 122 assert(shouldThrow.lineIndex == 2); 123 assert(shouldThrow.fileName == "config.ini"); 124 125 contents = 126 `[Group] 127 Key=Value1 128 Key=Value2`; 129 130 shouldThrow = collectException!IniLikeReadException(new IniLikeFile(iniLikeStringReader(contents))); 131 assert(shouldThrow !is null, "Duplicate key should throw"); 132 assert(shouldThrow.lineNumber == 3); 133 134 contents = 135 `[Group] 136 Key=Value 137 =File manager`; 138 139 shouldThrow = collectException!IniLikeReadException(new IniLikeFile(iniLikeStringReader(contents))); 140 assert(shouldThrow !is null, "Empty key should throw"); 141 assert(shouldThrow.lineNumber == 3); 142 143 contents = 144 `[Group] 145 #Comment 146 Valid=Key 147 NotKeyNotGroupNotComment`; 148 149 shouldThrow = collectException!IniLikeReadException(new IniLikeFile(iniLikeStringReader(contents))); 150 assert(shouldThrow !is null, "Invalid entry should throw"); 151 assert(shouldThrow.lineNumber == 4); 152 153 contents = 154 `#Comment 155 NotComment 156 [Group] 157 Valid=Key`; 158 shouldThrow = collectException!IniLikeReadException(new IniLikeFile(iniLikeStringReader(contents))); 159 assert(shouldThrow !is null, "Invalid comment should throw"); 160 assert(shouldThrow.lineNumber == 2);
Ini-like file.