{"id":20852081,"url":"https://github.com/icedragon200/kuddle_config","last_synced_at":"2025-04-10T19:51:32.442Z","repository":{"id":57514314,"uuid":"406559137","full_name":"IceDragon200/kuddle_config","owner":"IceDragon200","description":"Elixir Config Provider using Kuddle","archived":false,"fork":false,"pushed_at":"2024-12-26T19:19:11.000Z","size":37,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-24T17:49:49.512Z","etag":null,"topics":["config","configprovider","elixir","kdl"],"latest_commit_sha":null,"homepage":"","language":"Elixir","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/IceDragon200.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","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}},"created_at":"2021-09-15T00:16:10.000Z","updated_at":"2025-01-03T13:10:58.000Z","dependencies_parsed_at":"2025-01-19T06:26:44.988Z","dependency_job_id":null,"html_url":"https://github.com/IceDragon200/kuddle_config","commit_stats":{"total_commits":14,"total_committers":1,"mean_commits":14.0,"dds":0.0,"last_synced_commit":"6958ebb609d5684e2f2f5e51e86771adc46fd8a4"},"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/IceDragon200%2Fkuddle_config","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/IceDragon200%2Fkuddle_config/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/IceDragon200%2Fkuddle_config/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/IceDragon200%2Fkuddle_config/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/IceDragon200","download_url":"https://codeload.github.com/IceDragon200/kuddle_config/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248283688,"owners_count":21077902,"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":["config","configprovider","elixir","kdl"],"created_at":"2024-11-18T03:16:14.457Z","updated_at":"2025-04-10T19:51:32.418Z","avatar_url":"https://github.com/IceDragon200.png","language":"Elixir","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Kuddle Config\n\nAn Elixir [`Config.Provider`](https://hexdocs.pm/elixir/master/Config.Provider.html) using [kuddle](https://github.com/IceDragon200/kuddle), also general configuration helpers using Kuddle.\n\n## Installation\n\nTo add `kuddle_config` to your project:\n\n```elixir\ndef deps do\n  [\n    {:kuddle_config, \"~\u003e 0.3.0\"}\n  ]\nend\n```\n\n## Usage\n\nKuddle provides 2 different config providers:\n\n### Single File Providers\n\nThe default Config.Provider which will load a kdl file as config\n\n#### Kuddle.Config.Provider\n\nUsed for elixir releases:\n\n```elixir\n# Format\ndefp releases do\n  [\n    application: [\n      config_providers: [\n        {Kuddle.Config.Provider, [\n          path: config_path()\n        ]}\n      ]\n    ]\n  ]\nend\n\n# Example\ndefp releases do\n  [\n    application: [\n      config_providers: [\n        {Kuddle.Config.Provider, [\n          path: {:system, \"PATH_TO_CONFIG\", \"/default/path/to/kdl/config\"}\n        ]}\n      ]\n    ]\n  ]\nend\n```\n\n#### Kuddle.Config.Distillery.Provider\n\nUsed for distillery releases\n\n```elixir\n# Format\nrelease :my_app do\n  set config_providers: [\n    {Kuddle.Config.Distillery.Provider, [\n      path: config_path()\n    ]}\n  ]\nend\n\n# Example\nrelease :my_app do\n  set config_providers: [\n    {Kuddle.Config.Distillery.Provider, [\n      path: {:system, \"PATH_TO_CONFIG\", \"/default/path/to/kdl/config\"}\n    ]}\n  ]\nend\n```\n\n### Directory Loaders\n\n#### Kuddle.Config.DirectoryProvider\n\n```elixir\n# A special config provider that will load every kdl file in a directory as config\n\n# Format\ndefp releases do\n  [\n    application: [\n      config_providers: [\n        {Kuddle.Config.DirectoryProvider, [\n          paths: [config_path()],\n          extensions: [String.t()]\n        ]}\n      ]\n    ]\n  ]\nend\n\n# Example\ndefp releases do\n  [\n    application: [\n      config_providers: [\n        {Kuddle.Config.DirectoryProvider, [\n          paths: [\n            {:system, \"PATH_TO_CONFIG\", \"/default/path/to/kdl/config\"}\n          ],\n          extensions: [\".kdl\", \".kuddle\"]\n        ]}\n      ]\n    ]\n  ]\nend\n```\n\n#### Kuddle.Config.Distillery.DirectoryProvider\n\n```elixir\n# Format\nrelease :my_app do\n  set config_providers: [\n    {Kuddle.Config.Distillery.DirectoryProvider, [\n      paths: [config_path()],\n      extensions: [String.t()]\n    ]}\n  ]\nend\n\n# Example\nrelease :my_app do\n  set config_providers: [\n    {Kuddle.Config.Distillery.DirectoryProvider, [\n      paths: [\n        {:system, \"PATH_TO_CONFIG\", \"/default/path/to/kdl/config\"}\n      ],\n      extensions: [\".kdl\", \".kuddle\"]\n    ]}\n  ]\nend\n```\n\n## Other Use Cases\n\nDespite the original purpose of this library being the config providers, the config module itself is quite useful even without the providers:\n\n```elixir\n# Have a KDL blob you wish to load?\n{:ok, config} =\n  Kuddle.Config.load_config_blob(\"\"\"\n  application {\n    node \"value\"\n  }\n  \"\"\")\n\n[\n  application: [\n    node: \"value\"\n  ]\n] = config\n\n# Have a KDL file you'd like to load?\n{:ok, config} = Kuddle.Config.load_config_file(\"my_kdl_config.kdl\")\n\n[\n  application: [\n    node2: \"some_other_value\"\n  ]\n] = config\n\n# Have a directory filled with KDL files you'd like to load into one config?\n{:ok, config} = Kuddle.Config.load_config_directory(\"/my/kdl/configs\", [\".kdl\", \".kuddle\"])\n\n[\n  data: [\n    {MyRepo, [\n      database: \"database\",\n      host: \"127.0.0.1\",\n      port: 5432,\n    ]},\n  ],\n  web: [\n    http: [\n      port: 4000\n    ]\n  ],\n  workers: [\n    amqp: [\n      host: \"127.0.0.1\",\n      port: 5732,\n      virtual_host: \"my_workers\",\n    ]\n  ]\n] = config\n\n# Have the kuddle document already?\n{:ok, config} = Kuddle.Config.load_config_document(document)\n\n[\n  logger: [\n    console: [\n      level: :debug\n    ]\n  ]\n] = config\n```\n\n## Config Format\n\nRoot nodes are application level config, while subsequent sub nodes will be one level deeper config\n\n```kdl\napplication {\n  key \"value\"\n\n  key2 {\n    subkey \"value\"\n  }\n}\n```\n\nIs equivalent to:\n\n```elixir\nconfig :application,\n  key: \"value\",\n  key2: [\n    subkey: \"value\"\n  ]\n```\n\nConfig is extracted from both attributes and sub nodes:\n\n```kdl\napplication {\n  food {\n    bacon \"1\"\n    eggs \"2\"\n  }\n}\n```\n\nIs equivalent to:\n\n```kdl\napplication {\n  food bacon=\"1\" eggs=\"2\"\n}\n```\n\nEither can be mixed and matched to achieve a comfortable format:\n\n```kdl\napplication {\n  food bacon=\"1\" {\n    eggs \"2\"\n  }\n}\n```\n\nThere is one tiny gotcha in regards to lists:\n\n```kdl\napplication {\n  node \"value\"\n}\n```\n\nWould evaluate to:\n\n```elixir\n[\n  application: [\n    node: \"value\"\n  ]\n]\n```\n\nAs one would expect, however:\n\n```kdl\napplication {\n  node \"value\" \"value2\"\n}\n```\n\nWould evaluate to:\n\n```elixir\n[\n  application: [\n    node: [\"value\", \"value2\"]\n  ]\n]\n```\n\nAssuming the configuration requires a list, it can be coerced using the `(list)` annotation on the node:\n\n```kdl\napplication {\n  (list)node \"value\"\n}\n```\n\n```elixir\n[\n  application: [\n    node: [\"value\"]\n  ]\n]\n```\n\nSometimes it is useful to set a tuple, which is something most available configuration languages struggle with for elixir:\n\n```kdl\napplication {\n  (tuple)thing \"left\" \"right\"\n}\n```\n\n```elixir\n[\n  application: [\n    thing: {\"left\", \"right\"}\n  ]\n]\n```\n\nYou can also cast values into atoms:\n\n```kdl\nlogger {\n  console {\n    level (atom)\"debug\"\n  }\n}\n```\n\n```elixir\n[\n  logger: [\n    console: [\n      level: :debug\n    ]\n  ]\n]\n```\n\nA list of all available types and more information can be found in the Kuddle.Config.Types module, or the table below.\n\n| Type Annotation  | Example                                                                       |\n| ---------------- | ----------------------------------------------------------------------------- |\n| `date`           | `start_date (date)\"2021-09-14\"`                                               |\n| `utc_datetime`   | `inserted_at (utc_datetime)\"2021-09-14T18:00:00.000000Z\"`                     |\n| `naive_datetime` | `deleted_at (naive_datetime)\"2021-09-14T18:00:00.000000Z\"`                    |\n| `time`           | `start_time (time)\"18:00:23\"`                                                 |\n| `decimal`        | `cost (decimal)\"0.002500\"`                                                    |\n| `atom`           | `level (atom)\"debug\"`                                                         |\n| `boolean`        | `enable_polling (boolean)\"YES\"`                                               |\n| `tuple`          | `(tuple)call_pair \"New York\" \"12003004000\"`                                   |\n| `list`           | `(list)allow_list \"117.27.222.122\"`                                           |\n\nAdditional types can be registered using `kuddle_config` `:types` config:\n\n```elixir\nconfig :kuddle_config,\n  types: [\n    geopoint: {MyGeoPoint, :cast},\n  ]\n```\n\n```elixir\ndefmodule MyGeoPoint do\n  def cast(value) do\n    {:ok, String.split(value, \",\", parts: 2) |\u003e Enum.map(\u0026Decimal.new/1) |\u003e List.to_tuple()}\n  end\nend\n```\n\n```kdl\napplication {\n  point (geopoint)\"15.27,265.27\"\n}\n```\n\n```elixir\n[\n  application: [\n    point: {%Decimal{coef: \"1527\", exp: -2, sign: 1}, %Decimal{coef: \"26527\", exp: -2, sign: 1}}\n  ]\n]\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ficedragon200%2Fkuddle_config","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ficedragon200%2Fkuddle_config","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ficedragon200%2Fkuddle_config/lists"}