# `Reactor.Step.Group`
[🔗](https://github.com/ash-project/reactor/blob/main/lib/reactor/step/group.ex/#L6)

Wrap the execution of a number of steps with before/after functions.

Unlike `Reactor.Step.Around`, this step doesn't need to run a nested Reactor
instance, but instead can emit the steps directly into the parent Reactor.

## Options

* `before` - a three-arity function that will be called before running any
  child steps.
* `after` - a three-arity function that will be called after running any
  emitted steps.
* `allow_async?` - a boolean indicating whether the emitted steps can be
  executed asynchronously or must remain within the current process.

## Before function

The before function will be passed the following arguments:

1. `arguments` - the values of any step arguments needed by the group.
2. `context` - the Reactor context.
3. `steps` - the list of steps passed in the options.

This provides you the opportunity to modify the arguments, context and list of
steps to be executed.

The successful return value should be `{:ok, arguments, context, steps}`.  The
returned arguments will be used to provide any `input` arguments to nested
steps.

### Example

```elixir
def no_time_travel(arguments, context, steps) do
  steps = steps
    |> Enum.filter(&(&1.name == :program_time_circuits))

  arguments = arguments
    |> Map.delete(:destination_time)

  {:ok, arguments, context, steps}
end
```

## After function

The after function will be called with a single argument; a map of the nested
step results.

The successful return value should be `{:ok, any}` where `any` will be treated
as the result of the group.

```elixir
def find_current_year(results) do
  case Map.fetch(results, :time_circuits) do
    {:ok, %{present_time: present_time}} -> {:ok, present_time.year}
    _ -> {:error, "Unable to read the present time from the time circuits"}
  end
end
```

# `after_fun`

```elixir
@type after_fun() :: (Reactor.inputs() -&gt; {:ok, any()} | {:error, any()})
```

The after function.

# `after_option`

```elixir
@type after_option() :: {:after, mfa() | after_fun()}
```

The MFA or 1-arity function which this step will call after successfully
running the steps.

# `allow_async_option`

```elixir
@type allow_async_option() :: {:allow_async?, boolean()}
```

Should the emitted steps be allowed to run asynchronously?

Optional. Defaults to `true`.

# `before_fun`

```elixir
@type before_fun() :: (Reactor.inputs(), Reactor.context(), [Reactor.Step.t()] -&gt;
                   {:ok, Reactor.inputs(), Reactor.context(),
                    [Reactor.Step.t()]}
                   | {:error, any()})
```

The before function.

# `before_option`

```elixir
@type before_option() :: {:before, mfa() | before_fun()}
```

The MFA or 3-arity function which this step will call before running any
steps.

# `options`

```elixir
@type options() :: [
  before_option() | after_option() | allow_async_option() | steps_option()
]
```

# `steps_option`

```elixir
@type steps_option() :: {:steps, [Reactor.Step.t()]}
```

The initial steps to pass into the "before" function.

Optional.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
