ini - Read and write INI configuration files

INI files are simple text files with a basic structure composed of sections, properties and values used to store configuration parameters.

Here's an example from the package.ini of this package:

import ini

var package_ini = """
[package]
name=ini
desc=Read and write INI configuration files.
[upstream]
git=https://github.com/nitlang/nit.git
git.directory=lib/ini/
"""

Basic usage

IniFile is used to parse INI strings and access their content:

var ini = new IniFile.from_string(package_ini)
assert ini["package.name"] == "ini"
assert ini["upstream.git.directory"] == "lib/ini/"
assert ini["unknown.unknown"] == null

IniFile can also load INI configuration from a file:

package_ini.write_to_file("my_package.ini")

ini = new IniFile.from_file("my_package.ini")
assert ini["package.name"] == "ini"
assert ini["upstream.git.directory"] == "lib/ini/"

"my_package.ini".to_path.delete

INI content can be added or edited through the IniFile API then written to a stream or a file.

ini["package.name"] = "new name"
ini["upstream.git.directory"] = "/dev/null"
ini["section.key"] = "value"

var stream = new StringWriter
ini.write_to(stream)

assert stream.to_s == """
[package]
name=new name
desc=Read and write INI configuration files.
[upstream]
git=https://github.com/nitlang/nit.git
git.directory=/dev/null
[section]
key=value
"""

INI content

Properties

Properties are the basic element of the INI format. Every property correspond to a key associated to a value thanks to the equal (=) sign.

ini = new IniFile.from_string("""
key1=value1
key2=value2
""")
assert ini["key1"] == "value1"
assert ini["key2"] == "value2"
assert ini.length == 2

Accessing an unknown property returns null:

assert ini["unknown"] == null

Properties can be iterated over:

var i = 1
for key, value in ini do
    assert key == "key{i}"
    assert value == "value{i}"
    i += 1
end

Property keys cannot contain the character =. Values can contain any character. Spaces are trimmed.

ini = new IniFile.from_string("""
prop=erty1=value1
 property2 =  value2
property3=value3 ; with semicolon
""")
assert ini[";property1"] == null
assert ini["prop=erty1"] == null
assert ini["prop"] == "erty1=value1"
assert ini["property2"] == "value2"
assert ini[" property2 "] == "value2"
assert ini["property3"] == "value3 ; with semicolon"

Both keys and values are case sensitive.

ini = new IniFile.from_string("""
Property1=value1
property2=Value2
""")
assert ini["property1"] == null
assert ini["Property1"] == "value1"
assert ini["property2"] != "value2"
assert ini["property2"] == "Value2"

Sections

Properties may be grouped into arbitrary sections. The section name appears on a line by itself between square brackets ([ and ]).

All keys after the section declaration are associated with that section. The is no explicit "end of section" delimiter; sections end at the next section declaration or the end of the file. Sections cannot be nested.

var content = """
key1=value1
key2=value2
[section1]
key1=value3
key2=value4
[section2]
key1=value5
"""

ini = new IniFile.from_string(content)
assert ini["key1"] == "value1"
assert ini["unknown"] == null
assert ini["section1.key1"] == "value3"
assert ini["section1.unknown"] == null
assert ini["section2.key1"] == "value5"

Sections can be iterated over:

i = 1
for section in ini.sections do
    assert section.name == "section{i}"
    assert section["key1"].has_prefix("value")
    i += 1
end

When iterating over a file properties, only properties at root are returned. flatten can be used to iterate over all properties including the one from sections.

assert ini.join(", ", ": ") == "key1: value1, key2: value2"
assert ini.flatten.join(", ", ": ") ==
    "key1: value1, key2: value2, section1.key1: value3, section1.key2: value4, section2.key1: value5"

i = 0
for key, value in ini do
    i += 1
    assert key == "key{i}" and value == "value{i}"
end
assert i == 2

Sections name may contain any character including brackets ([ and ]). Spaces are trimmed.

ini = new IniFile.from_string("""
[[section1]]
key=value1
[ section 2 ]
key=value2
[section1.section3]
key=value3
""")
assert ini.sections.length == 3
assert ini["[section1].key"] == "value1"
assert ini["section 2.key"] == "value2"
assert ini["section1.section3.key"] == "value3"
assert ini.sections.last.name == "section1.section3"

The dot . notation is used to create new sections with []=. Unknown sections will be created on the fly.

