README.md

# Horus: anonymous function to standalone module

[![Hex.pm](https://img.shields.io/hexpm/v/horus)](https://hex.pm/packages/horus/)
[![Test](https://github.com/rabbitmq/horus/actions/workflows/test.yaml/badge.svg)](https://github.com/rabbitmq/horus/actions/workflows/test.yaml)
[![Codecov](https://codecov.io/gh/rabbitmq/horus/branch/main/graph/badge.svg?token=R0OGKZ2RK2)](https://codecov.io/gh/rabbitmq/horus)

Horus is a library that extracts an anonymous function's code and creates a
standalone version of it in a new module at runtime.

The goal is to have a storable and transferable function which does not depend
on the availability of the module that defined it.

<img align="right" height="150" src="/doc/horus-logo.svg">

## How does it work?

To achieve that goal, Horus extracts the assembly code of the anonymous
function and creates a standalone Erlang module based on it. This module can be
stored, transfered to another Erlang node and executed anywhere without the
presence of the initial anonymous function's module.

## Project maturity

Horus is still under active development and should be considered *Alpha* at
this stage.

## Documentation

* A short tutorial in the [Getting started](#getting-started) section below
* [Documentation and API reference](https://rabbitmq.github.io/horus/)

## Getting started

### Add as a dependency

Add Horus as a dependency of your project:

Using Rebar:

```erlang
%% In rebar.config
{deps, [{horus, "0.2.1"}]}.
```

Using Erlang.mk:

```make
# In your Makefile
DEPS += horus
dep_horus = hex 0.2.1
```

Using Mix:

```elixir
# In mix.exs
defp deps do
  [
    :horus, "0.2.1"}
  ]
end
```

### Extract an anonymous function

To extract an anonymous function, use `horus:to_standalone_fun/1`:

```erlang
Fun = fun() ->
          do_something_fancy()
      end,

StandaloneFun = horus:to_standalone_fun(Fun).
```

It works with references to regular functions are well:

```erlang
Log = fun logger:info/2,

StandaloneLog = horus:to_standalone_fun(Log).
```

### Execute a standalone function

Once extracted, the function can be stored as an Erlang binary, or transfered
to a remote Erlang node. You then use `horus:exec/2` to execute it:

```erlang
receive
    {standalone_fun, StandaloneLog} ->
        horus:exec(
          StandaloneLog,
          ["~p received and executed function", [self()]])
end.
```

## How to build

### Build

```
rebar3 compile
```

### Build documentation

```
rebar3 edoc
```

### Test

```
rebar3 xref
rebar3 eunit
rebar3 ct --sname ct
rebar3 as test dialyzer
```

## Copyright and License

© 2021-2023 VMware, Inc. or its affiliates.

This work is dual-licensed under the Apache License 2.0 and the Mozilla Public
License 2.0. You can choose between one of them if you use this work.

SPDX-License-Identifier: Apache-2.0 OR MPL-2.0