I have a Plug with many functions that return a parameterized anonymous function, for example:
def scaling(vmin,vmax) do
fn value ->
cond do
not is_number(value) -> 0
value <= vmin -> vmin
value > vmax -> vmax
true -> value
end
end
end
The code of the Plug
defmodule Plug.RouterDataProcessor do
def init(opts), do: opts
def call(conn, opts) do
case conn.private[:process] do
nil -> conn
tasks -> process(conn,tasks, opts[:on_error])
end
end
def process(conn,tasks,on_error) do
Enum.map(tasks,do_task(Map.get(conn.body_params,"items") ))
end
def do_task(data) do
fn task ->
Enum.map(data,fn value ->fd.(value) end)
end
end
def scaling(vmin,vmax) do
fn value ->
cond do
not is_number(value) -> 0
value <= vmin -> vmin
value > vmax -> vmax
true -> value
end
end
end
end
end
The function is already declared inside the plug.
The function will be passed from the route to the plug,
So in the Route:
defmodule UsersRouter do
use RouterHelpers
use Plug.ErrorHandler
import Plug.RouterDataProcessor
plug :match
plug Plug.RouterDataProcessor, on_error: &UsersRouter.on_error_fn/2
plug :dispatch
import Plug.RouterDataProcessor
tasks=[scaling(0,100),group(1),sum(1),sort(2)] # Many function can be grouped in a list
post "/receive/", private: %{process: tasks} do
# do something with data
# then send response
send_json(conn, %{status: "success"})
end
end
But when compile get the error:
== Compilation error in file lib/routes/data_router.ex ==
** (ArgumentError) cannot escape #Function<1.72916727/1 in DataProcessor.scaling/2>. The supported values are: lists, tuples, maps, atoms, numbers, bitstrings
Then try to capture, but is a incorrect point because I need to capture the returned anonymous function.
My second attemp is use quote/unquote
def scaling(vmin,vmax) do
quote do
fn value ->
cond do
not is_number(value) -> 0
value <= unquote(vmin) -> unquote(vmin)
value > unquote(vmax) -> unquote(vmax)
true -> value
end
end
end
end
But I can’t find how to execute the quoted expression
def do_task(data) do
fn task ->
IO.inspect task # print the representation {:fn, [], ....
# try to execute
Enum.map(data,fn value ->task.(value) end)
end
end
Give me:
** (Plug.Conn.WrapperError) ** (BadFunctionError) expected a function, got:{:fn, [], …
I does not know why have this problem because if I run all inside the “post”,
the code run ok.
post "/datapro/" do
send_json(conn, %{ t: process(conn,[scaling(5,25)],&UsersRouter.on_error_fn/2)})
end
I am newbie, so is good to resolve with the quoted aproach, or there is any better way ?
Is there any performance drawback when use AST representation ?
How can resolve it ?