Passing anonymous function as plug option

I can’t seem to pass an anonymous function as an option to a Plug. I am using plug_hmouse which from the documentation takes an option digest that is a function to be called on a string. The example is provided below:

plug PlugHMouse,
  ... # other options
  digest: fn string -> Base.encode16(string) end

However when I try this in my router.ex, I get the following error:

router.ex

plug PlugHMouse,
  validate: {"x-hub-signature", webhook_secret},
  hash_algo: :sha,
  split_digest: true,
  digest: fn string -> Base.encode16(string, :lower) end

error

== Compilation error in file lib/spellcanary_web/router.ex ==
** (ArgumentError) cannot escape #Function<0.85932033 in file:lib/spellcanary_web/router.ex>. The supported values are: lists, tuples, maps, atoms, numbers, bitstrings, PIDs and remote functions in the format &Mod.fun/arity
    (elixir) src/elixir_quote.erl:122: :elixir_quote.argument_error/1
    (elixir) src/elixir_quote.erl:259: :elixir_quote.do_quote/3
    (elixir) src/elixir_quote.erl:421: :elixir_quote.do_quote_splice/5
    (plug) lib/plug/builder.ex:312: Plug.Builder.init_module_plug/4
    (plug) lib/plug/builder.ex:286: anonymous fn/5 in Plug.Builder.compile/3
    (elixir) lib/enum.ex:1940: Enum."-reduce/3-lists^foldl/2-0-"/3
    (plug) lib/plug/builder.ex:284: Plug.Builder.compile/3
    lib/spellcanary_web/router.ex:17: (module)
    (stdlib) erl_eval.erl:680: :erl_eval.do_apply/6
    (elixir) lib/kernel/parallel_compiler.ex:208: anonymous fn/4 in Kernel.ParallelCompiler.spawn_workers/6

I don’t get this error when passing &Base.encode16/1 but I do get it when using an anonymous function or when defining a function in my router and passing that, eg.

def encode16lower(string) do
  Base.encode16(string, :lower)
end

...
plug PlugHMouse,
  validate: {"x-hub-signature", webhook_secret},
  hash_algo: :sha,
  split_digest: true,
  digest: &self().encode16lower/1

I need the anonymous function since I want to add an extra argument to the function I’m calling. How can I get around this error?

1 Like

Module attributes can not contain anonymous functions. They may only contain a very strict subset of values. Whereas &Mod.fun/arit is one of these.

&self().encode16lower/1

self() does not return a module name, but a PID. Probably you meant __MODULE__.encode16lower/1?

3 Likes

Thanks NobbZ, the __MODULE__ tip fixed the error! I didn’t realise that calling plug would create a module attribute. For anyone reading this thread in future, the docs on Module attributes actually have some info on this.

3 Likes