2025-01-12 04:36:52 +08:00

576 lines
33 KiB
HTML
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="generator" content="pandoc" />
<meta http-equiv="X-UA-Compatible" content="IE=EDGE" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Transformers</title>
<script>// Pandoc 2.9 adds attributes on both header and div. We remove the former (to
// be compatible with the behavior of Pandoc < 2.8).
document.addEventListener('DOMContentLoaded', function(e) {
var hs = document.querySelectorAll("div.section[class*='level'] > :first-child");
var i, h, a;
for (i = 0; i < hs.length; i++) {
h = hs[i];
if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6
a = h.attributes;
while (a.length > 0) h.removeAttribute(a[0].name);
}
});
</script>
<style type="text/css">
code{white-space: pre-wrap;}
span.smallcaps{font-variant: small-caps;}
span.underline{text-decoration: underline;}
div.column{display: inline-block; vertical-align: top; width: 50%;}
div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
ul.task-list{list-style: none;}
</style>
<style type="text/css">
code {
white-space: pre;
}
.sourceCode {
overflow: visible;
}
</style>
<style type="text/css" data-origin="pandoc">
pre > code.sourceCode { white-space: pre; position: relative; }
pre > code.sourceCode > span { line-height: 1.25; }
pre > code.sourceCode > span:empty { height: 1.2em; }
.sourceCode { overflow: visible; }
code.sourceCode > span { color: inherit; text-decoration: inherit; }
div.sourceCode { margin: 1em 0; }
pre.sourceCode { margin: 0; }
@media screen {
div.sourceCode { overflow: auto; }
}
@media print {
pre > code.sourceCode { white-space: pre-wrap; }
pre > code.sourceCode > span { display: inline-block; text-indent: -5em; padding-left: 5em; }
}
pre.numberSource code
{ counter-reset: source-line 0; }
pre.numberSource code > span
{ position: relative; left: -4em; counter-increment: source-line; }
pre.numberSource code > span > a:first-child::before
{ content: counter(source-line);
position: relative; left: -1em; text-align: right; vertical-align: baseline;
border: none; display: inline-block;
-webkit-touch-callout: none; -webkit-user-select: none;
-khtml-user-select: none; -moz-user-select: none;
-ms-user-select: none; user-select: none;
padding: 0 4px; width: 4em;
color: #aaaaaa;
}
pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa; padding-left: 4px; }
div.sourceCode
{ }
@media screen {
pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
}
code span.al { color: #ff0000; font-weight: bold; }
code span.an { color: #60a0b0; font-weight: bold; font-style: italic; }
code span.at { color: #7d9029; }
code span.bn { color: #40a070; }
code span.bu { color: #008000; }
code span.cf { color: #007020; font-weight: bold; }
code span.ch { color: #4070a0; }
code span.cn { color: #880000; }
code span.co { color: #60a0b0; font-style: italic; }
code span.cv { color: #60a0b0; font-weight: bold; font-style: italic; }
code span.do { color: #ba2121; font-style: italic; }
code span.dt { color: #902000; }
code span.dv { color: #40a070; }
code span.er { color: #ff0000; font-weight: bold; }
code span.ex { }
code span.fl { color: #40a070; }
code span.fu { color: #06287e; }
code span.im { color: #008000; font-weight: bold; }
code span.in { color: #60a0b0; font-weight: bold; font-style: italic; }
code span.kw { color: #007020; font-weight: bold; }
code span.op { color: #666666; }
code span.ot { color: #007020; }
code span.pp { color: #bc7a00; }
code span.sc { color: #4070a0; }
code span.ss { color: #bb6688; }
code span.st { color: #4070a0; }
code span.va { color: #19177c; }
code span.vs { color: #4070a0; }
code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; }
</style>
<script>
// apply pandoc div.sourceCode style to pre.sourceCode instead
(function() {
var sheets = document.styleSheets;
for (var i = 0; i < sheets.length; i++) {
if (sheets[i].ownerNode.dataset["origin"] !== "pandoc") continue;
try { var rules = sheets[i].cssRules; } catch (e) { continue; }
var j = 0;
while (j < rules.length) {
var rule = rules[j];
// check if there is a div.sourceCode rule
if (rule.type !== rule.STYLE_RULE || rule.selectorText !== "div.sourceCode") {
j++;
continue;
}
var style = rule.style.cssText;
// check if color or background-color is set
if (rule.style.color === '' && rule.style.backgroundColor === '') {
j++;
continue;
}
// replace div.sourceCode by a pre.sourceCode rule
sheets[i].deleteRule(j);
sheets[i].insertRule('pre.sourceCode{' + style + '}', j);
}
}
})();
</script>
<style type="text/css">body {
background-color: #fff;
margin: 1em auto;
max-width: 700px;
overflow: visible;
padding-left: 2em;
padding-right: 2em;
font-family: "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 14px;
line-height: 1.35;
}
#TOC {
clear: both;
margin: 0 0 10px 10px;
padding: 4px;
width: 400px;
border: 1px solid #CCCCCC;
border-radius: 5px;
background-color: #f6f6f6;
font-size: 13px;
line-height: 1.3;
}
#TOC .toctitle {
font-weight: bold;
font-size: 15px;
margin-left: 5px;
}
#TOC ul {
padding-left: 40px;
margin-left: -1.5em;
margin-top: 5px;
margin-bottom: 5px;
}
#TOC ul ul {
margin-left: -2em;
}
#TOC li {
line-height: 16px;
}
table {
margin: 1em auto;
border-width: 1px;
border-color: #DDDDDD;
border-style: outset;
border-collapse: collapse;
}
table th {
border-width: 2px;
padding: 5px;
border-style: inset;
}
table td {
border-width: 1px;
border-style: inset;
line-height: 18px;
padding: 5px 5px;
}
table, table th, table td {
border-left-style: none;
border-right-style: none;
}
table thead, table tr.even {
background-color: #f7f7f7;
}
p {
margin: 0.5em 0;
}
blockquote {
background-color: #f6f6f6;
padding: 0.25em 0.75em;
}
hr {
border-style: solid;
border: none;
border-top: 1px solid #777;
margin: 28px 0;
}
dl {
margin-left: 0;
}
dl dd {
margin-bottom: 13px;
margin-left: 13px;
}
dl dt {
font-weight: bold;
}
ul {
margin-top: 0;
}
ul li {
list-style: circle outside;
}
ul ul {
margin-bottom: 0;
}
pre, code {
background-color: #f7f7f7;
border-radius: 3px;
color: #333;
white-space: pre-wrap;
}
pre {
border-radius: 3px;
margin: 5px 0px 10px 0px;
padding: 10px;
}
pre:not([class]) {
background-color: #f7f7f7;
}
code {
font-family: Consolas, Monaco, 'Courier New', monospace;
font-size: 85%;
}
p > code, li > code {
padding: 2px 0px;
}
div.figure {
text-align: center;
}
img {
background-color: #FFFFFF;
padding: 2px;
border: 1px solid #DDDDDD;
border-radius: 3px;
border: 1px solid #CCCCCC;
margin: 0 5px;
}
h1 {
margin-top: 0;
font-size: 35px;
line-height: 40px;
}
h2 {
border-bottom: 4px solid #f7f7f7;
padding-top: 10px;
padding-bottom: 2px;
font-size: 145%;
}
h3 {
border-bottom: 2px solid #f7f7f7;
padding-top: 10px;
font-size: 120%;
}
h4 {
border-bottom: 1px solid #f7f7f7;
margin-left: 8px;
font-size: 105%;
}
h5, h6 {
border-bottom: 1px solid #ccc;
font-size: 105%;
}
a {
color: #0033dd;
text-decoration: none;
}
a:hover {
color: #6666ff; }
a:visited {
color: #800080; }
a:visited:hover {
color: #BB00BB; }
a[href^="http:"] {
text-decoration: underline; }
a[href^="https:"] {
text-decoration: underline; }
code > span.kw { color: #555; font-weight: bold; }
code > span.dt { color: #902000; }
code > span.dv { color: #40a070; }
code > span.bn { color: #d14; }
code > span.fl { color: #d14; }
code > span.ch { color: #d14; }
code > span.st { color: #d14; }
code > span.co { color: #888888; font-style: italic; }
code > span.ot { color: #007020; }
code > span.al { color: #ff0000; font-weight: bold; }
code > span.fu { color: #900; font-weight: bold; }
code > span.er { color: #a61717; background-color: #e3d2d2; }
</style>
</head>
<body>
<h1 class="title toc-ignore">Transformers</h1>
<p>Transformers allow you to apply functions to the glue input and
output, before and after evaluation. This allows you to write things
like <code>glue_sql()</code>, which automatically quotes variables for
you or add a syntax for automatically collapsing outputs.</p>
<p>The transformer functions simply take two arguments <code>text</code>
and <code>envir</code>, where <code>text</code> is the unparsed string
inside the glue block and <code>envir</code> is the execution
environment. Most transformers will then call
<code>eval(parse(text = text, keep.source = FALSE), envir)</code> which
parses and evaluates the code.</p>
<p>You can then supply the transformer function to glue with the
<code>.transformer</code> argument. In this way users can manipulate the
text before parsing and change the output after evaluation.</p>
<p>It is often useful to write a <code>glue()</code> wrapper function
which supplies a <code>.transformer</code> to <code>glue()</code> or
<code>glue_data()</code> and potentially has additional arguments. One
important consideration when doing this is to include
<code>.envir = parent.frame()</code> in the wrapper to ensure the
evaluation environment is correct.</p>
<p>Some example implementations of potentially useful transformers
follow. The aim right now is not to include most of these custom
functions within the <code>glue</code> package. Rather, users are
encouraged to create custom functions using transformers to fit their
individual needs.</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode r"><code class="sourceCode r"><span id="cb1-1"><a href="#cb1-1" tabindex="-1"></a><span class="fu">library</span>(glue)</span></code></pre></div>
<div id="collapse-transformer" class="section level3">
<h3>collapse transformer</h3>
<p>A transformer which automatically collapses any glue block ending
with <code>*</code>.</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode r"><code class="sourceCode r"><span id="cb2-1"><a href="#cb2-1" tabindex="-1"></a>collapse_transformer <span class="ot">&lt;-</span> <span class="cf">function</span>(<span class="at">regex =</span> <span class="st">&quot;[*]$&quot;</span>, ...) {</span>
<span id="cb2-2"><a href="#cb2-2" tabindex="-1"></a> <span class="cf">function</span>(text, envir) {</span>
<span id="cb2-3"><a href="#cb2-3" tabindex="-1"></a> collapse <span class="ot">&lt;-</span> <span class="fu">grepl</span>(regex, text)</span>
<span id="cb2-4"><a href="#cb2-4" tabindex="-1"></a> <span class="cf">if</span> (collapse) {</span>
<span id="cb2-5"><a href="#cb2-5" tabindex="-1"></a> text <span class="ot">&lt;-</span> <span class="fu">sub</span>(regex, <span class="st">&quot;&quot;</span>, text)</span>
<span id="cb2-6"><a href="#cb2-6" tabindex="-1"></a> }</span>
<span id="cb2-7"><a href="#cb2-7" tabindex="-1"></a> res <span class="ot">&lt;-</span> <span class="fu">identity_transformer</span>(text, envir)</span>
<span id="cb2-8"><a href="#cb2-8" tabindex="-1"></a> <span class="cf">if</span> (collapse) {</span>
<span id="cb2-9"><a href="#cb2-9" tabindex="-1"></a> <span class="fu">glue_collapse</span>(res, ...) </span>
<span id="cb2-10"><a href="#cb2-10" tabindex="-1"></a> } <span class="cf">else</span> {</span>
<span id="cb2-11"><a href="#cb2-11" tabindex="-1"></a> res</span>
<span id="cb2-12"><a href="#cb2-12" tabindex="-1"></a> }</span>
<span id="cb2-13"><a href="#cb2-13" tabindex="-1"></a> }</span>
<span id="cb2-14"><a href="#cb2-14" tabindex="-1"></a>}</span>
<span id="cb2-15"><a href="#cb2-15" tabindex="-1"></a></span>
<span id="cb2-16"><a href="#cb2-16" tabindex="-1"></a><span class="fu">glue</span>(<span class="st">&quot;{1:5*}</span><span class="sc">\n</span><span class="st">{letters[1:5]*}&quot;</span>, <span class="at">.transformer =</span> <span class="fu">collapse_transformer</span>(<span class="at">sep =</span> <span class="st">&quot;, &quot;</span>))</span>
<span id="cb2-17"><a href="#cb2-17" tabindex="-1"></a><span class="co">#&gt; 1, 2, 3, 4, 5</span></span>
<span id="cb2-18"><a href="#cb2-18" tabindex="-1"></a><span class="co">#&gt; a, b, c, d, e</span></span>
<span id="cb2-19"><a href="#cb2-19" tabindex="-1"></a></span>
<span id="cb2-20"><a href="#cb2-20" tabindex="-1"></a><span class="fu">glue</span>(<span class="st">&quot;{1:5*}</span><span class="sc">\n</span><span class="st">{letters[1:5]*}&quot;</span>, <span class="at">.transformer =</span> <span class="fu">collapse_transformer</span>(<span class="at">sep =</span> <span class="st">&quot;, &quot;</span>, <span class="at">last =</span> <span class="st">&quot; and &quot;</span>))</span>
<span id="cb2-21"><a href="#cb2-21" tabindex="-1"></a><span class="co">#&gt; 1, 2, 3, 4 and 5</span></span>
<span id="cb2-22"><a href="#cb2-22" tabindex="-1"></a><span class="co">#&gt; a, b, c, d and e</span></span>
<span id="cb2-23"><a href="#cb2-23" tabindex="-1"></a></span>
<span id="cb2-24"><a href="#cb2-24" tabindex="-1"></a>x <span class="ot">&lt;-</span> <span class="fu">c</span>(<span class="st">&quot;one&quot;</span>, <span class="st">&quot;two&quot;</span>)</span>
<span id="cb2-25"><a href="#cb2-25" tabindex="-1"></a><span class="fu">glue</span>(<span class="st">&quot;{x}: {1:5*}&quot;</span>, <span class="at">.transformer =</span> <span class="fu">collapse_transformer</span>(<span class="at">sep =</span> <span class="st">&quot;, &quot;</span>))</span>
<span id="cb2-26"><a href="#cb2-26" tabindex="-1"></a><span class="co">#&gt; one: 1, 2, 3, 4, 5</span></span>
<span id="cb2-27"><a href="#cb2-27" tabindex="-1"></a><span class="co">#&gt; two: 1, 2, 3, 4, 5</span></span></code></pre></div>
</div>
<div id="shell-quoting-transformer" class="section level3">
<h3>Shell quoting transformer</h3>
<p>A transformer which automatically quotes variables for use in shell
commands, e.g. via <code>system()</code> or <code>system2()</code>.</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode r"><code class="sourceCode r"><span id="cb3-1"><a href="#cb3-1" tabindex="-1"></a>shell_transformer <span class="ot">&lt;-</span> <span class="cf">function</span>(<span class="at">type =</span> <span class="fu">c</span>(<span class="st">&quot;sh&quot;</span>, <span class="st">&quot;csh&quot;</span>, <span class="st">&quot;cmd&quot;</span>, <span class="st">&quot;cmd2&quot;</span>)) {</span>
<span id="cb3-2"><a href="#cb3-2" tabindex="-1"></a> type <span class="ot">&lt;-</span> <span class="fu">match.arg</span>(type)</span>
<span id="cb3-3"><a href="#cb3-3" tabindex="-1"></a> <span class="cf">function</span>(text, envir) {</span>
<span id="cb3-4"><a href="#cb3-4" tabindex="-1"></a> res <span class="ot">&lt;-</span> <span class="fu">identity_transformer</span>(text, envir)</span>
<span id="cb3-5"><a href="#cb3-5" tabindex="-1"></a> <span class="fu">shQuote</span>(res)</span>
<span id="cb3-6"><a href="#cb3-6" tabindex="-1"></a> }</span>
<span id="cb3-7"><a href="#cb3-7" tabindex="-1"></a>}</span>
<span id="cb3-8"><a href="#cb3-8" tabindex="-1"></a></span>
<span id="cb3-9"><a href="#cb3-9" tabindex="-1"></a>glue_sh <span class="ot">&lt;-</span> <span class="cf">function</span>(..., <span class="at">.envir =</span> <span class="fu">parent.frame</span>(), <span class="at">.type =</span> <span class="fu">c</span>(<span class="st">&quot;sh&quot;</span>, <span class="st">&quot;csh&quot;</span>, <span class="st">&quot;cmd&quot;</span>, <span class="st">&quot;cmd2&quot;</span>)) {</span>
<span id="cb3-10"><a href="#cb3-10" tabindex="-1"></a> .type <span class="ot">&lt;-</span> <span class="fu">match.arg</span>(.type)</span>
<span id="cb3-11"><a href="#cb3-11" tabindex="-1"></a> <span class="fu">glue</span>(..., <span class="at">.envir =</span> .envir, <span class="at">.transformer =</span> <span class="fu">shell_transformer</span>(.type))</span>
<span id="cb3-12"><a href="#cb3-12" tabindex="-1"></a></span>
<span id="cb3-13"><a href="#cb3-13" tabindex="-1"></a>}</span>
<span id="cb3-14"><a href="#cb3-14" tabindex="-1"></a></span>
<span id="cb3-15"><a href="#cb3-15" tabindex="-1"></a>filename <span class="ot">&lt;-</span> <span class="st">&quot;test&quot;</span></span>
<span id="cb3-16"><a href="#cb3-16" tabindex="-1"></a><span class="fu">writeLines</span>(<span class="at">con =</span> filename, <span class="st">&quot;hello!&quot;</span>)</span>
<span id="cb3-17"><a href="#cb3-17" tabindex="-1"></a></span>
<span id="cb3-18"><a href="#cb3-18" tabindex="-1"></a>command <span class="ot">&lt;-</span> <span class="fu">glue_sh</span>(<span class="st">&quot;cat {filename}&quot;</span>)</span>
<span id="cb3-19"><a href="#cb3-19" tabindex="-1"></a>command</span>
<span id="cb3-20"><a href="#cb3-20" tabindex="-1"></a><span class="co">#&gt; cat &#39;test&#39;</span></span>
<span id="cb3-21"><a href="#cb3-21" tabindex="-1"></a><span class="fu">system</span>(command)</span></code></pre></div>
</div>
<div id="emoji-transformer" class="section level3">
<h3>emoji transformer</h3>
<p>A transformer which converts the text to the equivalent emoji.</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode r"><code class="sourceCode r"><span id="cb4-1"><a href="#cb4-1" tabindex="-1"></a>emoji_transformer <span class="ot">&lt;-</span> <span class="cf">function</span>(text, envir) {</span>
<span id="cb4-2"><a href="#cb4-2" tabindex="-1"></a> <span class="cf">if</span> (<span class="fu">grepl</span>(<span class="st">&quot;[*]$&quot;</span>, text)) {</span>
<span id="cb4-3"><a href="#cb4-3" tabindex="-1"></a> text <span class="ot">&lt;-</span> <span class="fu">sub</span>(<span class="st">&quot;[*]$&quot;</span>, <span class="st">&quot;&quot;</span>, text)</span>
<span id="cb4-4"><a href="#cb4-4" tabindex="-1"></a> <span class="fu">glue_collapse</span>(<span class="fu">ji_find</span>(text)<span class="sc">$</span>emoji)</span>
<span id="cb4-5"><a href="#cb4-5" tabindex="-1"></a> } <span class="cf">else</span> {</span>
<span id="cb4-6"><a href="#cb4-6" tabindex="-1"></a> <span class="fu">ji</span>(text)</span>
<span id="cb4-7"><a href="#cb4-7" tabindex="-1"></a> }</span>
<span id="cb4-8"><a href="#cb4-8" tabindex="-1"></a>}</span>
<span id="cb4-9"><a href="#cb4-9" tabindex="-1"></a></span>
<span id="cb4-10"><a href="#cb4-10" tabindex="-1"></a>glue_ji <span class="ot">&lt;-</span> <span class="cf">function</span>(..., <span class="at">.envir =</span> <span class="fu">parent.frame</span>()) {</span>
<span id="cb4-11"><a href="#cb4-11" tabindex="-1"></a> <span class="fu">glue</span>(..., <span class="at">.open =</span> <span class="st">&quot;:&quot;</span>, <span class="at">.close =</span> <span class="st">&quot;:&quot;</span>, <span class="at">.envir =</span> .envir, <span class="at">.transformer =</span> emoji_transformer)</span>
<span id="cb4-12"><a href="#cb4-12" tabindex="-1"></a>}</span>
<span id="cb4-13"><a href="#cb4-13" tabindex="-1"></a><span class="fu">glue_ji</span>(<span class="st">&quot;one :heart:&quot;</span>)</span>
<span id="cb4-14"><a href="#cb4-14" tabindex="-1"></a><span class="fu">glue_ji</span>(<span class="st">&quot;many :heart*:&quot;</span>)</span></code></pre></div>
</div>
<div id="sprintf-transformer" class="section level3">
<h3>sprintf transformer</h3>
<p>A transformer which allows succinct <code>sprintf</code> format
strings.</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode r"><code class="sourceCode r"><span id="cb5-1"><a href="#cb5-1" tabindex="-1"></a>sprintf_transformer <span class="ot">&lt;-</span> <span class="cf">function</span>(text, envir) {</span>
<span id="cb5-2"><a href="#cb5-2" tabindex="-1"></a> m <span class="ot">&lt;-</span> <span class="fu">regexpr</span>(<span class="st">&quot;:.+$&quot;</span>, text)</span>
<span id="cb5-3"><a href="#cb5-3" tabindex="-1"></a> <span class="cf">if</span> (m <span class="sc">!=</span> <span class="sc">-</span><span class="dv">1</span>) {</span>
<span id="cb5-4"><a href="#cb5-4" tabindex="-1"></a> format <span class="ot">&lt;-</span> <span class="fu">substring</span>(<span class="fu">regmatches</span>(text, m), <span class="dv">2</span>)</span>
<span id="cb5-5"><a href="#cb5-5" tabindex="-1"></a> <span class="fu">regmatches</span>(text, m) <span class="ot">&lt;-</span> <span class="st">&quot;&quot;</span></span>
<span id="cb5-6"><a href="#cb5-6" tabindex="-1"></a> res <span class="ot">&lt;-</span> <span class="fu">identity_transformer</span>(text, envir)</span>
<span id="cb5-7"><a href="#cb5-7" tabindex="-1"></a> <span class="fu">do.call</span>(sprintf, <span class="fu">list</span>(<span class="fu">glue</span>(<span class="st">&quot;%{format}&quot;</span>), res))</span>
<span id="cb5-8"><a href="#cb5-8" tabindex="-1"></a> } <span class="cf">else</span> {</span>
<span id="cb5-9"><a href="#cb5-9" tabindex="-1"></a> <span class="fu">identity_transformer</span>(text, envir)</span>
<span id="cb5-10"><a href="#cb5-10" tabindex="-1"></a> }</span>
<span id="cb5-11"><a href="#cb5-11" tabindex="-1"></a>}</span>
<span id="cb5-12"><a href="#cb5-12" tabindex="-1"></a></span>
<span id="cb5-13"><a href="#cb5-13" tabindex="-1"></a>glue_fmt <span class="ot">&lt;-</span> <span class="cf">function</span>(..., <span class="at">.envir =</span> <span class="fu">parent.frame</span>()) {</span>
<span id="cb5-14"><a href="#cb5-14" tabindex="-1"></a> <span class="fu">glue</span>(..., <span class="at">.transformer =</span> sprintf_transformer, <span class="at">.envir =</span> .envir)</span>
<span id="cb5-15"><a href="#cb5-15" tabindex="-1"></a>}</span>
<span id="cb5-16"><a href="#cb5-16" tabindex="-1"></a><span class="fu">glue_fmt</span>(<span class="st">&quot;π = {pi:.3f}&quot;</span>)</span>
<span id="cb5-17"><a href="#cb5-17" tabindex="-1"></a><span class="co">#&gt; π = 3.142</span></span></code></pre></div>
</div>
<div id="signif-transformer" class="section level3">
<h3>signif transformer</h3>
<p>A transformer generator that represents numbers with a given number
of significant digits. This is useful if we want to represent all
numbers using the same significant digits</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode r"><code class="sourceCode r"><span id="cb6-1"><a href="#cb6-1" tabindex="-1"></a>signif_transformer <span class="ot">&lt;-</span> <span class="cf">function</span>(<span class="at">digits =</span> <span class="dv">3</span>) {</span>
<span id="cb6-2"><a href="#cb6-2" tabindex="-1"></a> <span class="fu">force</span>(digits)</span>
<span id="cb6-3"><a href="#cb6-3" tabindex="-1"></a> <span class="cf">function</span>(text, envir) {</span>
<span id="cb6-4"><a href="#cb6-4" tabindex="-1"></a> x <span class="ot">&lt;-</span> <span class="fu">identity_transformer</span>(text, envir)</span>
<span id="cb6-5"><a href="#cb6-5" tabindex="-1"></a> <span class="cf">if</span> (<span class="fu">is.numeric</span>(x)) {</span>
<span id="cb6-6"><a href="#cb6-6" tabindex="-1"></a> <span class="fu">signif</span>(x, <span class="at">digits =</span> digits)</span>
<span id="cb6-7"><a href="#cb6-7" tabindex="-1"></a> } <span class="cf">else</span> {</span>
<span id="cb6-8"><a href="#cb6-8" tabindex="-1"></a> x</span>
<span id="cb6-9"><a href="#cb6-9" tabindex="-1"></a> }</span>
<span id="cb6-10"><a href="#cb6-10" tabindex="-1"></a> }</span>
<span id="cb6-11"><a href="#cb6-11" tabindex="-1"></a>}</span>
<span id="cb6-12"><a href="#cb6-12" tabindex="-1"></a>glue_signif <span class="ot">&lt;-</span> <span class="cf">function</span>(..., <span class="at">.envir =</span> <span class="fu">parent.frame</span>()) {</span>
<span id="cb6-13"><a href="#cb6-13" tabindex="-1"></a> <span class="fu">glue</span>(..., <span class="at">.transformer =</span> <span class="fu">signif_transformer</span>(<span class="dv">3</span>), <span class="at">.envir =</span> .envir)</span>
<span id="cb6-14"><a href="#cb6-14" tabindex="-1"></a>}</span>
<span id="cb6-15"><a href="#cb6-15" tabindex="-1"></a></span>
<span id="cb6-16"><a href="#cb6-16" tabindex="-1"></a><span class="fu">glue_signif</span>(<span class="st">&quot;π = {pi}; 10π = {10*pi}; 100π = {100*pi}&quot;</span>)</span>
<span id="cb6-17"><a href="#cb6-17" tabindex="-1"></a><span class="co">#&gt; π = 3.14; 10π = 31.4; 100π = 314</span></span></code></pre></div>
</div>
<div id="safely-transformer" class="section level3">
<h3>safely transformer</h3>
<p>A transformer that acts like <code>purrr::safely()</code>, which
returns a value instead of an error.</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode r"><code class="sourceCode r"><span id="cb7-1"><a href="#cb7-1" tabindex="-1"></a>safely_transformer <span class="ot">&lt;-</span> <span class="cf">function</span>(<span class="at">otherwise =</span> <span class="cn">NA</span>) {</span>
<span id="cb7-2"><a href="#cb7-2" tabindex="-1"></a> <span class="cf">function</span>(text, envir) {</span>
<span id="cb7-3"><a href="#cb7-3" tabindex="-1"></a> <span class="fu">tryCatch</span>(</span>
<span id="cb7-4"><a href="#cb7-4" tabindex="-1"></a> <span class="fu">identity_transformer</span>(text, envir),</span>
<span id="cb7-5"><a href="#cb7-5" tabindex="-1"></a> <span class="at">error =</span> <span class="cf">function</span>(e) <span class="cf">if</span> (<span class="fu">is.language</span>(otherwise)) <span class="fu">eval</span>(otherwise) <span class="cf">else</span> otherwise)</span>
<span id="cb7-6"><a href="#cb7-6" tabindex="-1"></a> }</span>
<span id="cb7-7"><a href="#cb7-7" tabindex="-1"></a>}</span>
<span id="cb7-8"><a href="#cb7-8" tabindex="-1"></a></span>
<span id="cb7-9"><a href="#cb7-9" tabindex="-1"></a>glue_safely <span class="ot">&lt;-</span> <span class="cf">function</span>(..., <span class="at">.otherwise =</span> <span class="cn">NA</span>, <span class="at">.envir =</span> <span class="fu">parent.frame</span>()) {</span>
<span id="cb7-10"><a href="#cb7-10" tabindex="-1"></a> <span class="fu">glue</span>(..., <span class="at">.transformer =</span> <span class="fu">safely_transformer</span>(.otherwise), <span class="at">.envir =</span> .envir)</span>
<span id="cb7-11"><a href="#cb7-11" tabindex="-1"></a>}</span>
<span id="cb7-12"><a href="#cb7-12" tabindex="-1"></a></span>
<span id="cb7-13"><a href="#cb7-13" tabindex="-1"></a><span class="co"># Default returns missing if there is an error</span></span>
<span id="cb7-14"><a href="#cb7-14" tabindex="-1"></a><span class="fu">glue_safely</span>(<span class="st">&quot;foo: {xyz}&quot;</span>)</span>
<span id="cb7-15"><a href="#cb7-15" tabindex="-1"></a><span class="co">#&gt; foo: NA</span></span>
<span id="cb7-16"><a href="#cb7-16" tabindex="-1"></a></span>
<span id="cb7-17"><a href="#cb7-17" tabindex="-1"></a><span class="co"># Or an empty string</span></span>
<span id="cb7-18"><a href="#cb7-18" tabindex="-1"></a><span class="fu">glue_safely</span>(<span class="st">&quot;foo: {xyz}&quot;</span>, <span class="at">.otherwise =</span> <span class="st">&quot;Error&quot;</span>)</span>
<span id="cb7-19"><a href="#cb7-19" tabindex="-1"></a><span class="co">#&gt; foo: Error</span></span>
<span id="cb7-20"><a href="#cb7-20" tabindex="-1"></a></span>
<span id="cb7-21"><a href="#cb7-21" tabindex="-1"></a><span class="co"># Or output the error message in red</span></span>
<span id="cb7-22"><a href="#cb7-22" tabindex="-1"></a><span class="fu">library</span>(crayon)</span>
<span id="cb7-23"><a href="#cb7-23" tabindex="-1"></a><span class="fu">glue_safely</span>(<span class="st">&quot;foo: {xyz}&quot;</span>, <span class="at">.otherwise =</span> <span class="fu">quote</span>(<span class="fu">glue</span>(<span class="st">&quot;{red}Error: {conditionMessage(e)}{reset}&quot;</span>)))</span>
<span id="cb7-24"><a href="#cb7-24" tabindex="-1"></a><span class="co">#&gt; foo: Error: Failed to evaluate glue component {xyz}</span></span>
<span id="cb7-25"><a href="#cb7-25" tabindex="-1"></a><span class="co">#&gt; Caused by error:</span></span>
<span id="cb7-26"><a href="#cb7-26" tabindex="-1"></a><span class="co">#&gt; ! object &#39;xyz&#39; not found</span></span></code></pre></div>
</div>
<div id="variables-and-values-transformer" class="section level3">
<h3>“Variables and Values” transformer</h3>
<p>A transformer that expands input of the form <code>{var_name=}</code>
into <code>var_name = var_value</code>, i.e. a shorthand for exposing
variable names with their values. This is inspired by an <a href="https://docs.python.org/3.8/whatsnew/3.8.html#f-strings-now-support-for-quick-and-easy-debugging">f-strings
feature coming in Python 3.8</a>. Its actually more general: you can
use it with an expression input such as <code>{expr=}</code>.</p>
<div class="sourceCode" id="cb8"><pre class="sourceCode r"><code class="sourceCode r"><span id="cb8-1"><a href="#cb8-1" tabindex="-1"></a>vv_transformer <span class="ot">&lt;-</span> <span class="cf">function</span>(text, envir) {</span>
<span id="cb8-2"><a href="#cb8-2" tabindex="-1"></a> regex <span class="ot">&lt;-</span> <span class="st">&quot;=$&quot;</span></span>
<span id="cb8-3"><a href="#cb8-3" tabindex="-1"></a> <span class="cf">if</span> (<span class="sc">!</span><span class="fu">grepl</span>(regex, text)) {</span>
<span id="cb8-4"><a href="#cb8-4" tabindex="-1"></a> <span class="fu">return</span>(<span class="fu">identity_transformer</span>(text, envir))</span>
<span id="cb8-5"><a href="#cb8-5" tabindex="-1"></a> }</span>
<span id="cb8-6"><a href="#cb8-6" tabindex="-1"></a></span>
<span id="cb8-7"><a href="#cb8-7" tabindex="-1"></a> text <span class="ot">&lt;-</span> <span class="fu">sub</span>(regex, <span class="st">&quot;&quot;</span>, text)</span>
<span id="cb8-8"><a href="#cb8-8" tabindex="-1"></a> res <span class="ot">&lt;-</span> <span class="fu">identity_transformer</span>(text, envir)</span>
<span id="cb8-9"><a href="#cb8-9" tabindex="-1"></a> n <span class="ot">&lt;-</span> <span class="fu">length</span>(res)</span>
<span id="cb8-10"><a href="#cb8-10" tabindex="-1"></a> res <span class="ot">&lt;-</span> <span class="fu">glue_collapse</span>(res, <span class="at">sep =</span> <span class="st">&quot;, &quot;</span>)</span>
<span id="cb8-11"><a href="#cb8-11" tabindex="-1"></a> <span class="cf">if</span> (n <span class="sc">&gt;</span> <span class="dv">1</span>) {</span>
<span id="cb8-12"><a href="#cb8-12" tabindex="-1"></a> res <span class="ot">&lt;-</span> <span class="fu">c</span>(<span class="st">&quot;[&quot;</span>, res, <span class="st">&quot;]&quot;</span>)</span>
<span id="cb8-13"><a href="#cb8-13" tabindex="-1"></a> }</span>
<span id="cb8-14"><a href="#cb8-14" tabindex="-1"></a> <span class="fu">glue_collapse</span>(<span class="fu">c</span>(text, <span class="st">&quot; = &quot;</span>, res))</span>
<span id="cb8-15"><a href="#cb8-15" tabindex="-1"></a>}</span></code></pre></div>
<div class="sourceCode" id="cb9"><pre class="sourceCode r"><code class="sourceCode r"><span id="cb9-1"><a href="#cb9-1" tabindex="-1"></a><span class="fu">set.seed</span>(<span class="dv">1234</span>)</span>
<span id="cb9-2"><a href="#cb9-2" tabindex="-1"></a>description <span class="ot">&lt;-</span> <span class="st">&quot;some random&quot;</span></span>
<span id="cb9-3"><a href="#cb9-3" tabindex="-1"></a>numbers <span class="ot">&lt;-</span> <span class="fu">sample</span>(<span class="dv">100</span>, <span class="dv">4</span>)</span>
<span id="cb9-4"><a href="#cb9-4" tabindex="-1"></a>average <span class="ot">&lt;-</span> <span class="fu">mean</span>(numbers)</span>
<span id="cb9-5"><a href="#cb9-5" tabindex="-1"></a>sum <span class="ot">&lt;-</span> <span class="fu">sum</span>(numbers)</span>
<span id="cb9-6"><a href="#cb9-6" tabindex="-1"></a></span>
<span id="cb9-7"><a href="#cb9-7" tabindex="-1"></a><span class="fu">glue</span>(<span class="st">&quot;For {description} {numbers=}, {average=}, {sum=}.&quot;</span>, <span class="at">.transformer =</span> vv_transformer)</span>
<span id="cb9-8"><a href="#cb9-8" tabindex="-1"></a><span class="co">#&gt; For some random numbers = [28, 80, 22, 9], average = 34.75, sum = 139.</span></span>
<span id="cb9-9"><a href="#cb9-9" tabindex="-1"></a></span>
<span id="cb9-10"><a href="#cb9-10" tabindex="-1"></a>a <span class="ot">&lt;-</span> <span class="dv">3</span></span>
<span id="cb9-11"><a href="#cb9-11" tabindex="-1"></a>b <span class="ot">&lt;-</span> <span class="fl">5.6</span></span>
<span id="cb9-12"><a href="#cb9-12" tabindex="-1"></a><span class="fu">glue</span>(<span class="st">&quot;{a=}</span><span class="sc">\n</span><span class="st">{b=}</span><span class="sc">\n</span><span class="st">{a * 9 + b * 2=}&quot;</span>, <span class="at">.transformer =</span> vv_transformer)</span>
<span id="cb9-13"><a href="#cb9-13" tabindex="-1"></a><span class="co">#&gt; a = 3</span></span>
<span id="cb9-14"><a href="#cb9-14" tabindex="-1"></a><span class="co">#&gt; b = 5.6</span></span>
<span id="cb9-15"><a href="#cb9-15" tabindex="-1"></a><span class="co">#&gt; a * 9 + b * 2 = 38.2</span></span></code></pre></div>
</div>
<!-- code folding -->
<!-- dynamically load mathjax for compatibility with self-contained -->
<script>
(function () {
var script = document.createElement("script");
script.type = "text/javascript";
script.src = "https://mathjax.rstudio.com/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML";
document.getElementsByTagName("head")[0].appendChild(script);
})();
</script>
</body>
</html>