ini = new IniFile
ini["key"] = "value1"
ini["section1.key"] = "value2"
ini["section2.key"] = "value3"

stream = new StringWriter
ini.write_to(stream)
assert stream.to_s == """
key=value1
[section1]
key=value2
[section2]
key=value3
"""

Sections can also be created manually:

ini = new IniFile
ini["key"] = "value1"

var section = new IniSection("section1")
section["key"] = "value2"
ini.sections.add section

stream = new StringWriter
ini.write_to(stream)
assert stream.to_s == """
key=value1
[section1]
key=value2
"""

Comments

Comments are indicated by semicolon (;) or a number sign (#) at the begining of the line. Commented lines are ignored as well as empty lines.

ini = new IniFile.from_string("""
; This is a comment.
; property1=value1

# This is another comment.
# property2=value2
""")
assert ini.is_empty

Unicode support

INI files support Unicode:

ini = new IniFile.from_string("""
property❤=héhé
""")
assert ini["property❤"] == "héhé"

Error handling

By default IniFile does not stop when it cannot parse a line in a string (loaded by from_string or load_string) or a file (loaded by from_file or load_file).

ini = new IniFile.from_string("""
key1=value1
key2
key3=value3
""")

assert ini.length == 2
assert ini["key1"] == "value1"
assert ini["key2"] == null
assert ini["key3"] == "value3"

This behaviour can be modified by setting stop_on_first_error to true.

ini = new IniFile.from_string("""
key1=value1
key2
key3=value3
""", stop_on_first_error = true)

assert ini.length == 1
assert ini["key1"] == "value1"
assert ini["key2"] == null
assert ini["key3"] == null

Wathever the value set for stop_on_first_error, errors can be checked thanks to the errors array:

assert ini.errors.length == 1
assert ini.errors.first.message == "Unexpected string `key2` at line 2."

All subgroups and modules

module ini

ini :: ini

Read and write INI configuration files
package_diagram ini\> ini core core ini\>->core config config config->ini\> nitc nitc nitc->ini\> markdown markdown markdown->config markdown2 markdown2 markdown2->config nlp nlp nlp->config popcorn popcorn popcorn->config vsm vsm vsm->config markdown... ... markdown...->markdown markdown2... ... markdown2...->markdown2 nlp... ... nlp...->nlp popcorn... ... popcorn...->popcorn vsm... ... vsm...->vsm

Ancestors

group codecs

core > codecs

Group module for all codec-related manipulations
group collection

core > collection

This module define several collection classes.
group text

core > text

All the classes and methods related to the manipulation of text entities

Parents

group core

core

Nit common library of core classes and methods

Children

group config

config

Configuration options for nit tools and apps
group nitc

nitc

Nit compiler and tools

Descendants

group api

nitc > doc > api

Components required to build a web server about the nit model.
group catalog

nitc > catalog

Basic catalog generator for Nit packages
group commands

nitc > doc > commands

group compiler

nitc > compiler

Compilation to C
group compiler_ffi

nitc > compiler > compiler_ffi

Full FFI support for the compiler
group doc

nitc > doc

group dynamic_loading_ffi

nitc > interpreter > dynamic_loading_ffi

This group implement a partial support for the Nit FFI in the interpreter.
group examples

nlp > examples

group examples

vsm > examples

group ffi

nitc > ffi

Full FFI support, independent of the compiler
group frontend

nitc > frontend

Collect and orchestration of main frontend phases
group github

github

Nit wrapper for Github API
group interpreter

nitc > interpreter

Interpretation of Nit programs
group markdown

markdown

A markdown parser for Nit.
group metrics

nitc > metrics

Various statistics about Nit models and programs
group model

nitc > model

The meta model of Nit programs
group modelize

nitc > modelize

Create a model from nit source files
group nitni

nitc > nitni

Native interface related services (used underneath the FFI)
group parser

nitc > parser

Parser and AST for the Nit language
group platform

nitc > platform

Platform system, used to customize the behavior of the compiler.
group popcorn

popcorn

Popcorn
group saf

nitc > saf

Nit Static Analysis Framework.
group semantize

nitc > semantize

Process bodies of methods in regard with the model.
group static

nitc > doc > static

Nitdoc generation framework
group term

nitc > doc > term

group testing

nitc > testing

Test unit generation and execution for Nit.
group uml

nitc > uml

Group head module for UML generation services
group vm

nitc > vm

Entry point of all vm components