shipwithjev

Catalog / Tools & apps

0478GitHub

jev

Elixir/OTP client designed around GenServer replies and pattern matching.

dannote/jevREADME ↗
# Jev

[](https://hex.pm/packages/jev) [](https://hexdocs.pm/jev) [](https://github.com/dannote/jev/actions/workflows/ci.yml)

[TypeSafe Jev](https://docs.typesafe.ai) and compatible decision models for OTP.

Jev is a peer process. You reply to it from a GenServer, and its answer is a
message you pattern match on.

```elixir
defmodule Triage do
  use Jev.Server

  def init(_), do: {:ok, %{}}

  def handle_call({:labels, issue}, from, s) do
    {:reply, {from, issue,
       kind: {"What kind of issue is this?", %{bug: "Broken", feature: "New behavior", other: nil}},
       severity: {"How severe for users?", ["Cosmetic", "Workaround", "Blocks", "Data loss"]},
       security: "Does this describe a vulnerability?"}, s}
  end

  # Clause order is the routing. Thresholds are guards.
  def handle_answer(%{security: p}, from, s) when p > 0.5, do: done(from, [:security], s)

  def handle_answer(%{kind: :bug, severity: sev, confidence: %{kind: c}}, from, s)
      when c > 0.85 and sev >= 2,
      do: done(from, [:bug, :"priority:high"], s)

  def handle_answer(%{kind: k, confidence: %{kind: c}}, from, s) when c > 0.6, do: done(from, [k], s)
  def handle_answer(%{kind: k}, from, s), do: done(from, [k, :"needs-triage"], s)
  def handle_answer({:error, reason}, from, s), do: done(from, {:error, reason}, s)

  defp done(from, result, s) do
    GenServer.reply(from, result)
    {:noreply, s}
  end
end
```

Nothing below `handle_answer/3` touches the network, so tests call it with a
literal map. The server never blocks on Jev: a hundred calls can be in flight,
and each answer finds its clause when it lands.

## Installation

```elixir
def deps do
  [{:jev, "~> 0.1"}]
end
```

```elixir
config :jev, api_key: System.get_env("TYPESAFE_API_KEY")   # or just set TYPESAFE_API_KEY
```

Or, 

Also filed under Tools & apps