<p><div><div><div><div data-show-faces="false" data-height="21" data-width="100" data-layout="button_count" data-send="true" data-href="https://www.r-bloggers.com/transformers-glue/"></div></div><div></div></div><div></div></div>
<div>
(This article was first published on <strong><a href="http://www.questionflow.org/2018/08/21/transformers-glue/"> QuestionFlow </a></strong>, and kindly contributed to <a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers)</a> </div>
<p> General description of transformers functionality in {glue} with some potentially useful examples.</p>
<div>
<h1>Prologue</h1>
<p>Package {<a rel="nofollow" href="https://glue.tidyverse.org/index.html" target="_blank">glue</a>} is designed as â€œsmall, fast, dependency freeâ€� tools to â€œglue strings to data in Râ€�. To put simply, it provides concise and flexible alternatives for <code>paste()</code> with some additional features:</p>
<pre><code>library(glue)

x &lt;- 10
paste(&quot;I have&quot;, x, &quot;apples.&quot;)
## [1] &quot;I have 10 apples.&quot;
glue(&quot;I have {x} apples.&quot;)
## I have 10 apples.</code></pre>
<p>Recently, fate lead me to try using {glue} in a package. I was very pleased to how it makes code more readable, which I believe is a very important during package development. However, I stumbled upon this pretty unexpected behavior:</p>
<pre><code>y &lt;- NULL
paste(&quot;I have&quot;, x, &quot;apples and&quot;, y, &quot;oranges.&quot;)
## [1] &quot;I have 10 apples and  oranges.&quot;
str(glue(&quot;I have {x} apples and {y} oranges.&quot;))
## Classes 'glue', 'character'  chr(0)</code></pre>
<p>If one of the expressions is evaluated into <code>NULL</code> then the output becomes empty string. This was unintuitive result and for a while I thought about stop using {glue} because <code>NULL</code> is expected to be a valid input. However, if <a rel="nofollow" href="https://github.com/jimhester" target="_blank">Jim Hester</a> is package author, you should expect some sort of designed solution to <em>any</em> problem. This time wasnâ€<img alt="™" src="https://s.w.org/images/core/emoji/11/72x72/2122.png" class="wp-smiley">t an exception: there is a <a rel="nofollow" href="https://glue.tidyverse.org/articles/transformers.html" target="_blank">transformers</a> functionality.</p>
<p>Basically, transformer is a function that changes the output of R expressions the way you want. As I wanted to make <code>NULL</code> visible, this is a perfect way to do it.</p>
</div>
<div>
<h1>Overview</h1>
<p>This post describes an easy way to create {glue} wrappers with custom transformers. It also lists some examples that can be helpful in common tasks:</p>
<ul>
<li><strong>Transformers</strong> uses a little bit of functional programming magic to create a potentially useful transformers.</li>
</ul>
<p>Setup is very simple this time:</p>
<pre><code># {glue} was loaded in examples
# For functional programming magic
library(purrr)
# For string manipulation in one of the examples
library(stringr)</code></pre>
</div>
<div>
<h1>Transformers</h1>
<p>The task of creating wrapper for <code>glue()</code> essentially consists from two parts:</p>
<ul>
<li>Evaluate properly a supplied R expressions.</li>
<li>Modify them to show intended behavior.</li>
</ul>
<p>The <code>transforming_glue()</code> wrapper does exactly this:</p>
<pre><code>transforming_glue &lt;- function(transformer) {
  function(..., .sep = &quot;&quot;, .envir = parent.frame(), .open = &quot;{&quot;, .close = &quot;}&quot;,
           .na = &quot;NA&quot;) {
    glue(
      ..., .sep = .sep, .envir = .envir, .open = .open, .close = .close,
      .na = &quot;NA&quot;,
      .transformer = compose(transformer, identity_transformer)
    )
  }
}</code></pre>
<p>Breakdown of this code:</p>
<ul>
<li>Input is a <code>transformer</code> – function that takes an already evaluated R object and modifies it the way you want.</li>
<li>Output is a function that is a wrapper for <code>glue()</code>. Its transformer is a function composition that first evaluates R expression with <code>identity_transformer</code> (function from {glue}) and then applies supplied <code>transformer</code>. Composition here is done with <a rel="nofollow" href="https://purrr.tidyverse.org/reference/compose.html" target="_blank">compose()</a> – an element of functional programming magic from {<a rel="nofollow" href="https://purrr.tidyverse.org/" target="_blank">purrr</a>}.</li>
</ul>
<div>
<h2>Show NULL</h2>
<p>Back to initial problem. We want <code>NULL</code> to be a valid R value for a <code>glue()</code>:</p>
<pre><code>show_null &lt;- function(x, val = &quot;NULL&quot;) {
  if (is.null(x)) {
    val
  } else {
    x
  }
}

