IniLikeFile

Ini-like file.

Constructors

this
this()

Construct empty IniLikeFile, i.e. without any groups or values

this
this(string fileName)

Read from file.

this
this(IniLikeReader reader, string fileName)

Read from range of inilike.range.IniLikeReader. Note: All exceptions thrown within constructor are turning into IniLikeReadException.

Members

Functions

addCommentForGroup
void addCommentForGroup(string comment, IniLikeGroup currentGroup, string groupName)

Add comment for group. This function is called only in constructor and can be reimplemented in derived classes.

addGroup
IniLikeGroup addGroup(string groupName)

Create new group using groupName.

addKeyValueForGroup
void addKeyValueForGroup(string key, string value, IniLikeGroup currentGroup, string groupName)

Add key/value pair for group. This function is called only in constructor and can be reimplemented in derived classes.

appendLeadingComment
string appendLeadingComment(string line)

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.

byGroup
auto byGroup()

Range of groups in order how they were defined in file.

clearLeadingComments
void clearLeadingComments()

Remove all coments met before groups.

createGroup
IniLikeGroup createGroup(string groupName)

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.

fileName
string fileName()

File path where the object was loaded from.

group
inout(IniLikeGroup) group(string groupName)

Get group by name.

leadingComments
auto leadingComments()

Leading comments.

prependLeadingComment
string prependLeadingComment(string line)

Prepend leading comment (e.g. for setting shebang line).

removeGroup
bool removeGroup(string groupName)

Remove group by name. Do nothing if group with such name does not exist.

save
void save(OutRange sink)

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.

saveToFile
void saveToFile(string fileName)

Save object to the file using .ini-like format.

saveToString
string saveToString()

Save object to string using .ini like format.

Static functions

createEmptyGroup
createEmptyGroup(string groupName)

Can be used in derived classes to create instance of IniLikeGroup.

Examples

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);

Meta