{"id":13509672,"url":"https://github.com/fertapric/async_with","last_synced_at":"2025-04-05T15:08:02.251Z","repository":{"id":24919365,"uuid":"100596991","full_name":"fertapric/async_with","owner":"fertapric","description":"The asynchronous version of Elixir's \"with\", resolving the dependency graph and executing the clauses in the most performant way possible!","archived":false,"fork":false,"pushed_at":"2023-04-10T11:58:38.000Z","size":157,"stargazers_count":155,"open_issues_count":2,"forks_count":4,"subscribers_count":7,"default_branch":"master","last_synced_at":"2024-05-02T11:13:07.163Z","etag":null,"topics":["async","elixir"],"latest_commit_sha":null,"homepage":"https://hexdocs.pm/async_with","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/fertapric.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}},"created_at":"2017-08-17T11:37:20.000Z","updated_at":"2024-04-22T05:26:25.000Z","dependencies_parsed_at":"2024-01-05T21:59:53.227Z","dependency_job_id":"d14f6284-484f-46df-85a9-42793cd9af48","html_url":"https://github.com/fertapric/async_with","commit_stats":{"total_commits":160,"total_committers":6,"mean_commits":"26.666666666666668","dds":"0.14375000000000004","last_synced_commit":"b0d3d876cb6159b9948c1e93e38e6660228dea1f"},"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fertapric%2Fasync_with","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fertapric%2Fasync_with/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fertapric%2Fasync_with/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fertapric%2Fasync_with/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fertapric","download_url":"https://codeload.github.com/fertapric/async_with/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247353746,"owners_count":20925329,"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":["async","elixir"],"created_at":"2024-08-01T02:01:11.254Z","updated_at":"2025-04-05T15:08:02.226Z","avatar_url":"https://github.com/fertapric.png","language":"Elixir","funding_links":[],"categories":["Utilities"],"sub_categories":[],"readme":"# AsyncWith\n\n[![Build Status](https://github.com/fertapric/async_with/workflows/CI/badge.svg)](https://github.com/fertapric/async_with/actions?query=workflow%3ACI)\n\nThe asynchronous version of Elixir's `with`, resolving the dependency graph and executing the clauses in the most performant way possible!\n\n## Installation\n\nAdd `async_with` to your project's dependencies in `mix.exs`:\n\n```elixir\ndef deps do\n  [{:async_with, \"~\u003e 0.3\"}]\nend\n```\n\nAnd fetch your project's dependencies:\n\n```shell\n$ mix deps.get\n```\n\n## Usage\n\n_TL;DR: `use AsyncWith` and just write `async` in front of `with`._\n\n`async with` always executes the right side of each clause inside a new task. Tasks are spawned as soon as all the tasks that it depends on are resolved. In other words, `async with` resolves the dependency graph and executes all the clauses in the most performant way possible. It also ensures that, if a clause does not match, any running task is shut down.\n\nLet's start with an example:\n\n```elixir\niex\u003e use AsyncWith\niex\u003e\niex\u003e opts = %{width: 10, height: 15}\niex\u003e async with {:ok, width} \u003c- Map.fetch(opts, :width),\n...\u003e            {:ok, height} \u003c- Map.fetch(opts, :height) do\n...\u003e   {:ok, width * height}\n...\u003e end\n{:ok, 150}\n```\n\nAs in `with/1`, if all clauses match, the `do` block is executed, returning its result. Otherwise the chain is aborted and the non-matched value is returned:\n\n```elixir\niex\u003e use AsyncWith\niex\u003e\niex\u003e opts = %{width: 10}\niex\u003e async with {:ok, width} \u003c- Map.fetch(opts, :width),\n...\u003e            {:ok, height} \u003c- Map.fetch(opts, :height) do\n...\u003e  {:ok, width * height}\n...\u003e end\n:error\n```\n\nIn addition, guards can be used in patterns as well:\n\n```elixir\niex\u003e use AsyncWith\niex\u003e\niex\u003e users = %{\"melany\" =\u003e \"guest\", \"bob\" =\u003e :admin}\niex\u003e async with {:ok, role} when not is_binary(role) \u003c- Map.fetch(users, \"bob\") do\n...\u003e   :ok\n...\u003e end\n:ok\n```\n\nVariables bound inside `async with` won't leak; \"bare expressions\" may also be inserted between the clauses:\n\n```elixir\niex\u003e use AsyncWith\niex\u003e\niex\u003e width = nil\niex\u003e opts = %{width: 10, height: 15}\niex\u003e async with {:ok, width} \u003c- Map.fetch(opts, :width),\n...\u003e            double_width = width * 2,\n...\u003e            {:ok, height} \u003c- Map.fetch(opts, :height) do\n...\u003e   {:ok, double_width * height}\n...\u003e end\n{:ok, 300}\niex\u003e width\nnil\n```\n\nAn `else` option can be given to modify what is being returned from `async with` in the case of a failed match:\n\n```elixir\niex\u003e use AsyncWith\niex\u003e\niex\u003e opts = %{width: 10}\niex\u003e async with {:ok, width} \u003c- Map.fetch(opts, :width),\n...\u003e            {:ok, height} \u003c- Map.fetch(opts, :height) do\n...\u003e   {:ok, width * height}\n...\u003e else\n...\u003e   :error -\u003e\n...\u003e     {:error, :wrong_data}\n...\u003e end\n{:error, :wrong_data}\n```\n\nIf an `else` block is used and there are no matching clauses, an `AsyncWith.ClauseError` exception is raised.\n\nOrder-dependent clauses that do not express their dependency via their used or defined variables could lead to race conditions, as they are executed in separated tasks:\n\n```elixir\nuse AsyncWith\n\nasync with Agent.update(agent, fn _ -\u003e 1 end),\n           Agent.update(agent, fn _ -\u003e 2 end) do\n  Agent.get(agent, fn state -\u003e state end) # 1 or 2\nend\n```\n\n[Check the documentation](https://hexdocs.pm/async_with) for more information.\n\n## Documentation\n\nDocumentation is available at https://hexdocs.pm/async_with\n\n## Code formatter\n\n[As described in `Code.format_string!/2` documentation](https://hexdocs.pm/elixir/Code.html#format_string!/2-parens-and-no-parens-in-function-calls), Elixir will add parens to all calls except for:\n\n1. calls that have do/end blocks\n2. local calls without parens where the name and arity of the local call is also listed under `:locals_without_parens`\n\n`async with` expressions should fall under the first category and be kept without parens, because they are similar to `with/1` calls.\n\nThis is then the recommended `.formatter.exs` configuration:\n\n```elixir\n[\n  # Regular formatter configuration\n  # ...\n\n  import_deps: [:async_with]\n]\n```\n\nAs an alternative, you can add `async: 1` and `async: 2` directly to the list `:locals_without_parens`.\n\n## Contributing\n\nBug reports and pull requests are welcome on GitHub at https://github.com/fertapric/async_with. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.\n\n### Running tests\n\nClone the repo and fetch its dependencies:\n\n```shell\n$ git clone https://github.com/fertapric/async_with.git\n$ cd async_with\n$ mix deps.get\n$ mix test\n```\n\n### Building docs\n\n```shell\n$ mix docs\n```\n\n## Acknowledgements\n\nI would like to express my gratitude to all the people in the [Elixir Core Mailing list](https://groups.google.com/forum/#!forum/elixir-lang-core) who gave ideas and feedback on the early stages of this project. A very special mention to Luke Imhoff ([@KronicDeth](https://github.com/KronicDeth)), Theron Boerner ([@hunterboerner](https://github.com/hunterboerner)), and John Wahba ([@johnwahba](https://github.com/johnwahba)).\n\n## Copyright and License\n\n(c) Copyright 2017-2019 Fernando Tapia Rico\n\nAsyncWith source code is licensed under the [MIT License](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffertapric%2Fasync_with","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffertapric%2Fasync_with","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffertapric%2Fasync_with/lists"}