defmodule AmpsLib.IniManager do @moduledoc """ Documentation for `AmpsLib.IniManager`. """ @doc """ Load contents from INI File ## Examples iex> AmpsLib.load_ini(filename) returns map """ def load_ini(filename) do {:ok, data} = File.read filename parse_ini(data) end @doc """ Decode ini file contents as MAP. ## Examples iex> AmpsLib.IniManager.decode(data) returns map """ def parse_ini(data) do # Filter out the garbage rows ; \n "" data = String.split(data, ~r/[\r\n]+/) |> Enum.filter(fn line -> !Regex.match?(~r/^\s*[;]/, line) and line != "" end) # Parse the remaining lines with that sick ini regex ini_regex = ~r/^\[([^\]]*)\]$|^([^=]+)(=(.*))?$/i data = Enum.map(data, fn line -> [matches | _rest] = Regex.scan(ini_regex, line) matches end) {output, _level} = Enum.reduce(data, {%{}, 0}, fn line, {output, level} -> case {line, level} do {[_, "", key, _, value], 0} -> # If it has [] we need to insert output = if String.match?(key, ~r/\[\]/) do key = key |> String.trim() |> String.replace("[]", "") |> String.to_atom() value = value |> String.trim() Map.update(output, key, [], fn v -> v ++ [value] end) else # This is a new field that isn't a list key = key |> String.trim() |> String.to_atom() value = value |> String.trim() Map.put(output, key, value) end {output, level} {[_, "", key, _, value], level} -> output = if String.match?(key, ~r/\[\]/) do key = key |> String.trim() |> String.replace("[]", "") |> String.to_atom() value = value |> String.trim() update_in(output[level], fn map -> Map.update(map, key, [value], fn v -> v ++ [value] end) end) else # This is a new field that isn't a list key = key |> String.trim() |> String.to_atom() value = value |> String.trim() update_in(output[level], &Map.put(&1, key, value)) end {output, level} {[_, header], _} -> key = String.to_atom(header) {Map.put(output, key, %{}), key} _ -> {output, level} end end) output end end