TINI
TIni is a simple-to-use .ini string parser & printer made in Haxe. This is inspired by JWambaugh's TJSON.
It's entirely cross-platform and should work on all platforms since it relies on string manipulation.
TIni was made as a simple parser in order to educate people wanting to learn about parsers (like hscript or tjson). While it's nowhere near as complex as something like hscript, it serves as a good starting ground for people wanting to learn about it.
Usage
Install TINI through Haxelib by running the following in the command line:
haxelib install tini
You can also install it through Github:
haxelib git tini https://github.com/TBar09/TINI.git
To use the haxelib in a project:
- For Haxe projects, use -lib tini.
- For OpenFL/Lime projects, use <haxelib name="tini"/>.
Here is basic usage:
; My INI file.ini
myVar="Hello world!!"
myStr=Hello world!
myFloat = 10.254
[MyGroup]
myGroupedStr="Hi, I'm in a group!!"
myBool = true
// Main.hx
import tini.TINI;
function main() {
var myParser:IniParser = new IniParser(TINI.defaultRules);
//You can also run TINI.parse() instead, which automatically parses the string and returns it's object.
var myObject:Dynamic = myParser.parse(sys.io.File.getContent("My INI file.ini"));
trace(myObject.myStr); // Hello world!
trace(myObject.MyGroup.myBool); //true
trace(Reflect.fields(myObject)); //["myVar", "myStr", "myFloat", "MyGroup"]
}
There is also an ini printer too:
// Main.hx
import tini.TINI;
function main() {
var myObject = {
myStr: "Hello world!!",
MyGroup: {
myBool: true
}
}
//Just like with the parser, there is also a shorter TINI.stringify() method.
var myPrinter:IniPrinter = new IniPrinter(TINI.defaultRules);
/*
; Generated by the TIni library
myStr="Hello world!!"
[MyGroup]
myBool=true
*/
trace(myPrinter.stringify(myObject));
}
Features
While TIni is a barebones ini file parser, it does have some features that make it stand out from other ini parsers.
Array & Maps
Ini files can declare arrays and string maps:
; My INI file.ini
myArr=[10.2, true, ["Hello", "world", "!!"]]
myStringMap=["one" => "Hello", "two" => "World"]
myIntMap=[1 => "Hello", 2 => "World", 3 => "!!!"]
Anonymous Structures
Ini files can declare full anonymous structures:
; My INI file.ini
myStruct={hello: "World", nestedStruct: {world: "Hello"}}
[!NOTE] Ini-declared structures are parser only! Trying to use nested structures with the ini printer will only create an ini group instead of a structure.
Saving Variables
Values inside of an ini file can be brought up again later in the file as a variable:
; My INI file.ini
myVar=10.2
[My Group]
; This saves as 10.2
myOtherVar=myVar
[!NOTE] Only the variable itself is allowed, so doing calculations like
myOtherVar=myVar + 10isn't supported. This is a limitation for now.
Classes & Enums
Ini files can save classes and enums into itself as a string, which can later be parsed back into what it was originally:
; My INI file.ini
myEnum=__ini_enm__Vehicle.TRUCK
; Enums with arguments work too!
myOtherEnum=__ini_enm__Vehicle.CUSTOM("My car", 150, true)
// Main.hx
import tini.TINI;
enum Vehicle {
CAR;
TRUCK;
CUSTOM(name:String, mph:Int, isCool:Bool);
}
function main() {
var obj:Dynamic = TINI.parse(sys.io.File.getContent("My INI file.ini"));
switch(obj.myOtherEnum) {
case CAR:
trace("This is a car");
case TRUCK:
trace("This is a truck");
CUSTOM(name, mph, isCool):
trace('This is a $name that can go ${Std.string(mph)} miles per-hour!');
}
}
__root__ Keyword
If a group name is called __root__, then the current group will be dropped and any further assign lines
will be written to the root structure itself and not inside a group.
; My INI file.ini
myVar=2
; myGroupedVar will be inside of group "My Group", while myRootVar will not.
[My Group]
myGroupedVar=10
[__root__]
myRootVar=20
Ini Rules
The Ini parser & printer supports custom rules that can change how a string/parser is parsed/printed:
// My INI file.ini
myVar>10.2
// Main.hx
import tini.TINI;
function main() {
var iniParser:IniParser = new IniParser({
ASSIGN_KEY: ">",
COMMENT_KEY: "//",
ARGUMENT_DELIMITER: ",",
ANON_STRUCTURES_ALLOWED: true,
CLASSES_ALLOWED: true,
ENUM_ALLOWED: true,
CLASS_KEY: "__ini_cls__",
ENUM_KEY: "__ini_enm__"
});
var retObj:Dynamic = iniParser.parse(sys.io.File.getContent("My INI file.ini"));
trace(retObj.myVar); //10.2
}
The first argument of both the IniParser and IniPrinter is a structure with custom rules. If it is left blank then the default rules in TINI.hx are used.
[!NOTE] For the static methods
TINI.parseandTINI.stringify, the second argument is the custom rules.
Below is a full list of rules that you can change:
| Rule name | Default value | Function |
|---|---|---|
ASSIGN_KEY | = | The key that will tell the parser where to split the key and the value in a key->value assign line. |
COMMENT_KEY | ; | The key that will tell the parser if the line is a comment. |
ARGUMENT_DELIMITER | , | The key that will split arguments in a string class or enum. |
ROOT_KEYWORD_ALLOWED | true | Whether the "root" keyword can be used in groups. |
ANON_STRUCTURES_ALLOWED | true | Whether anonymous structure parsing should be allowed. |
CLASSES_ALLOWED | true | Whether class instance parsing should be allowed. |
CLASS_KEY | __ini_cls__ | The prefix string that tells the parser that the line is a class instance. |
ENUM_ALLOWED | true | Whether enum instance parsing should be allowed. |
ENUM_KEY | __ini_enm__ | The prefix string that tells the parser that the line is an enum instance. |
Limitations
Currently, TIni has a few limits:
- No sub-groups, so you can't do
[My Group.subgroup]. This is planned for a future version. - No in-line comments (
myVar=10.2 ;I am a comment). This is planned for a future version.