arjan / decorator

Function decorators for Elixir
MIT License
385 stars 20 forks source link

Unquoting default params results in elixir_locals.ensure_no_undefined_local/3 #48

Open spencerdcarlson opened 3 years ago

spencerdcarlson commented 3 years ago

Definition

defmodule ArgsValidator do
  use Decorator.Define, validate: 1

  def validate(_, _, %{args: function_args}) do
    quote do: unquote(function_args)
  end
end

Usage

use ArgsValidator

@decorate validate([&Ecto.UUID.cast/1])
  defdelegate resource(uuid, opts \\ []),
    to: ResourceByUUID,
    as: :call
    (elixir) src/elixir_locals.erl:108: :elixir_locals."-ensure_no_undefined_local/3-lc$^0/1-0-"/2
    (elixir) src/elixir_locals.erl:108: anonymous fn/3 in :elixir_locals.ensure_no_undefined_local/3
    (stdlib) erl_eval.erl:680: :erl_eval.do_apply/6
** (exit) shutdown: 1
    (mix) lib/mix/tasks/compile.all.ex:59: Mix.Tasks.Compile.All.do_compile/4
    (mix) lib/mix/tasks/compile.all.ex:24: anonymous fn/1 in Mix.Tasks.Compile.All.run/1
    (mix) lib/mix/tasks/compile.all.ex:40: Mix.Tasks.Compile.All.with_logger_app/1
    (mix) lib/mix/task.ex:331: Mix.Task.run_task/3
    (mix) lib/mix/tasks/compile.ex:96: Mix.Tasks.Compile.run/1
    (mix) lib/mix/task.ex:331: Mix.Task.run_task/3
    (iex) lib/iex/helpers.ex:104: IEx.Helpers.recompile/1
Ivor commented 2 years ago

Printing out the args returns this for the variable with the default value:

{:\\, [line: 170], [{:attrs, [line: 170], nil}, {:%{}, [line: 170], []}]}

and returns this compile error:

....ex:170: undefined function \\/2
Ivor commented 2 years ago

Not something I am very familiar with, but I am wondering if this would work:

    args_with_or_default =
      Enum.reduce(args, [], fn
        {:\\, _line, [{_var_name, _var_line, nil}, _default_value]} = ast_for_default, acc ->
          new_ast_for_default =
            ast_for_default
            |> Tuple.delete_at(0)
            |> Tuple.insert_at(0, :||)

          acc ++ [new_ast_for_default]

        arg, acc ->
          acc ++ [arg]
      end)

And then using args_with_or_default as the args.