4

I need to apply some functions to a map of values. The functions are around 900 function in the worst case so i created them as records in a database and load them at once to a map.This way i may create an admin page to manage all the conversion formulas ... one day...

Now I have them like this

conversion=%{"0":"Tools.Myfunc1/1","1":"Tools.Myfunc2/1",etc...}

then I need to apply/execute them in a map statement.

The problem is that they are as strings and i get this error

|>Stream.zip(conversion) |>Enum.map( fn {rawValue, formula} -> convertUsing(rawValue,formula) end) expected a function, got "myModule.Myfunc/1"

def convertUsing(value,formula) do
        {h,form}=formula
            value
            |>ieee
            |>form.()
     end
2
  • Do they all have an arity of 1 or could that change? Also, it looks like when you call the function in convertUsing you are expecting an arity of 0 which means no arguments. Commented Feb 2, 2016 at 15:44
  • arity of 1 always. If i just pass a &myFunc1/1 in the ConvertUsing , it works Commented Feb 2, 2016 at 15:44

2 Answers 2

8

You could prepend a & and then use Code.eval_string/1 to evaluate the contents of the string. This will give you the desired captured function:

defmodule Conversion do
  def convert_using(value, conversions) do
    conversions
    |> Enum.map(&string_to_fun/1)
    |> Enum.reduce(value, &apply(&1, [&2]))
  end

  defp string_to_fun(str) do
    {fun, _} = Code.eval_string("&#{str}")
    fun
  end
end

Then you can do:

defmodule Tools do
  def piratize(str), do: "#{str} arr!"
  def upcase(str), do: String.upcase(str)
end

"Hello, world!"
|> Conversion.convert_using(["Tools.piratize/1", "Tools.upcase/1"])
|> IO.puts

# HELLO, WORLD! ARR!

You might want to restrict the allowed functions to a certain module that contains only trivial conversions or so, otherwise you might introduce some security risk. For example:

defp string_to_fun(str) do
  {fun, _} = Code.eval_string("&Tools.#{str}")
  fun
end

And then just store "upcase/1" and so on in the database.

Sign up to request clarification or add additional context in comments.

Comments

0

Does Kernal.apply combined with String.to_atom help you? This would require you to have the function implemented in the module called by apply.

apply(<Module Name>, <:string_converted_to_atom>, [<args>])

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.