{"id":18319907,"url":"https://github.com/bitwalker/toml-elixir","last_synced_at":"2025-10-06T03:45:08.913Z","repository":{"id":42702594,"uuid":"142738896","full_name":"bitwalker/toml-elixir","owner":"bitwalker","description":"An implementation of TOML for Elixir projects, compliant with the latest specification","archived":false,"fork":false,"pushed_at":"2024-08-14T20:51:44.000Z","size":202,"stargazers_count":202,"open_issues_count":10,"forks_count":27,"subscribers_count":7,"default_branch":"main","last_synced_at":"2025-05-16T18:05:21.465Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Elixir","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bitwalker.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2018-07-29T07:08:09.000Z","updated_at":"2025-03-23T15:50:01.000Z","dependencies_parsed_at":"2025-05-16T18:05:27.008Z","dependency_job_id":null,"html_url":"https://github.com/bitwalker/toml-elixir","commit_stats":null,"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bitwalker%2Ftoml-elixir","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bitwalker%2Ftoml-elixir/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bitwalker%2Ftoml-elixir/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bitwalker%2Ftoml-elixir/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bitwalker","download_url":"https://codeload.github.com/bitwalker/toml-elixir/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254582904,"owners_count":22095518,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-05T18:14:38.755Z","updated_at":"2025-10-06T03:45:03.867Z","avatar_url":"https://github.com/bitwalker.png","language":"Elixir","readme":"# TOML for Elixir\n\n[![Main](https://github.com/bitwalker/toml-elixir/workflows/elixir/badge.svg?branch=main)](https://github.com/bitwalker/toml-elixir/actions?query=workflow%3A%22elixir%22+branch%3Amain)\n[![Hex.pm Version](https://img.shields.io/hexpm/v/toml.svg?style=flat)](https://hex.pm/packages/toml)\n[![Hex Docs](https://img.shields.io/badge/hex-docs-lightgreen.svg?style=flat)](https://hexdocs.pm/toml)\n[![Total Download](https://img.shields.io/hexpm/dt/toml.svg?style=flat)](https://hex.pm/packages/toml)\n[![Last Updated](https://img.shields.io/github/last-commit/bitwalker/toml-elixir.svg?style=flat)](https://github.com/bitwalker/toml-elixir/commits/main)\n\nThis is a TOML library for Elixir projects. \n\nIt is compliant with version 1.0 of the [official TOML specification](https://github.com/toml-lang/toml). You can find a\nbrief overview of the feature set below, but you are encouraged to read the full spec at the link above (it is short and easy to read!).\n\n## Features\n\n- Decode from string, file, or stream\n- Fully compliant with the latest version of the TOML spec\n- Is tested against [toml-test](https://github.com/BurntSushi/toml-test), a test\n  suite for spec-compliant TOML encoders/decoders, used by implementations in\n  multiple languages. The test suite has been integrated into this project to be\n  run under Mix so that we get better error information and so it can run as\n  part of the test suite.\n- Decoder produces a map with values using the appropriate Elixir data types for\n  representation\n- Supports extension via value transformers (see `Toml.Transform` docs for details)\n- Supports use as a configuration provider in Distillery 2.x+ (use TOML\n  files for configuration!)\n- Decoder is written by hand to take advantage of various optimizations.\n- Library passes Dialyzer checks\n\n## Comparison To Other Libraries\n\nI compared `toml` to four other libraries:\n\n- `toml_elixir`\n- `tomlex`\n- `jerry`\n- `etoml`\n\nOf these four, none correctly implement the 0.5.0 specification. Either they are\ntargeting older versions of the spec (in `etoml`, it is built against pre-0.1),\nare not fully implemented (i.e. don't support all features), or have bugs which\nprevent them from properly parsing a 0.5.0 example file (the\n`test/fixtures/example.toml` file in this repository).\n\nIf you are looking for a TOML library, at present `toml` is the only one which\nfull implements the spec and correctly decodes `example.toml`.\n\n## Installation\n\nThis library is available on Hex as `:toml`, and can be added to your deps like so:\n\n```elixir\ndef deps do\n  [\n    {:toml, \"~\u003e 0.7\"}\n  ]\nend\n```\n\nNOTE: You can determine the latest version on Hex by running `mix hex.info toml`.\n\n## Type Conversions\n\nIn case you are curious how TOML types are translated to Elixir types, the\nfollowing table provides the conversions.\n\n**NOTE:** The various possible representations of each type, such as\nhex/octal/binary integers, quoted/literal strings, etc., are considered to be\nthe same base type (e.g. integer and string respectively in the examples given).\n\n| TOML | Elixir |\n|-------|-------|\n| String | String.t (binary) |\n| Integer | integer |\n| inf | :infinity |\n| +inf | :infinity |\n| -inf | :negative_infinity |\n| nan | :nan |\n| +nan | :nan |\n| -nan | :negative_nan |\n| Boolean | boolean |\n| Offset Date-Time | DateTime.t |\n| Local Date-Time | NaiveDateTime.t |\n| Local Date | Date.t |\n| Local Time | Time.t |\n| Array | list |\n| Table | map |\n| Table Array | list(map) |\n\n## Implementation-specific Behaviors\n\nCertain features of TOML have implementation-specific behavior:\n\n- `-inf`, `inf`, and `+inf` are all valid infinity values in TOML.\n  In Erlang/Elixir, these don't have exact representations. Instead, by convention, \n  `:infinity` is used for positive infinity, as atoms are always larger than integers\n  when using comparison operators, so `:infinity \u003e \u003cany integer\u003e` will always be true.\n  However, negative infinity cannot be represented, as numbers are always considered smaller\n  than every other type in term comparisons. Instead, we represent it with `:negative_infinity`,\n  so that the type information is not lost, but you must be careful to deal with it specifically\n  in comparisons/sorting/etc.\n- `-nan`, `nan`, and `+nan` are all valid NaN (not a number) values in TOML. In Erlang/Elixir,\n  NaN is traditionally represented with `:nan`, but there is no representation for negative NaN,\n  and no API actually produces `:nan`, instead invalid numbers typically raise errors, in the typical \n  spirit of \"let it crash\" in the face of errors. For purposes of preserving type information though,\n  we use the `:nan` convention, and `:negative_nan` for -NaN. You will need to take care to deal with\n  these values manually if the values need to be preserved.\n- The maximum precision of times in the various time types is microseconds (i.e. precision to six decimal places),\n  if you provide higher precision values (i.e. nanoseconds), the extra precision will be lost.\n- Hex, octal, and binary numbers are converted to integers, so serializing those values after decoding\n  them from a TOML document will be in their decimal representation.\n\n## Example Usage\n\nThe following is a brief overview of how to use this library. First, let's take\na look at an example TOML file, as borrowed from the [TOML\nhomepage](https://github.com/toml-lang/toml):\n\n``` toml\n# This is a TOML document.\n\ntitle = \"TOML Example\"\n\n[owner]\nname = \"Tom Preston-Werner\"\ndob = 1979-05-27T07:32:00-08:00 # First class dates\n\n[database]\nserver = \"192.168.1.1\"\nports = [ 8001, 8001, 8002 ]\nconnection_max = 5000\nenabled = true\n\n[servers]\n\n  # Indentation (tabs and/or spaces) is allowed but not required\n  [servers.alpha]\n  ip = \"10.0.0.1\"\n  dc = \"eqdc10\"\n\n  [servers.beta]\n  ip = \"10.0.0.2\"\n  dc = \"eqdc10\"\n\n[clients]\ndata = [ [\"gamma\", \"delta\"], [1, 2] ]\n\n# Line breaks are OK when inside arrays\nhosts = [\n  \"alpha\",\n  \"omega\"\n]\n```\n\n### Parsing\n\n```elixir\niex\u003e input = \"\"\"\n[database]\nserver = \"192.168.1.1\"\n\"\"\"\n...\u003e {:ok, %{\"database\" =\u003e %{\"server\" =\u003e \"192.168.1.1\"}}} = Toml.decode(input)\n...\u003e {:ok, %{database: %{server: \"192.168.1.1\"}}} = Toml.decode(input, keys: :atoms)\n...\u003e stream = File.stream!(\"example.toml\")\n...\u003e {:ok, %{\"database\" =\u003e %{\"server\" =\u003e \"192.168.1.1\"}}} = Toml.decode_stream(stream)\n...\u003e {:ok, %{\"database\" =\u003e %{\"server\" =\u003e \"192.168.1.1\"}}} = Toml.decode_file(\"example.toml\")\n...\u003e invalid = \"\"\"\n[invalid]\na = 1 b = 2\n\"\"\"\n...\u003e {:error, {:invalid_toml, reason}} = Toml.decode(invalid); IO.puts(reason)\nexpected '\\n', but got 'b' in nofile on line 2:\n\n    a = 1 b = 2\n         ^\n\n:ok\n```\n\n### Transforms\n\nSupport for extending value conversions is provided by the `Toml.Transform`\nbehavior. An example is shown below:\n\nGiven the following TOML document:\n\n``` toml\n[servers.alpha]\nip = \"192.168.1.1\"\nports = [8080, 8081]\n\n[servers.beta]\nip = \"192.168.1.2\"\nports = [8082, 8083]\n```\n\nAnd the following modules:\n\n``` elixir\ndefmodule Server do\n  defstruct [:name, :ip, :ports]\nend\n\ndefmodule IPStringToCharlist do\n  use Toml.Transform\n  \n  def transform(:ip, v) when is_binary(v) do\n    String.to_charlist(v)\n  end\n  def transform(_k, v), do: v\nend\n\ndefmodule CharlistToIP do\n  use Toml.Transform\n  \n  def transform(:ip, v) when is_list(v) do\n    case :inet.parse_ipv4_address(v) do\n      {:ok, address} -\u003e\n        address\n      {:error, reason} -\u003e\n        {:error, {:invalid_ip_address, reason}}\n    end\n  end\n  def transform(:ip, v), do: {:error, {:invalid_ip_address, v}}\n  def transform(_k, v), do: v\nend\n\ndefmodule ServerMapToList do\n  use Toml.Transform\n  \n  def transform(:servers, v) when is_map(v) do\n    for {name, server} \u003c- v, do: struct(Server, Map.put(server, :name, name))\n  end\n  def transform(_k, v), do: v\nend\n```\n\nYou can convert the TOML document to a more strongly-typed version using the\nabove transforms like so:\n\n```elixir\niex\u003e transforms = [IPStringToCharlist, CharlistToIP, ServerMapToList]\n...\u003e {:ok, result} = Toml.decode(\"example.toml\", keys: :atoms, transforms: transforms)\n%{servers: [%Server{name: :alpha, ip: {192,168,1,1}}, ports: [8080, 8081] | _]}\n```\n\nThe transforms given here are intended to show how they can be composed: they\nare applied in the order provided, and the document is transformed using a\ndepth-first, bottom-up traversal. Put another way, you transform the leaves of\nthe tree before the branches; as shown in the example above, this means the\n`:ip` key is converted to an address tuple before the `:servers` key is\ntransformed into a list of `Server` structs.\n\n## Using with Elixir Releases (1.9+)\n\nTo use this library as a configuration provider in Elixir, use the following\nexample of how one might use it in their release configuration, and tailor it\nto your needs:\n\n```elixir\nconfig_providers: [\n  {Toml.Provider, [\n    path: {:system, \"XDG_CONFIG_DIR\", \"myapp.toml\"},\n    transforms: [...]\n  ]}\n]\n```\n\nSee the \"Using as a Config Provider\" section for more info.\n\n## Using with Distillery\n\nLike the above, use the following example as a guideline for how you use this\nin your own release configuration (i.e. in `rel/config.exs`):\n\n``` elixir\nrelease :myapp do\n  # ...snip...\n  set config_providers: [\n    {Toml.Provider, [path: \"${XDG_CONFIG_DIR}/myapp.toml\", transforms: [...]]}\n  ]\nend\n```\n\n## Using as a Config Provider\n\nThe usages described above will result in `Toml.Provider` being invoked during boot, at which point it\nwill evaluate the given path and read the TOML file it finds. If one is not\nfound, or is not accessible, the provider will raise an error, and the boot\nsequence will terminate unsuccessfully. If it succeeds, it persists settings in\nthe file to the application environment (i.e. you access it via\n`Application.get_env/2`).\n\nYou can pass the same options in the arguments list for `Toml.Provider` as you\ncan to `Toml.decode/2`, but `:path` is required, and `:keys` only supports\n`:atoms` and `:atoms!` values.\n\nThe config provider expects a certain format to the TOML file, namely that keys\nat the root of the document correspond to applications which need to be configured.\nIf it encounters keys at the root of the document which are not tables, they are ignored.\n\n``` toml\n# This is an example of something that would be ignored\ntitle = \"My config file\"\n\n# We're expecting something like this:\n[myapp]\nkey = \"value\"\n\n# To use a bit of Phoenix config, you translate to TOML like so:\n[myapp.\"MyApp.Endpoint\"]\ncache_static_manifest = \"priv/static/cache_manifest.json\"\n\n[myapp.\"MyApp.Endpoint\".http]\nport = \"4000\"\n\n[myapp.\"MyApp.Endpoint\".force_ssl]\nhsts = true\n\n# Or logger..\n[logger]\nlevel = \"info\"\n\n[logger.console]\nformat = \"[$level] $message \\n\"\n```\n\n## Roadmap\n\n- [x] Add benchmarking suite\n- [x] Provide options for converting keys to atom, similar to Jason/Poison/etc.\n- [ ] Optimize lexer to always send offsets to decoder, rather than only in some cases\n- [ ] Try to find pathological TOML files to test\n\n## License\n\nThis project is licensed Apache 2.0, see the `LICENSE` file in this repo for details.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbitwalker%2Ftoml-elixir","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbitwalker%2Ftoml-elixir","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbitwalker%2Ftoml-elixir/lists"}