Skip to content

Commit

Permalink
fix: fix Spark.Options.validate_type for :fun (ash-project#91)
Browse files Browse the repository at this point in the history
  • Loading branch information
vonagam authored May 1, 2024
1 parent 0d74d59 commit 86d9ff2
Showing 1 changed file with 25 additions and 40 deletions.
65 changes: 25 additions & 40 deletions lib/spark/options/options.ex
Original file line number Diff line number Diff line change
Expand Up @@ -171,8 +171,14 @@ defmodule Spark.Options do
Usually used for process initialization using `start_link` and similar. The
second element of the tuple can be any term.
* `:fun` - Any function.
* `{:fun, arity}` - Any function with the specified arity.
* `{:fun, args_types}` - A function with the specified arguments.
* `{:fun, args_types, return_type}` - A function with the specified arguments and return type.
* `{:in, choices}` or `{:one_of, choices}` - A value that is a member of one of the `choices`. `choices`
should be a list of terms or a `Range`. The value is an element in said
list of terms, that is, `value in choices` is `true`.
Expand Down Expand Up @@ -203,8 +209,6 @@ defmodule Spark.Options do
* `{:spark_type, module, builtin_function, templates}` - same as the above, but includes additional templates for elixir_sense autocomplete
* `:fun` - a function of any arity
* `:literal` -> any literal value. Maps to `:any`, but is used for documentation.
* `{:literal, value}` -> exactly the value specified.
Expand Down Expand Up @@ -395,7 +399,10 @@ defmodule Spark.Options do
| :reference
| :mfa
| :mod_arg
| :fun
| {:fun, arity :: non_neg_integer}
| {:fun, list(type)}
| {:fun, list(type), type}
| {:in, [any] | Range.t()}
| {:or,
[type | {:keyword_list, schema} | {:non_empty_keyword_list, schema} | {:map, schema}]}
Expand All @@ -415,9 +422,6 @@ defmodule Spark.Options do
| {:spark_type, module, builtin_function :: atom}
| {:spark_type, module, builtin_function :: atom, templates :: [String.t()]}
| {:struct, module}
| :fun
| {:fun, list(type)}
| {:fun, list(type), type}
| {:wrap_list, type}
| :literal
| {:literal, any}
Expand Down Expand Up @@ -948,6 +952,22 @@ defmodule Spark.Options do
)
end

defp validate_type(:fun, _key, value) when is_function(value) do
{:ok, value}
end

defp validate_type(:fun, key, value) do
error_tuple(key, value, "expected function in #{render_key(key)}, got: #{inspect(value)}")
end

defp validate_type({:fun, args}, key, value) when is_list(args) do
validate_type({:fun, length(args)}, key, value)
end

defp validate_type({:fun, args, _}, key, value) when is_list(args) do
validate_type({:fun, length(args)}, key, value)
end

defp validate_type({:fun, arity}, _key, value) when is_function(value, arity) do
{:ok, value}
end
Expand Down Expand Up @@ -1302,41 +1322,6 @@ defmodule Spark.Options do
)
end

defp validate_type(:fun, _key, value) when is_function(value) do
{:ok, value}
end

defp validate_type(:fun, key, value) when is_function(value) do
error_tuple(key, value, "expected function in #{render_key(key)}, got: #{inspect(value)}")
end

defp validate_type({:fun, args}, key, value) when is_function(value) do
expected_arity = Enum.count(args)
{:arity, actual_arity} = :erlang.fun_info(value, :arity)

if actual_arity == expected_arity do
{:ok, value}
else
error_tuple(
key,
value,
"expected function of arity #{expected_arity} #{render_key(key)}, got a function of #{actual_arity} arity"
)
end
end

defp validate_type({:fun, args}, key, value) do
error_tuple(
key,
value,
"expected function of arity #{Enum.count(args)} #{render_key(key)}, got: #{inspect(value)}"
)
end

defp validate_type({:fun, args, _}, key, value) when is_function(value) do
validate_type({:fun, args}, key, value)
end

defp validate_type({:wrap_list, type}, key, value) when not is_list(value) do
validate_type({:wrap_list, type}, key, List.wrap(value))
end
Expand Down

0 comments on commit 86d9ff2

Please sign in to comment.