{"id":22750389,"url":"https://github.com/ruby2elixir/plugin","last_synced_at":"2025-04-14T12:55:05.507Z","repository":{"id":57534684,"uuid":"49765440","full_name":"ruby2elixir/plugin","owner":"ruby2elixir","description":"Plugin helps you to structure your business logic in composable blocks","archived":false,"fork":false,"pushed_at":"2016-02-19T09:53:45.000Z","size":26,"stargazers_count":4,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-03-28T02:05:20.785Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Elixir","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ruby2elixir.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-01-16T08:18:23.000Z","updated_at":"2019-04-14T14:20:34.000Z","dependencies_parsed_at":"2022-09-26T18:21:42.126Z","dependency_job_id":null,"html_url":"https://github.com/ruby2elixir/plugin","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ruby2elixir%2Fplugin","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ruby2elixir%2Fplugin/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ruby2elixir%2Fplugin/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ruby2elixir%2Fplugin/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ruby2elixir","download_url":"https://codeload.github.com/ruby2elixir/plugin/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248885681,"owners_count":21177636,"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-12-11T04:14:40.004Z","updated_at":"2025-04-14T12:55:05.477Z","avatar_url":"https://github.com/ruby2elixir.png","language":"Elixir","readme":"# `Plugin` helps you to structure your business logic in composable blocks.\n\n[![Build status](https://travis-ci.org/ruby2elixir/plugin.svg \"Build status\")](https://travis-ci.org/ruby2elixir/plugin)\n[![Hex version](https://img.shields.io/hexpm/v/plugin.svg \"Hex version\")](https://hex.pm/packages/plugin)\n![Hex downloads](https://img.shields.io/hexpm/dt/plugin.svg \"Hex downloads\")\n\n\n\nBasically a light version of [Plug](https://github.com/elixir-lang/plug). Most of the code is a straight copy from Plug,\n\nThink:\n  - `Plug` without web-specific logic and without a typed `Conn`.\n\n\n## Story\n\nAfter having structured my business logic  with `middleware` pattern recently to keep it simple, testable and composable I came to like that pattern very much.\n\nIf you take a look at [Phoenix](github.com/phoenixframework/phoenix/) you see how far this pattern can be pushed and how reusable your bits of logic become.\n\n\nSo, I'd like to have a small library to help me build small modules that can be stacked together and composed in each other. I looked on Github and found this package: https://github.com/liveforeverx/plugin.git. It's mostly a copy-paste from Plug with some changes.\n\nIt gave me the initial direction, but it had no unit tests and was quite unusable.\n\nSo, I rewrote some bits and here we are.\n\n\n\n## Installation\n\n  1. Add plugin to your list of dependencies in `mix.exs`:\n\n        def deps do\n          [{:plugin, \"~\u003e 0.1.0\"}]\n        end\n\n\n## Usage\n\nAll the rules how you structure/implement Plugs apply here:\n- Module Plugins\n- Function Plugins\n- Builder Plugins\n\n\nExample for Builder plugins:\n\n```elixir\ndefmodule Plugin1 do\n  use Plugin.Builder\n  plugin :first_fn\n\n  def first_fn(acc, _) do\n    Map.put(acc, :first_fn_passed, true)\n  end\nend\n\ndefmodule Plugin2 do\n  use Plugin.Builder\n  plugin :second_fn\n\n  def second_fn(acc, _) do\n    Map.put(acc, :second_fn_passed, true)\n  end\nend\n\ndefmodule Plugin3 do\n  use Plugin.Builder\n  plugin Plugin1\n  plugin Plugin2\nend\n\nacc = Plugin.call(Plugin3, %{})\ntrue = Map.get(acc, :first_fn_passed)\ntrue = Map.get(acc, :second_fn_passed)\n```\n\nModule Plugin:\n\n\n```elixir\ndefmodule PluginWithConfig do\n  use Plugin.Helpers # small convenience helpers\n  def init(opts) do\n    Keyword.put(opts, :current_ip, \"0.0.0.0\")\n  end\n\n  def call(acc, opts) do\n    acc\n    |\u003e assign(:from, Keyword.get(opts, :current_ip) )\n    |\u003e assign(:extra, Keyword.get(opts, :extra_info))\n  end\nend\n\ndefmodule BuilderUsesPlugingWithConfig do\n  use Plugin.Builder\n\n  plugin PluginWithConfig, extra_info: \"some_info\"\nend\n\nacc = Plugin.call(BuilderUsesPlugingWithConfig, %{})\n%{assigns: %{from: \"0.0.0.0\"}} = acc\n%{assigns: %{extra: \"some_info\"}} = acc\n```\n\n\nTo learn more about Plug please watch following freshly (2016/01) released videos:\n  - [Elixir Louisville: Plug, Friend of Web Developers](https://www.youtube.com/watch?v=-gev84S9_-c)\n  - [Elixir Louisville: Plug, Friend of Web Developers - Demo](https://www.youtube.com/watch?v=tfRD_e-yvOE)\n  - [Elixir Plug unveiled - 2015/09](https://medium.com/@kansi/elixir-plug-unveiled-bf354e364641#.phulhbtrd)\n\n\n## Most of the code is taken directly from `plug`.\n\nLicense for part of codes:\n\nCopyright (c) 2013 Plataformatec.\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n\n## Some links why you might consider \"Middleware Pattern\" as a general solution pattern even outside of web request / response cycle:\n  - https://twitter.com/mitchellh/status/237389160976101377\n  - https://twitter.com/mitchellh/status/235211110087786496\n  - http://programmers.stackexchange.com/questions/203314/what-is-the-middleware-pattern\n  - http://blog.carbonfive.com/2014/12/14/composing-data-pipelines-mostly-stateless-web-applications-in-clojure/\n  - https://speakerdeck.com/swlaschin/railway-oriented-programming-a-functional-approach-to-error-handling\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fruby2elixir%2Fplugin","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fruby2elixir%2Fplugin","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fruby2elixir%2Fplugin/lists"}