<turbo-stream action="append" target="posts_list"><template>    <div class="postbit" id="217089" data-post-id="217089">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="Sebb" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/Sebb/120/21818_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  Sebb
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Definitely use a CSV-parser. I just wanted to keep it simple.</p>
<p>I like your little template-engine, but maybe its not really beginner-friendly (and it doesn’t address the selection of the template by CSV header).</p>
<p>my solution with nimble</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">def load(csv) do
  [header | rows] = NimbleCSV.RFC4180.parse_string(csv, skip_headers: false)
  Enum.map(rows, fn row -&gt; sentence(row, header) end)
end

defp sentence([name, email, balance], ["name", "email", "balance"]) do
  "#{name}, you owe us #{balance} this month. Please see your statement here #{email}"
end

defp sentence([other, header], ["other", "header"]) do
  "#{other}, ... #{header} ..."
end
</code></pre>
<p><span class="mention">@mnussbaumer</span>’s solution is better because you don’t need to write code for the templates, could even put them in a json if you want. Just create a map <code>header -&gt; template</code> from which to select the template you need.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="217089" data-batch-url="/posts/batch_likers">
                        3
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/replacing-placeholders-in-a-string-from-csv-values/40390/12">Post #11</a>
	                </div>
	            </div>
              <div id="likers-container-217089" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="217089"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #11"></div>
  </section>
</div>
    <div class="postbit" id="217114" data-post-id="217114">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="hakarabakara" src="/assets/icons/user-9f439610.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  hakarabakara
                    <span class="op-star" title="Thread Starter">
                      <img alt="OP" class="op-star-icon" src="/assets/thread-icons/thread-icon-thread-starter-df91e872.png" />
                    </span>
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Thank you very much.</p>
<p>This works perfectly on my Ubuntu box which allows upgrading to <code>1.12</code> of elixir which introduced <code>Enum.zip_reduce</code>. Production VM runs Centos 7 so I’m stuck at <code>1.10</code> unfortunately. The IP is whitelisted by a service provider and they’ve dragged their feet in getting another whitelisted where we can have Debian</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="217114" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/replacing-placeholders-in-a-string-from-csv-values/40390/13">Post #12</a>
	                </div>
	            </div>
              <div id="likers-container-217114" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="217114"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #12"></div>
  </section>
</div>
    <div class="postbit" id="217119" data-post-id="217119">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="amnu3387" src="/assets/icons/user-9f439610.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  amnu3387
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>In the <a href="https://hexdocs.pm/elixir/Enum.html#zip_reduce/3" rel="noopener nofollow ugc">docs</a> it’s mentioned it’s basically sugar for <code>Enum.reduce(Stream.zip(enums), acc, reducer)</code></p>
<p>It should work with:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">Stream.zip(row, replacement_hs)
|&gt; Enum.reduce(template, fn {col_val, header}, acc -&gt;
      String.replace(acc, header, col_val)
end)
</code></pre>
<p>Perhaps extracting that bit into its own fun</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">@spec template_token_replacement(template :: String.t(), row :: list(String.t()), tokens :: list(String.t()) :: String.t()
def template_token_replacement(template, row, replacement_tokens) do
  row
  |&gt; Stream.zip(replacement_tokens)
  |&gt; Enum.reduce(template, fn {col_val, header}, acc -&gt;
      String.replace(acc, header, col_val)
  end)
end
</code></pre> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="217119" data-batch-url="/posts/batch_likers">
                        1
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/replacing-placeholders-in-a-string-from-csv-values/40390/14">Post #13</a>
	                </div>
	            </div>
              <div id="likers-container-217119" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="217119"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #13"></div>
  </section>
</div>
    <div class="postbit" id="217133" data-post-id="217133">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="Sebb" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/Sebb/120/21818_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  Sebb
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>I think this is more readable.</p>
<p>Another thing about the templates: just found out, that <code>EEx</code> is part of Elixir, so the templates could also be written in <code>EEx</code> (without any dependency). But as I understand it, the <code>assigns</code> have to be in the form <code>[{:atom, &lt;value&gt;}, ...]</code> so the header would have to be converted to atoms.</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">EEx.eval_string(
   "&lt;%= @name %&gt;, you owe us &lt;%= @balance %&gt; this month...",
   [name: "Wayne Campbell", balance: "$964.14", ...]
)
</code></pre> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="217133" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/replacing-placeholders-in-a-string-from-csv-values/40390/15">Post #14</a>
	                </div>
	            </div>
              <div id="likers-container-217133" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="217133"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #14"></div>
  </section>
</div>
    <div class="postbit" id="217143" data-post-id="217143">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="l00ker" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/l00ker/120/4095_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  l00ker
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="hakarabakara" data-post="13" data-topic="40390">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/letter_avatar_proxy/v4/letter/h/96bed5/48.png" class="avatar"> hakarabakara:</div>
<blockquote>
<p>Production VM runs Centos 7 so I’m stuck at <code>1.10</code> unfortunately.</p>
</blockquote>
</aside>
<p>Not necessarily. You can use a  <a href="https://hexdocs.pm/mix/Mix.Tasks.Release.html#content" rel="noopener nofollow ugc">mix release</a> which will include ERTS and the compiled Elixir app. You don’t need to have Erlang &amp; Elixir installed on the production VM. That’s the real beauty of a mix release.</p>
<hr>
<p>A little off topic but relevant to my suggestion:</p>
<p>The easiest way to do this is to install the <code>lxd</code> snap on your Ubuntu box and then launch a CentOS 7 container and shell into it.</p>
<p>Inside the CentOS 7 container install <a href="https://asdf-vm.com" rel="noopener nofollow ugc">asdf</a>, then the Erlang &amp; Elixir asdf plugins. Then install all of the dependencies required to build Erlang (see the asdf erlang plugin repo).</p>
<p>After that install Erlang &amp; Elixir via asdf, copy your mix project into the container and build the release. Upload the release the the production VM and run it.</p>
<p>It might sound like a bit much, but it’s actually not that complicated and once it’s done, you will then have the CentOS 7 container around to use for future releases as well as a playground to build and test anything else that you don’t want to install on the production CentOS server. I’ve been using LXC containers for all sorts of things like that for years now.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="217143" data-batch-url="/posts/batch_likers">
                        1
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/replacing-placeholders-in-a-string-from-csv-values/40390/16">Post #15</a>
	                </div>
	            </div>
              <div id="likers-container-217143" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="217143"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-last-post cat-last-post" title="Last post!"></div>
  </section>
</div>
</template></turbo-stream><turbo-stream action="replace" target="load-more-container"><template><div id="load-more-container" class="load-more-container">
    <span class="all-loaded">— All posts loaded —</span>
</div></template></turbo-stream>