# `Igniter.Code.Function`
[🔗](https://github.com/ash-project/igniter/blob/v0.8.2/lib/igniter/code/function.ex#L5)

Utilities for working with functions.

# `append_argument`

```elixir
@spec append_argument(Sourceror.Zipper.t(), any()) ::
  {:ok, Sourceror.Zipper.t()} | :error
```

Appends an argument to a function call, leaving the zipper at the function call's node.

# `argument_equals?`

```elixir
@spec argument_equals?(Sourceror.Zipper.t(), integer(), any()) :: boolean()
```

Checks if the provided function call (in a Zipper) has an argument that equals
`term` at `index`.

# `argument_matches_pattern?`
*macro* 

Returns `true` if the argument at the provided index exists and matches the provided pattern

Note: to check for argument equality, use `argument_equals?/3` instead.

# `argument_matches_predicate?`

```elixir
@spec argument_matches_predicate?(
  Sourceror.Zipper.t(),
  non_neg_integer(),
  (Sourceror.Zipper.t() -&gt;
     boolean())
) :: boolean()
```

Returns true if the argument at the given index matches the provided predicate

# `function?`

```elixir
@spec function?(
  Sourceror.Zipper.t(),
  name :: :any | :any_named | {module(), atom()} | :anonymous,
  arity :: :any | non_neg_integer() | [non_neg_integer()]
) :: boolean()
```

Returns true if the value is a function literal.

Examples:
  - `fn x -> x end`
  - `&(&1 + &2)`
  - `&SomeMod.fun/2`

To refine the check, you can use `name` and `arity`.

## Names

- `:any` - matches any function literal, named or not
- `:any_named` - matches any named function literal
- `:anonymous` - matches any anonymous function literal
- `{module, name}` - matches a function literal with the given module and name

# `function_call?`

```elixir
@spec function_call?(Sourceror.Zipper.t()) :: boolean()
```

Returns `true` if the node is a function call

# `function_call?`

```elixir
@spec function_call?(
  Sourceror.Zipper.t(),
  atom() | {module(), atom()},
  arity :: integer() | :any | [integer()]
) :: boolean()
```

Returns `true` if the node is a function call of the given name

If an `atom` is provided, it only matches functions in the form of `function(name)`.

If an `{module, atom}` is provided, it matches functions called on the given module,
taking into account any imports or aliases.

# `get_local_function_call`

```elixir
@spec get_local_function_call(Sourceror.Zipper.t()) ::
  {:ok, {atom(), non_neg_integer()}} | :error
```

Gets the name and arity of a local function call.

Returns `:error` if the node is not a function call or cannot be determined.

# `get_local_function_call_name`

```elixir
@spec get_local_function_call_name(Sourceror.Zipper.t()) :: {:ok, atom()} | :error
```

Gets the name of a local function call.

Returns `:error` if the node is not a function call or cannot be determined.

# `move_to_def`

```elixir
@spec move_to_def(Sourceror.Zipper.t(), Keyword.t()) ::
  {:ok, Sourceror.Zipper.t()} | :error
```

# `move_to_def`

```elixir
@spec move_to_def(
  Sourceror.Zipper.t(),
  fun :: atom(),
  arity :: integer() | [integer()] | :any,
  Keyword.t()
) :: {:ok, Sourceror.Zipper.t()} | :error
```

Moves the zipper to a function definition by the given name and arity. You may
also pass in a :target option to specify where in the function you want to
move to. By default it will move to the inside of the function.
The `:target` option can be one of the following:
- `:inside` - moves to the inside of the function
- `:before` - moves to before the function and takes into consideration the
  attributes `@doc`, `@spec`, and `@impl` if they exist
- `:at` - moves to the function definition itself. Use this if you want to add
  code directly before or directly after the function.

## Example - Moves before the function.

```elixir
zipper =
  """
  defmodule Test do
    @doc "hello"
    @spec hello() :: :world
    def hello() do
      :world
    end
  end
  """
  |> Sourceror.parse_string!()
  |> Zipper.zip()

{:ok, zipper} = Igniter.Code.Function.move_to_function_and_attrs(zipper, :hello, 0)

zipper =
  Igniter.Code.Common.add_code(
    zipper,
    """
    def world() do
      :hello
    end
    """,
    placement: :before
  )

Igniter.Util.Debug.code_at_node(Zipper.topmost(zipper))
# defmodule Test do
#   def world() do
#     :hello
#   end
#
#   @doc "hello"
#   @spec hello() :: :world
#   def hello() do
#     :world
#   end
# end
```

# `move_to_defp`

```elixir
@spec move_to_defp(
  Sourceror.Zipper.t(),
  fun :: atom(),
  arity :: integer() | [integer()],
  Keyword.t()
) ::
  {:ok, Sourceror.Zipper.t()} | :error
```

# `move_to_function_call`

Moves to a function call by the given name and arity, matching the given predicate, in the current or lower scope

# `move_to_function_call_in_current_scope`

Moves to a function call by the given name and arity, matching the given predicate, in the current scope

# `move_to_nth_argument`

```elixir
@spec move_to_nth_argument(
  Sourceror.Zipper.t(),
  non_neg_integer()
) :: {:ok, Sourceror.Zipper.t()} | :error
```

Moves to the `nth` argument of a function call.

# `update_nth_argument`

```elixir
@spec update_nth_argument(
  Sourceror.Zipper.t(),
  non_neg_integer(),
  (Sourceror.Zipper.t() -&gt; {:ok, Sourceror.Zipper.t()} | :error | term())
) :: {:ok, Sourceror.Zipper.t()} | :error | term()
```

Updates the `nth` argument of a function call, leaving the zipper at the function call's node.

---

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