README.md


# Plumbery

[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![Hexdocs badge](https://img.shields.io/badge/docs-hexdocs-purple)](https://hexdocs.pm/plumbery)
[![Hex version badge](https://img.shields.io/hexpm/v/plumbery.svg)](https://hex.pm/packages/plumbery)

Plumbery is a framework for building pipelines in a declarative way. Pipeline
is just a function that accepts a struct and returns the same kind of struct.
This pattern is used by frameworks such as Plug and Ecto, and Plumbery may look
familiar if you used those frameworks, but it provides a generic API instead of
more specialized one. This pattern is often referred as Railway Oriented
Programming.


Plumbery provides tools for pipeline composition. A pipeline is composed from
functions (including other pipelines). When the pipeline function is called,
the functions inside the pipeline are called sequentially, stopping if one of
the functions returns an error or explicitly halts the pipeline.

All functions in a pipline accept exactly one argument called a request.
Request is a struct that must have some predefined fields used for pipeline
management, but can contain additional fields. Utilities are provided that can
generate pipeline entry functions that accept arbitrary arguments and convert
them into the struct expected by the pipeline.

```elixir
defmodule Example do
  use Plumbery
  import Plumbery.Request

  defp validate(req = %Plumbery.Request{}) do
    case req.command do
      %{number: n, mul: m} when is_integer(n) and n > 0 and is_integer(m) -> req
      _ -> error(req, :invalid_number)
    end
  end

  defp calculate(req = %Plumbery.Request{command: %{number: n, mul: m}}) do
    success(req, n * m)
  end

  pipeline :mult do
    private true
    unwrap true

    pipe :validate
    pipe :calculate
  
    inlet multiply(number, mul \\ 42), use_context: false
  end

end

{:error, :invalid_number} = Example.multiply(0)
{:ok, 126} = Example.multiply(3)
{:ok, 56} = Example.multiply(7, 8)
```