glue_null &lt;- transforming_glue(show_null)

# Example from Prologue
glue_null(&quot;I have {x} apples and {y} oranges.&quot;)
## I have 10 apples and NULL oranges.</code></pre>
</div>
<div>
<h2>Fixed width output</h2>
<p>With {<a rel="nofollow" href="https://stringr.tidyverse.org/" target="_blank">stringr</a>} package you can force an output to be fixed width:</p>
<pre><code>str_width &lt;- function(x, width) {
  if (str_length(x) > width) {
    str_trunc(x, width, side = &quot;right&quot;)
  } else {
    str_pad(x, width, side = &quot;right&quot;)
  }
}

glue_width &lt;- transforming_glue(partial(str_width, width = 10))

short_oh &lt;- &quot;Ooh!&quot;
long_oh &lt;- &quot;Oooooooooooh!&quot;
glue_width(&quot;This puzzles ({short_oh}) and surprises ({long_oh}) me.&quot;)
## This puzzles (Ooh!      ) and surprises (Ooooooo...) me.</code></pre>
<p><strong>Note</strong> usage of <a rel="nofollow" href="https://purrr.tidyverse.org/reference/partial.html" target="_blank">partial()</a> here: it takes function along with its argumentsâ€<img alt="™" src="https://s.w.org/images/core/emoji/11/72x72/2122.png" class="wp-smiley"> values and modifies it by â€œpre-fillingâ€� those arguments.</p>
</div>
<div>
<h2>Enclose output</h2>
<p>In some situation you might want to explicitly show which strings represent R objects in the output. You can do that by enclosing the output in some sort of braces:</p>
<pre><code>enclose &lt;- function(x, start = &quot;&lt;&quot;, end = &quot;>&quot;) {
  paste0(start, x, end)
}

glue_enclose &lt;- transforming_glue(enclose)

glue_enclose(&quot;What if I had {x} oranges?&quot;)
## What if I had &lt;10> oranges?</code></pre>
</div>
<div>
<h2>Bizarro encryption</h2>
<p>One possibly useful pattern is to encrypt the used data to prevent it from seeing by untrustworthy eyes. Here we will use simplified <code>bizarro()</code> example from <a rel="nofollow" href="https://www.youtube.com/watch?v=7oyiPBjLAWY" target="_blank">this insightful UseR 2018 talk</a> by the amazing <a rel="nofollow" href="https://github.com/jennybc" target="_blank">Jennifer (Jenny) Bryan</a>. Here <code>glue_bizarro()</code> â€œrevertsâ€� R objects based on their type.</p>
<pre><code>str_reverse &lt;- function(x) {
  vapply(
    strsplit(x, &quot;&quot;),
    FUN = function(z) paste(rev(z), collapse = &quot;&quot;),
    FUN.VALUE = &quot;&quot;
  )
}

bizarro &lt;- function(x) {
  cls &lt;- class(x)[[1]]
  
  switch(
    cls,
    logical = !x,
    integer = -x,
    numeric = -x,
    character = str_reverse(x),
    x
  )
}

glue_bizarro &lt;- transforming_glue(bizarro)

new_fruit &lt;- &quot;pomegranate&quot;
glue_bizarro(
  &quot;Then I might have {x + 10} apples. Is that {TRUE}?
   Maybe I want {new_fruit}?&quot;
)
## Then I might have -20 apples. Is that FALSE?
## Maybe I want etanargemop?</code></pre>
</div>
<div>
<h2>Ultimate example</h2>
<p>Using already familiar functional programming technique, we can create an ultimate <code>glue()</code> wrapper as a combination, or rather <code>compose()</code>-ition, of all previous examples. The most important part is supply them in correct order:</p>
<pre><code>glue_ultimate &lt;- transforming_glue(
  compose(
    enclose,
    partial(str_width, width = 10),
    # To ensure that input of `str_width()` is character
    as.character,
    show_null,
    bizarro
  )
)

glue_ultimate(
  &quot;I have {x} apples and {y} oranges.
   This puzzles ({short_oh}) and surprises ({long_oh}) me.
   What if I had {x} oranges?
   Then I might have {x + 10} apples. Is that {TRUE}?
   Maybe I want {new_fruit}?&quot;
)
## I have &lt;-10       > apples and </code></pre></div></div>