{"id":13617098,"url":"https://github.com/leptonyu/salak","last_synced_at":"2025-03-26T08:31:23.988Z","repository":{"id":56747155,"uuid":"146751370","full_name":"leptonyu/salak","owner":"leptonyu","description":"Haskell Configuration Loader","archived":false,"fork":false,"pushed_at":"2024-10-24T07:53:20.000Z","size":768,"stargazers_count":19,"open_issues_count":1,"forks_count":0,"subscribers_count":4,"default_branch":"master","last_synced_at":"2024-10-25T04:11:36.173Z","etag":null,"topics":["configuration-loader","haskell","salak","toml","yaml"],"latest_commit_sha":null,"homepage":null,"language":"Haskell","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/leptonyu.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}},"created_at":"2018-08-30T13:09:04.000Z","updated_at":"2024-10-24T07:53:23.000Z","dependencies_parsed_at":"2022-08-16T01:20:47.131Z","dependency_job_id":"475e91d3-970a-4d9e-bebd-407d0fac5803","html_url":"https://github.com/leptonyu/salak","commit_stats":{"total_commits":165,"total_committers":3,"mean_commits":55.0,"dds":"0.030303030303030276","last_synced_commit":"9e3535aed6c8a06e3b63d6d6afe7cfc0bb0efae7"},"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leptonyu%2Fsalak","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leptonyu%2Fsalak/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leptonyu%2Fsalak/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leptonyu%2Fsalak/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/leptonyu","download_url":"https://codeload.github.com/leptonyu/salak/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245618777,"owners_count":20645066,"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":["configuration-loader","haskell","salak","toml","yaml"],"created_at":"2024-08-01T20:01:36.936Z","updated_at":"2025-03-26T08:31:23.645Z","avatar_url":"https://github.com/leptonyu.png","language":"Haskell","funding_links":[],"categories":["Haskell"],"sub_categories":[],"readme":"# salak\n\n[![Hackage](https://img.shields.io/hackage/v/salak.svg?logo=haskell)](https://hackage.haskell.org/package/salak)\n[![Build](https://img.shields.io/travis/leptonyu/salak.svg?logo=travis)](https://travis-ci.com/leptonyu/salak)\n[![stackage LTS package](http://stackage.org/package/salak/badge/lts)](http://stackage.org/lts/package/salak)\n[![stackage Nightly package](http://stackage.org/package/salak/badge/nightly)](http://stackage.org/nightly/package/salak)\n[![MIT license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/leptonyu/salak/blob/master/salak/LICENSE)\n![Hackage-Deps](https://img.shields.io/hackage-deps/v/salak)\n\n\nConfiguration (re)loader in Haskell.\n\n### Packages\n\n- [![Hackage](https://img.shields.io/badge/salak-yaml-orange)](https://hackage.haskell.org/package/salak-yaml) Yaml support for salak.\n- [![Hackage](https://img.shields.io/badge/salak-toml-orange)](https://hackage.haskell.org/package/salak-toml) Toml support for salak.\n\n## Introduction\nThis library defines a universal procedure to load configurations and parse properties, also supports reload configuration files.\n\n## Parse Functions\n\n`MonadSalak` monad provide a unified function `require` to parse properties. Here are some examples.\n\n```Haskell\na :: Bool              \u003c- require \"bool.key\"\nb :: Maybe Int         \u003c- require \"int.optional.key\"\nc :: Either String Int \u003c- require \"int.error.key\"\nd :: IO Int            \u003c- require \"int.reloadable.key\" -- This property can be changed by reloading configurations.\n```\n\n## Load Strategy\nWe can load configurations from command lines, environment, configuration files such as yaml or toml etc., and we may want to have our own strategies to load configurations from multiply sources and overwrite properties by orders of these sources.\n\n`PropConfig` defines a common loading strategy:\n\u003e 1. loadCommandLine\n\u003e 2. loadEnvironment\n\u003e 3. loadConfFiles\n\u003e 4. load file from folder `application.dir` if defined\n\u003e 5. load file from current folder if enabled\n\u003e 6. load file from home folder if enabled\n\u003e 7. file extension matching, support yaml or toml or any other loader.\n\nLoad earlier has higher priorities. Priorities cannot be changed.\n\nFor command lines and environment, \n```\nCommandLine:  --package.a.enabled=true\nEnvironment: PACKAGE_A_ENABLED: false\n```\n\n## Performance\n\n#### Load Performance\n\n```log\nbenchmarking load/loadMock\ntime                 12.91 μs   (12.86 μs .. 12.95 μs)\n                     1.000 R²   (1.000 R² .. 1.000 R²)\nmean                 12.95 μs   (12.90 μs .. 13.02 μs)\nstd dev              200.7 ns   (150.4 ns .. 267.6 ns)\nvariance introduced by outliers: 12% (moderately inflated)\n\nbenchmarking load/loadCMD\ntime                 666.5 ns   (665.6 ns .. 667.8 ns)\n                     1.000 R²   (1.000 R² .. 1.000 R²)\nmean                 668.8 ns   (666.7 ns .. 672.7 ns)\nstd dev              9.395 ns   (5.114 ns .. 14.75 ns)\nvariance introduced by outliers: 13% (moderately inflated)\n\nbenchmarking load/loadEnv\ntime                 1.823 ms   (1.813 ms .. 1.833 ms)\n                     1.000 R²   (0.999 R² .. 1.000 R²)\nmean                 1.803 ms   (1.791 ms .. 1.814 ms)\nstd dev              39.13 μs   (31.88 μs .. 48.43 μs)\n\nbenchmarking load/loadYaml\ntime                 116.9 μs   (116.5 μs .. 117.3 μs)\n                     0.999 R²   (0.998 R² .. 1.000 R²)\nmean                 118.6 μs   (116.6 μs .. 126.6 μs)\nstd dev              13.17 μs   (866.0 ns .. 27.98 μs)\nvariance introduced by outliers: 84% (severely inflated)\n\nbenchmarking load/loadToml\ntime                 2.801 ms   (2.763 ms .. 2.833 ms)\n                     0.998 R²   (0.995 R² .. 1.000 R²)\nmean                 2.890 ms   (2.834 ms .. 3.056 ms)\nstd dev              266.0 μs   (45.31 μs .. 481.7 μs)\nvariance introduced by outliers: 63% (severely inflated)\n```\n\n#### Parse Performance\n\n```log\nbenchmarking parse-int/int\ntime                 1.285 μs   (1.280 μs .. 1.291 μs)\n                     1.000 R²   (1.000 R² .. 1.000 R²)\nmean                 1.294 μs   (1.289 μs .. 1.300 μs)\nstd dev              18.29 ns   (13.86 ns .. 26.49 ns)\nvariance introduced by outliers: 13% (moderately inflated)\n\nbenchmarking parse-int/int/text\ntime                 593.9 ns   (592.4 ns .. 595.6 ns)\n                     1.000 R²   (1.000 R² .. 1.000 R²)\nmean                 595.8 ns   (594.0 ns .. 598.8 ns)\nstd dev              7.536 ns   (5.243 ns .. 10.81 ns)\nvariance introduced by outliers: 12% (moderately inflated)\n\nbenchmarking parse-int/int/bool\ntime                 1.067 μs   (1.064 μs .. 1.070 μs)\n                     1.000 R²   (1.000 R² .. 1.000 R²)\nmean                 1.068 μs   (1.065 μs .. 1.072 μs)\nstd dev              10.28 ns   (7.972 ns .. 13.55 ns)\n\nbenchmarking run/text\ntime                 953.9 ns   (951.3 ns .. 957.1 ns)\n                     1.000 R²   (1.000 R² .. 1.000 R²)\nmean                 954.7 ns   (952.6 ns .. 958.4 ns)\nstd dev              8.659 ns   (5.963 ns .. 13.47 ns)\n\nbenchmarking run/bool\ntime                 1.218 μs   (1.214 μs .. 1.222 μs)\n                     1.000 R²   (1.000 R² .. 1.000 R²)\nmean                 1.216 μs   (1.213 μs .. 1.221 μs)\nstd dev              13.03 ns   (9.765 ns .. 18.64 ns)\n```\n\n#### Parse IO Performance\n\n```log\nbenchmarking parse-io/read-io\ntime                 7.803 ns   (7.785 ns .. 7.822 ns)\n                     1.000 R²   (1.000 R² .. 1.000 R²)\nmean                 7.812 ns   (7.797 ns .. 7.838 ns)\nstd dev              68.51 ps   (41.76 ps .. 118.5 ps)\n\nbenchmarking parse-io/parse-io\ntime                 2.286 μs   (1.702 μs .. 3.317 μs)\n                     0.494 R²   (0.456 R² .. 0.908 R²)\nmean                 2.856 μs   (2.243 μs .. 3.872 μs)\nstd dev              2.663 μs   (1.837 μs .. 3.365 μs)\nvariance introduced by outliers: 99% (severely inflated)\n```\n\nAs showed above, salak's performance is good enough for normal applications. Normally loading and parsing properties can be completed in less then 5ms. Also salak's `require` function support parsing `IO a` values, which can be used for dynamic values affected by reloading. Reading the wrapped `IO` value is much faster then `require`.\n\n## Usage\n\nEnvironment:\n```\nexport TEST_CONFIG_NAME=daniel\n```\nCurrent Directory:  salak.yaml\n```YAML\ntest.config:\n  name: noop\n  dir: ls\n```\nCurrent Directory:  salak.toml\n```TOML\n[test.config]\next=2\n```\n\n```Haskell\ndata Config = Config\n  { name :: Text\n  , dir  :: Maybe Text\n  , ext  :: Int\n  } deriving (Eq, Show)\n\ninstance FromProp m Config where\n  fromProp = Config\n    \u003c$\u003e \"user\" ? pattern \"[a-z]{5,16}\"\n    \u003c*\u003e \"pwd\"\n    \u003c*\u003e \"ext\" .?= 1\n\nmain = runSalakWith \"salak\" (YAML :|: TOML) $ do\n  c :: Config \u003c- require \"test.config\"\n  lift $ print c\n```\n\nGHCi play\n```Haskell\nλ\u003e :set -XFlexibleInstances -XMultiParamTypeClasses -XOverloadedStrings\nλ\u003e import Salak\nλ\u003e import Data.Default\nλ\u003e import Data.Text(Text)\nλ\u003e data Config = Config { name :: Text, dir  :: Maybe Text, ext  :: Int} deriving (Eq, Show)\nλ\u003e instance FromProp m Config where fromProp = Config \u003c$\u003e \"user\" \u003c*\u003e \"dir\" \u003c*\u003e \"ext\" .?= 1\nλ\u003e runSalak def (require \"\") :: IO Config\nConfig {name = \"daniel\", dir = Nothing, ext = 1}\n```\n\nTODO:\n- Add git pull support.\n- Add automatic reloading.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fleptonyu%2Fsalak","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fleptonyu%2Fsalak","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fleptonyu%2Fsalak/lists"}