Sign in

    ini_parser

    A complete INI file parser for MoonBit with support for sections, multiple data types, comments, and comprehensive error handling

    ini
    parser
    config
    configuration
    file-format
    Download zip
    Author
    Version
    0.1.0
    License
    Apache-2.0
    Last updated
    11 months ago
    Downloads
    30

    No dependencies

    #INI Parser for MoonBit

    A complete INI file parser implementation in MoonBit with support for sections, key-value pairs, comments, and multiple data types.

    #Features

    • ✅ Parse INI files with sections
    • ✅ Support for multiple data types (String, Int, Double, Bool)
    • ✅ Comment support (; and #)
    • ✅ Quoted string values
    • ✅ Boolean value parsing (true/false, yes/no, on/off, 1/0)
    • ✅ Comprehensive error handling
    • ✅ Round-trip conversion (parse → modify → serialize)

    #Quick Start

    test "parse and query INI file" {
    let ini_content =
    #|[server]
    #|host = localhost
    #|port = 8080
    #|debug = true
    #|

    let ini = try! @maria/ini_parser.parse(ini_content)

    // Query values with type-safe getters
    inspect(ini.get_string("server", "host"), content="Some(\"localhost\")")
    inspect(ini.get_int("server", "port"), content="Some(8080)")
    inspect(ini.get_bool("server", "debug"), content="Some(true)")
    }

    #API Reference

    #IniFile Structure

    The main structure for working with INI files:

    test "create new INI file" {
    let ini = @maria/ini_parser.IniFile::new()
    inspect(ini.sections(), content="[]")
    }

    #Parsing INI Files

    Parse INI content from a string:

    test "parse INI with multiple sections" {
    let content =
    #|[app]
    #|name = MyApp
    #|version = 1.0
    #|
    #|[database]
    #|host = localhost
    #|port = 5432
    #|

    let ini = try! @maria/ini_parser.parse(content)
    inspect(ini.sections().length(), content="2")
    inspect(ini.has_section("app"), content="true")
    inspect(ini.has_section("database"), content="true")
    }

    #Querying Values

    Type-safe getters for different value types:

    test "type-safe value getters" {
    let content =
    #|[config]
    #|name = test
    #|count = 42
    #|ratio = 3.14
    #|enabled = true
    #|

    let ini = try! @maria/ini_parser.parse(content)

    // Each getter returns Option[T]
    inspect(ini.get_string("config", "name"), content="Some(\"test\")")
    inspect(ini.get_int("config", "count"), content="Some(42)")
    inspect(ini.get_double("config", "ratio"), content="Some(3.14)")
    inspect(ini.get_bool("config", "enabled"), content="Some(true)")

    // Non-existent keys return None
    inspect(ini.get_string("config", "missing"), content="None")
    }

    #Setting Values

    Programmatically create or modify INI files:

    test "set values in INI file" {
    let ini = @maria/ini_parser.IniFile::new()

    // Set values using the IniValue enum
    ini.set("app", "name", @maria/ini_parser.String("MyApp"))
    ini.set("app", "port", @maria/ini_parser.Int(3000))
    ini.set("app", "enabled", @maria/ini_parser.Bool(true))
    ini.set("app", "timeout", @maria/ini_parser.Double(30.5))

    inspect(ini.get_string("app", "name"), content="Some(\"MyApp\")")
    inspect(ini.get_int("app", "port"), content="Some(3000)")
    inspect(ini.get_bool("app", "enabled"), content="Some(true)")
    inspect(ini.get_double("app", "timeout"), content="Some(30.5)")
    }

    #Serializing to String

    Convert INI file back to string format:

    test "serialize INI to string" {
    let ini = @maria/ini_parser.IniFile::new()
    ini.set("section", "key", @maria/ini_parser.String("value"))

    let output = ini.to_string()
    inspect(output.contains("[section]"), content="true")
    inspect(output.contains("key = value"), content="true")
    }

    #Comments

    Comments are supported with ; or #:

    test "parse with comments" {
    let content =
    #|; This is a comment
    #|[config]
    #|# Another comment
    #|key = value
    #|

    let ini = try! @maria/ini_parser.parse(content)
    inspect(ini.get_string("config", "key"), content="Some(\"value\")")
    }

    #Boolean Values

    Multiple boolean representations are supported:

    test "boolean parsing variations" {
    let content =
    #|[flags]
    #|a = true
    #|b = yes
    #|c = on
    #|d = 1
    #|e = false
    #|f = no
    #|g = off
    #|h = 0
    #|

    let ini = try! @maria/ini_parser.parse(content)

    // All true variants
    inspect(ini.get_bool("flags", "a"), content="Some(true)")
    inspect(ini.get_bool("flags", "b"), content="Some(true)")
    inspect(ini.get_bool("flags", "c"), content="Some(true)")
    inspect(ini.get_bool("flags", "d"), content="Some(true)")

    // All false variants
    inspect(ini.get_bool("flags", "e"), content="Some(false)")
    inspect(ini.get_bool("flags", "f"), content="Some(false)")
    inspect(ini.get_bool("flags", "g"), content="Some(false)")
    inspect(ini.get_bool("flags", "h"), content="Some(false)")
    }

    #Quoted Strings

    String values can be quoted:

    test "quoted string values" {
    let content =
    #|[strings]
    #|quoted = "hello world"
    #|single = 'with spaces'
    #|

    let ini = try! @maria/ini_parser.parse(content)
    inspect(ini.get_string("strings", "quoted"), content="Some(\"hello world\")")
    inspect(ini.get_string("strings", "single"), content="Some(\"with spaces\")")
    }

    #Error Handling

    The parser provides detailed error information:

    test "error on invalid section" {
    let invalid = "[section"
    let result = try? @maria/ini_parser.parse(invalid)
    inspect(result is Err(_), content="true")
    }

    test "error on empty key" {
    let invalid = "[section]\n= value"
    let result = try? @maria/ini_parser.parse(invalid)
    inspect(result is Err(_), content="true")
    }

    #Inspecting Structure

    Get information about sections and keys:

    test "inspect sections and keys" {
    let content =
    #|[section1]
    #|a = 1
    #|b = 2
    #|[section2]
    #|c = 3
    #|

    let ini = try! @maria/ini_parser.parse(content)

    let sections = ini.sections()
    inspect(sections.length(), content="2")
    inspect(sections.contains("section1"), content="true")

    let keys = ini.keys("section1")
    inspect(keys.length(), content="2")
    inspect(keys.contains("a"), content="true")
    inspect(keys.contains("b"), content="true")
    }

    #Error Types

    The parser can raise the following errors:

    • InvalidSection(line: Int, content: String) - Malformed section header
    • InvalidKeyValue(line: Int, content: String) - Missing = separator
    • EmptyKey(line: Int) - Key name is empty

    #Running the Demo

    moon run cmd/main

    This will run a comprehensive demo showing parsing, querying, and serialization features.

    ParseError

    pub(all) suberror ParseError {
    InvalidSection(Int, String)
    InvalidKeyValue(Int, String)
    EmptyKey(Int)
    }

    Parse error type
    impl Eq for ParseError
    impl Show for ParseError

    IniFile

    pub struct IniFile {
    sections : Map[String, Map[String, IniValue]]
    }

    INI file structure: sections map to key-value pairs
    impl Show for IniFile

    IniFile::get

    fn IniFile::get(self : IniFile, section : String, key : String) -> IniValue?

    Get value from a section

    IniFile::get_bool

    fn IniFile::get_bool(self : IniFile, section : String, key : String) -> Bool?

    Get bool value from a section

    IniFile::get_double

    fn IniFile::get_double(self : IniFile, section : String, key : String) -> Double?

    Get double value from a section

    IniFile::get_int

    fn IniFile::get_int(self : IniFile, section : String, key : String) -> Int?

    Get int value from a section

    IniFile::get_string

    fn IniFile::get_string(self : IniFile, section : String, key : String) -> String?

    Get string value from a section

    IniFile::has_section

    fn IniFile::has_section(self : IniFile, section : String) -> Bool

    Check if a section exists

    IniFile::keys

    fn IniFile::keys(self : IniFile, section : String) -> Array[String]

    Get all keys in a section

    IniFile::new

    fn IniFile::new() -> IniFile

    Create a new empty INI file

    IniFile::sections

    fn IniFile::sections(self : IniFile) -> Array[String]

    Get all section names

    IniFile::set

    fn IniFile::set(self : IniFile, section : String, key : String, value : IniValue) -> Unit

    Set a value in a section

    IniFile::to_string

    fn IniFile::to_string(self : IniFile) -> String

    Convert IniFile to string format

    IniValue

    pub(all) enum IniValue {
    String(String)
    Int(Int)
    Double(Double)
    Bool(Bool)
    }

    INI file value type
    impl Eq for IniValue
    impl Show for IniValue

    parse

    fn parse(input : String) -> IniFile raise ParseError

    Parse an INI file from a string

    Source Files