{"id":13809018,"url":"https://github.com/mruoss/pluggable","last_synced_at":"2025-07-15T12:38:17.674Z","repository":{"id":61281682,"uuid":"549689591","full_name":"mruoss/pluggable","owner":"mruoss","description":"Elixir library to build Plug-like pipelines","archived":false,"fork":false,"pushed_at":"2025-07-06T07:46:46.000Z","size":205,"stargazers_count":18,"open_issues_count":1,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-07-06T08:37:51.447Z","etag":null,"topics":["elixir","pipeline","plug"],"latest_commit_sha":null,"homepage":"","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/mruoss.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","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},"funding":{"github":["mruoss"]}},"created_at":"2022-10-11T15:23:58.000Z","updated_at":"2025-07-06T07:46:25.000Z","dependencies_parsed_at":"2023-10-10T20:26:04.753Z","dependency_job_id":"43964d91-25d0-43b7-b1d6-e151c8639453","html_url":"https://github.com/mruoss/pluggable","commit_stats":{"total_commits":102,"total_committers":4,"mean_commits":25.5,"dds":0.2941176470588235,"last_synced_commit":"66b18320a7c57a01171a2057db5a1eb17c6aa577"},"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/mruoss/pluggable","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mruoss%2Fpluggable","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mruoss%2Fpluggable/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mruoss%2Fpluggable/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mruoss%2Fpluggable/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mruoss","download_url":"https://codeload.github.com/mruoss/pluggable/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mruoss%2Fpluggable/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":265437104,"owners_count":23765100,"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":["elixir","pipeline","plug"],"created_at":"2024-08-04T01:01:57.986Z","updated_at":"2025-07-15T12:38:17.632Z","avatar_url":"https://github.com/mruoss.png","language":"Elixir","readme":"# Pluggable\n\n[![Module Version](https://img.shields.io/hexpm/v/pluggable.svg)](https://hex.pm/packages/pluggable)\n[![Coverage Status](https://coveralls.io/repos/github/mruoss/pluggable/badge.svg?branch=main)](https://coveralls.io/github/mruoss/pluggable?branch=main)\n[![Last Updated](https://img.shields.io/github/last-commit/mruoss/pluggable.svg)](https://github.com/mruoss/pluggable/commits/main)\n\n[![Build Status CI](https://github.com/mruoss/pluggable/actions/workflows/ci.yaml/badge.svg)](https://github.com/mruoss/pluggable/actions/workflows/ci.yaml)\n[![Build Status Elixir](https://github.com/mruoss/pluggable/actions/workflows/elixir_matrix.yaml/badge.svg)](https://github.com/mruoss/pluggable/actions/workflows/elixir_matrix.yaml)\n\n[![Hex Docs](https://img.shields.io/badge/hex-docs-lightgreen.svg)](https://hexdocs.pm/pluggable/)\n[![Total Download](https://img.shields.io/hexpm/dt/pluggable.svg)](https://hex.pm/packages/pluggable)\n[![License](https://img.shields.io/hexpm/l/pluggable.svg)](https://github.com/mruoss/pluggable/blob/main/LICENSE)\n\nPluggable helps to define `Plug` like pipelines but with arbitrary tokens.\nThe library comes with almost exact copies of the module `Plug` and\n`Plug.Builder`. However, instead of passing around a `%Plug.Conn{}` struct,\nthis library passes around a Token you define in your project.\n\n## Credits\n\nMost of the code in this module was copied from the\n[`:plug`](https://github.com/elixir-plug/plug/) library so credits go to the\ncreators and maintainers of `:plug`.\n\n## Installation\n\nThe package can be installed by adding `pluggable` to your list of dependencies\nin `mix.exs`:\n\n```elixir\ndef deps do\n  [\n    {:pluggable, \"~\u003e 1.0\"}\n  ]\nend\n```\n\n## Usage\n\nTo use this library, you first have to define your token. Once that\nis done, use `Pluggable.StepBuilder` to build steps and pipelines.\n\n### Deriving Pluggable.Token\n\nThe easiest way to define a token is to create a module which derives\n`Pluggable.Token` and defines a struct which, among others defines the keys:\n\n- `:halted` - the boolean status on whether the pipeline was halted\n- `:assigns` - shared user data as a map\n\nExample:\n\n```elixir\ndefmodule MyPipeline.Token do\n  @derive Pluggable.Token\n  defstruct [\n    halted: false,\n    assigns: %{},\n    # other state\n  ]\nend\n```\n\nIf the fields holding these two states are named differently, pass the fields\nas options to `@derive`:\n\n```elixir\ndefmodule MyPipeline.Token do\n  @derive {Pluggable.Token, halted_key: :stopped, assigns_key: :shared_state}\n  defstruct [\n    stopped: false,\n    shared_state: %{},\n    # other state\n  ]\nend\n```\n\n### Implementing Pluggable.Token\n\n`Pluggable.Token` can be implemented. The following is the default implementation\nwhen deriving `Pluggable.Token`\n\n```elixir\n  defmodule MyPipeline.Token do\n    defstruct [\n      halted: nil,\n      assigns: %{},\n      # other state\n    ]\n  end\n\n  defimpl Pluggable.Token, for: MyPipeline.Token do\n    def halted?(token), do: token.halted\n\n    def halt(token), do: %{token | halted: true}\n\n    def assign(%MyPipeline.Token{assigns: assigns} = token, key, value) when is_atom(key) do\n      %{token | assigns: Map.put(assigns, key, value)}\n    end\n  end\n```\n\n## Building Pipelines\n\n`Pluggable.StepBuilder` works just like `Plug.Builder`. See the\nmodule documentation for instructions.\n\n`Pluggable.PipelineBuilder` can be used to define and run multiple pipelines in \nthe same module. See the module documentation for instructions.\n\n## Code Formatting\n\nWhen using the `Pluggable.StepBuilder`, you might want to format the usage\nof the `step` macro without parens. To configure the formatter not to add\nparens, add this to your `.formatter.exs`:\n\n```elixir\n# .formatter.exs\n[\n  import_deps: [:pluggable]\n]\n```\n","funding_links":["https://github.com/sponsors/mruoss"],"categories":["Framework Components"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmruoss%2Fpluggable","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmruoss%2Fpluggable","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmruoss%2Fpluggable/lists"}