How to create a string template?

There’s no ability to create a string template variable? For instance:


defmodule M1 do
  @my_str_var "aaaaa{key1}bbbbb{key2}cccc" # this

  def get_string(var1, var2) do

    # but then how to use it?

    # String.interpolate(@my_str, var1,  var2)

    # or
    # String.interpolate(@my_str, %{key1: var1, key2: var2})


  end
end

you can use EEx.

template = "aaaaa<%= key1 %>bbbbb<%= key2 %>cccc"
EEx.eval_string(template, key1: "foo", key2: "bar")
#=> "aaaaafoobbbbbbarcccc"
1 Like

It’s worth noting that EEx.eval_string isn’t very fast. The EEx module documentation has more information on its use, I would suggest that you want the function_from_string macro.

3 Likes

What’s that?

A macro that expands to a function that can render your template quickly, as it basically has been transformed into a single big string concatenation.

If though you only have a small string as in the example above, just using string interpolation might work better.

2 Likes

Details can be found in the page that I linked :slight_smile:

So to make this more clear, it would turn "aaa<%= key1 %>bbb<%= key 2%>ccc" into

fn key1, key2 -> 
  key1_string = to_string(key1)
  key2_string = to_string(key2)
  "aaa" <> key1_string <> "bbb" <> key2_string <> "ccc" 
end
1 Like

I already have a function that does that. The question is how to store a string as a template string to re-use it in the function “get_string()”.

Without using EEx which is slow.

I think the core point is that you don’t store “template strings” but you can store strings and then combine them yourself, with bespoke code or a library.

1 Like

Only when you want to evaluate the template during runtime for each time you want to apply it.

If though, you use the macros provided by eex to compile the templates at compile time of your program and inject a runtime optimized version in your code, then eex is fast enough.

phoenix uses eex by default, but is rendering templates slow? No, not really, we still manage to get sub millisecond responses, despite having to use “slow” eex.

3 Likes

Maybe my post was not clear enough: What I showed you was what a function like the function_from_string macro would do.

While the parsing part is ‘slow’ (but no slower than any way you might be able to do this manually), you only have to do it once, and then can re-use it every time you fill it in. You can even (and this is what e.g. Phoenix does) run the parsing step at compile-time.

This is the only way to store a ‘template string’ directly without using e.g. EEx would be to store it as quote do "aaa#{x}bbb#{y}ccc" end and later on ‘embed’ it from within another macro that you write. That is probably very messy.

@Nicd’s approach below is much better :slightly_smiling_face:

The simplest way:

defmodule Foo do
  def get_string(var1, var2) do
    # do stuff ...
    bar = my_tpl_str(var1, var2)
    # etc
  end

  defp my_tpl_str(k1, k2), do: "aaaaa#{k1}bbbbb#{k2}ccccc"
end
4 Likes

I will ask question than no one else did: what you do with value returned from get_string/2? If you are sending it over the wire or save it to the file, then maybe you should check iodata() instead, so your “template” would look like:

def get_string(var1, var2) when is_string(var1) and is_string(var2) do
  ["aaaaa", var1, "bbbbb", var2, "cccc"]
end

IO.puts get_string("foo", "bar") # => aaaaafoobbbbbbarcccc
5 Likes