Giter Club home page Giter Club logo

epoxy's Introduction

epoxy logo
{epoxy}

extra-strength glue for scripts, reports, and apps.

CRAN status epoxy r-universe badge R-CMD-check Codecov test coverage

epoxy is super glue

Use epoxy chunks for extra-strength inline syntax. Just library(epoxy) in your R Markdown or Quarto document to get started. All epoxy chunks make it easy to transform values in place with a {cli}-inspired inline syntax described in ?epoxy_transform_inline.

The same functions that power epoxy chunks are availble in three flavors:

  • epoxy() for markdown and general purpose outputs

  • epoxy_html() for HTML outputs, with added support for HTML templating (see ?epoxy_transform_html)

  • epoxy_latex() for LaTeX reports

These functions are accompanied by a robust system for chained glue-transformers powered by epoxy_transform().

ui_epoxy_html() makes it easy to update text or HTML dynamically, anywhere in your Shiny app’s UI. For more complicated situations, ui_epoxy_mustache() lets you turn any Shiny UI into a template that leverages the Mustache templating language.

epoxy in R Markdown and Quarto documents

In R Markdown and Quarto documents, epoxy gives you an epoxy chunk where you can write in markdown, blending prose and data using glue’s template syntax.

Here’s an example using a small list containing data about a movie (expand the section below to see the full code for movie). We can use the inline transformer to format the replacement text as we build up a description from this data.

Movie data
movie <- list(
  year = 1989,
  title = "Back to the Future Part II",
  budget = 4e+07,
  domgross = 118450002,
  imdb_rating = 7.8,
  actors = c(
    "Michael J. Fox",
    "Christopher Lloyd",
    "Lea Thompson",
    "Thomas F. Wilson"
  ),
  runtime = 108L
)
```{epoxy}
The movie {.emph {.titlecase movie$title}}
was released in {.strong movie$year}.
It earned {.dollar movie$domgross}
with a budget of {.dollar movie$budget},
and it features movie stars
{.and movie$actors}.
```
The movie *Back to the Future Part II* was released in **1989**. It earned \$118,450,002 with a budget of \$40,000,000, and it features movie stars Michael J. Fox, Christopher Lloyd, Lea Thompson, and Thomas F. Wilson.

Learn more about epoxy chunks – and its siblings epoxy_html and epoxy_latex – in Getting Started. Or read more about epoxy’s inline formatting in ?epoxy_transform_inline.

Installation

You can install epoxy from CRAN:

install.packages("epoxy")

You can install the latest development version of epoxy with remotes

# install.packages("remotes")
remotes::install_github("gadenbuie/epoxy")

or from gadenbuie.r-universe.dev.

options(repos = c(
  gadenbuie = "https://gadenbuie.r-universe.dev/",
  getOption("repos")
))

install.packages("epoxy")

Setup

library(epoxy)

Loading epoxy adds four new knitr engines, or chunk types. Each type lets you intermix text with R code or data (expr in the table below), and each is geared toward a different output context.

Engine Output Context Delimiter
epoxy all-purpose markdown {expr}
epoxy_html HTML {{expr}}
epoxy_latex LaTeX <<expr>>
whisker all-purpose mustache template language

⚠️ Caution: Previously, epoxy provided a glue engine, but this conflicts with a similar chunk engine by the glue package. You can update existing documents to use the epoxy engine, or you can explicitly use epoxy’s glue chunk by including the following in your setup chunk.

use_epoxy_glue_engine()

Use epoxy

To use epoxy in your R Markdown document, create a new chunk using the engine of your choice. In that chunk, write in markdown, HTML, or LaTeX as needed, wrapping R expressions inside the delimiters for the epoxy chunk.

```{epoxy}
The average speed of the cars was **{mean(cars$speed)} mph.**
But on average the distance traveled was only _{mean(cars$dist)}_.
```

The average speed of the cars was 15.4 mph. But on average the distance traveled was only 42.98 ft.

epoxy is built around glue::glue(), which evaluates the R expressions in the { } and inserts the results into the string. The chunk above is equivalent to this call to glue::glue():

glue::glue("The average speed of the cars was **{mean(cars$speed)} mph**.
But on average the distance traveled was only _{mean(cars$dist)} ft_.")
#> The average speed of the cars was **15.4 mph**.
#> But on average the distance traveled was only _42.98 ft_.

One immediate advantage of using epoxy instead of glue::glue() is that RStudio’s autocompletion feature works inside epoxy chunks! Typing cars$ in the chunk will suggest the columns of cars.

Learn more

There’s a whole lot more that epoxy can do! Learn more:

Code of Conduct

Please note that the epoxy project is released with a Contributor Code of Conduct. By contributing to this project, you agree to abide by its terms.

epoxy's People

Contributors

gadenbuie avatar github-actions[bot] avatar jdlom avatar rossellhayes avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

epoxy's Issues

Align epoxy with {cli}

epoxy_style_format() should work more like cli's inline formatting. Instead of

{fmt(airbnb$hosts, "number")} hosts

the syntax would be

{number {airbnb$hosts}}

# or maybe with leading dot?
{.number {airbnb$hosts}}

# or using a shortcut
{# {airbnb$hosts}}

Format values in renderEpoxyHTML()

to allow htmltools::tags without having to wrap in format().

library(shiny)
library(epoxy)

ui <- fluidPage(
  epoxyHTML("test", "<p>{{image}}</p>")
)

server <- function(input, output, session) {
  output$test <- renderEpoxyHTML(
    image = format(tags$img(src = "http://placekitten.com/200/200"))
  )
}

shinyApp(ui, server)

epoxy_style_collapse in a dataframe

I am trying to use glue chunk to write the results of a model which I put inside a tibble. I want to use epoxy_style collapse() along with this and the results are weird. Also, the superscript doesn't seem to work inside the glue chunk.

```{r models}
m1<-lm(mpg~1,data = mtcars)
m2<-lm(mpg~factor(cyl),data = mtcars)
mods<-list(m1=m1,m2=m2)
results<-tibble(modnum=c("mod1","mod2"),models=mods)
results <-results %>% mutate(
        diag=map(models,glance)
) %>% unnest(diag) %>% slice(1:2)
```
```{glue modelres, eval=FALSE,.transformer=epoxy_style_collapse()}
{modnum} has an R^2 of {r.squared&}
```
```{glue ref.label="modelres",data=results}
```

I want results like this
mod1 has an R^2 of 0 and mod2 has an R^2 of 0.7333.

A version of `whisker::whisker.render()` that more closely aligns with `epoxy()`?

epoxy_mustache() that corresponds to ui_epoxy_mustache()? It would have slightly better semantics than whisker.render():

  • Takes ... and does the same thing as epoxy() re named/unnamed arguments.
  • Better aligns with Shiny's idea of truthiness, e.g. "" and NA are missing rather than counting as being included.
  • Might have to apply the same truthiness filter to render_epoxy()? Or opt-in and enabled for ui_epoxy_mustache() by default.

Epoxy transformer error after updating R

epoxy seems to run into an error after updating R. It was working fine previously. I have tried after knitting too..

Here is the session info

R version 4.1.0 (2021-05-18)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows 10 x64 (build 19042)

Matrix products: default

locale:
[1] LC_COLLATE=English_India.1252 LC_CTYPE=English_India.1252
[3] LC_MONETARY=English_India.1252 LC_NUMERIC=C
[5] LC_TIME=English_India.1252

attached base packages:
character(0)

other attached packages:
[1] epoxy_0.0.2.9000

loaded via a namespace (and not attached):
[1] Rcpp_1.0.6 lubridate_1.7.10 tidyr_1.1.3 prettyunits_1.1.1
[5] ps_1.6.0 assertthat_0.2.1 rprojroot_2.0.2 digest_0.6.27
[9] utf8_1.2.1 R6_2.5.0 cellranger_1.1.0 backports_1.2.1
[13] reprex_2.0.0 evaluate_0.14 httr_1.4.2 ggplot2_3.3.5
[17] pillar_1.6.1 utils_4.1.0 rlang_0.4.11 curl_4.3.2
[21] readxl_1.3.1 rstudioapi_0.13 callr_3.7.0 rmarkdown_2.9
[25] readr_1.4.0 stringr_1.4.0 munsell_0.5.0 broom_0.7.8
[29] compiler_4.1.0 modelr_0.1.8 xfun_0.24 pkgconfig_2.0.3
[33] stats_4.1.0 pkgbuild_1.2.0 htmltools_0.5.1.1 tidyselect_1.1.1
[37] tibble_3.1.2 bookdown_0.22 grDevices_4.1.0 fansi_0.5.0
[41] crayon_1.4.1 dplyr_1.0.7 dbplyr_2.1.1 withr_2.4.2
[45] grid_4.1.0 jsonlite_1.7.2 gtable_0.3.0 lifecycle_1.0.0
[49] DBI_1.1.1 magrittr_2.0.1 datasets_4.1.0 scales_1.1.1
[53] zip_2.2.0 cli_2.5.0 stringi_1.6.2 fs_1.5.0
[57] remotes_2.4.0 tidyverse_1.3.1 xml2_1.3.2 ellipsis_0.3.2
[61] graphics_4.1.0 generics_0.1.0 vctrs_0.3.8 openxlsx_4.2.4
[65] base_4.1.0 tools_4.1.0 forcats_0.5.1 glue_1.4.2
[69] purrr_0.3.4 hms_1.1.0 processx_3.5.2 yaml_2.2.1
[73] colorspace_2.0-2 rvest_1.0.0 knitr_1.33 haven_2.4.1
[77] methods_4.1.0
epoxy

Make it easier to add a new inline transformer

Currently you'd have to do something like this

epoxy_transform_set(
  epoxy_transform_inline(
    my_new_def = function(x) { ... }
  )
)

This would also unset previously established defaults, etc.

It'd be helpful to be able to directly add or update an inline transformer with a direct setter. Maybe:

  1. epoxy_transform_inline_set() (too long)
  2. epoxy_inline_set() (breaks pattern)
  3. epoy_transform_set(.my_new_def = ) could special case arguments that start with .

Templates do not use Parameters of the Template Chunk

Given the template ci:

    ```{glue ci, .open="(|", .close="|)", eval=FALSE}
    (|1+1|)
    ```

Having the following chunk pointing to the template is not enough:

    ```{glue n, ref.label="ci", data=dat}
    ```

It requires more parameters to work:

    ```{glue n, ref.label="ci", .open="(|", .close="|)", data=dat}
    ```

Might want to mention that or fix that. It appears that this will apply to all other parameters used in the template.

Rename `renderEpoxyHTML()`

After #51 it's not just for epoxyHTML(), so epoxy_render() might be a better name, also following epoxy_{output,render} naming for Shiny functions.

Give docs a full review

Make sure they better sell inline formatters and the core usage of epoxy, since that has changed epoxy considerably.

Include R chunks in Glue chunks?

Is there a way to include an R (or any other) chunk in the Glue chunk? I have a class assignment that wants us to answer questions with different values. In that, I need to include R code like this:

  ```{glue, .open="{{", .close="}}"}
  $$\alpha={{alpha}}$$
  $$\frac\alpha2={{alpha/2}}$$
  \```{r}
  z=qnorm(alpha/2, lower.tail = FALSE)
  z
  \```
  $$z_{\frac\alpha2}\approx {{z}}$$
  #Unable to include ending of block

Now I could just split the block up, but then it won't work as a template. Is the only way around it to format it by hand as a block? I would love this feature!

LaTeX Preview

With RStudio 1.4 they introduced Visual Editor that allows LaTeX equations to be previewed, even if Visual Editor is off. However, it breaks when the equation is written in code blocks, is there a way to fix this? I don't know if this is even possible without modifying RStudio's code, so it might be a deep issue.

From this:
image

To something like this?
image

If you add back the ticks, the equation box stays there, but it will not update. It would be great if this was fixed, even without replacement of the variables is fine by me as it is like code. ({and } may mess up the LaTeX, so I used (| and |) so it would not mess it up.

Add `epoxy_style_scale()`

A transformer wrapping scales functions.

I think the syntax might be something like

glue(
  "{s(sales_pct, '%')} of sales generated {s(revenue, '$')} in revenue.",
  sales_pct = 0.8,
  revenue = 125000,
  .transformer = epoxy_style_scales()
)

#> 80% of sales generated $125,000 in revenue

The central idea is that epoxy_style_scales() would make available a function s() with two arguments that is basically a switch around the scales::label_*() functions:

  • % for label_percent()
  • $ for label_dollar()
  • si for label_scientific()
  • p for label_pvalue()
  • o for label_ordinal()
  • b for label_bytes()
  • d, ds, dt for _date, _date_short, _time
  • etc...

maybe using partial matching so p --> pvalue.

Since the label function, e.g. label_percent(), take arguments and return a function that applies the formatting, epoxy_style_scales() would have an argument for each of the labellers and would accept a list of argument values for each.

Comments in Blocks

Is there a way to add comments to glue chunks as we do in R?

# This is a comment in R
    ```{glue}
    # Comment in glue?
    ```

Should `epoxy_transform_html()` collapse to single string?

I remember having reasons why I switched away from this – likely due to an interaction with the inline transformer – but this doesn't feel right:

library(epoxy)
epoxy_html("<ul>{{li letters[1:3]}}<ul>")
<ul><li>a</li><ul>
<ul><li>b</li><ul>
<ul><li>c</li><ul>

Remove `epoxy_style_format()`

The epoxy_style_format() inline formatter was an interesting idea, but ultimately I don't think it's as ergonomic as the inline foramtters. I'd rather remove it than publish epoxy on CRAN and have to support it or remove it soon thereafter.

Rename `epoxyHTML()`

Follow up from #51, I'd like to use epoxy_output as a prefix for epoxy-driven Shiny outputs.

Options:

  • epoxy_output_html()
  • epoxy_output()
  • other (suggestions?)

Emphasis tags not rendering in RStudio R chunk

Simple example using apreshill's bakeoff set:

```{r setup, include= FALSE}
library(bakeoff)
library(epoxy)
```
```{glue}
There are {nrow(bakeoff::series)} series of *The Great British Bake-Off* (or, **GBBO**).
```

The nrow correctly calculates, but the asterisks do not render italics or bold but just remain text, both inline in the code editor and in the Preview screen. I'm using the latest RStudio 4.1.0, glue 1.4.2, and epoxy 0.0.2.9000 on Mac OS.
Screen Shot 2021-05-23 at 19 23 37

Add example showing custom `.trunc` inline styler

This might be a useful example to include somewhere in the docs.

my_num <- 1234567890

epoxy(
  "* orig:  {my_num} or {my_num}\n",
  "* trunc: {.trunc_6 my_num}     or {.trunc_8 my_num}\n",
  "* head:  {.head_6 my_num}     or {.head_8 my_num}",
  .style = epoxy_style_inline(
    trunc_6 = \(x) glue::glue_collapse(x, width = 6),
    trunc_8 = \(x) glue::glue_collapse(x, width = 8),
    head_6 = \(x) substring(x, 1, min(nchar(x), 6)),
    head_8 = \(x) substring(x, 1, min(nchar(x), 8))
  )
)
#> * orig:  1234567890 or 1234567890
#> * trunc: 123...     or 12345...
#> * head:  123456     or 12345678

Release epoxy 0.1.1

Prepare for release:

  • git pull
  • Check current CRAN check results
  • Polish NEWS
  • urlchecker::url_check()
  • devtools::build_readme()
  • devtools::check(remote = TRUE, manual = TRUE)
  • devtools::check_win_devel()
  • revdepcheck::revdep_check(num_workers = 4)
  • Update cran-comments.md
  • git push

Submit to CRAN:

  • usethis::use_version('patch')
  • devtools::submit_cran()
  • Approve email

Wait for CRAN...

  • Accepted 🎉
  • usethis::use_github_release()
  • usethis::use_dev_version(push = TRUE)

Error when trying to use: In get_engine(options$engine) : Unknown language engine 'glue' (must be registered via knit_engines$set())

Great package, just scratched my exact itch. I like the usage style (as a Rmd dialect), very clean.

When trying to use epoxy, if knitr and/or rmarkdown libraries are not pre-loaded, you get the following error:

In get_engine(options$engine) :   
Unknown language engine 'glue' (must be registered via knit_engines$set())

Simple enough fix, but posting here for google-able posterity

Create whisker alias for `ui_epoxy_mustache()`

Since we have a whisker engine, it might make sense to provide a ui_epoxy_whisker() alias for ui_epoxy_mustache().

They have different names at the moment because one uses the whisker package (which provides an R-based implementation of the mustache syntax) and the other uses mustache.js.

Add an alias for mustache engine?

I called it the whisker engine because that's the R package name. And then I made ui_epoxy_mustache() because that's the javascript library name. But I gave an alias ui_epoxy_whisker() on the shiny side but not the knitr side. idk...

"whisker" = knitr_engine_whisker

Pairs with #91

epoxyHTML probably shouldn't inherit from globalenv

The app below will fail unless a non-function text exists in the calling environment or if text = "something" is provided in epoxyHTML().

library(shiny)

# text <- "placeholder"

ui <- fluidPage(
  textInput("text", "Text"),
  epoxy::epoxyHTML("test", "{{text}}")
)

server <- function(input, output, session) {
  output$test <- epoxy::renderEpoxyHTML(text = input$text)
}

shinyApp(ui, server)

This is because graphics::text() is a function and found in the global environment, and glue::glue_data() later tries to call as.character() on the function, which fails.

I think the following should be the only way to set individual placeholder values.

ui <- fluidPage(
  textInput("text", "Text"),
  epoxy::epoxyHTML("test", "{{text}}", text = "placeholder")
)

Should it really be called `epoxy_style()`?

I used .style and epoxy_style() because it felt a little more user friendly than transformer. But it has always felt a little awkward when writing the documentation: which thing am I talking about exactly? In which case transformer is the precise term. Also style gets confused with CSS styles or is otherwise a little too ambiguous.

I don't really want to change everything and my feeling is most people will use the currently named epoxy_style_inline() just by default. But I also don't want to be stuck with a naming convention that I'm not happy with.

I'm considering replacing style with transform or transformer everywhere:

  • epoxy_transform()
  • epoxy_transform_inline()
  • epoxy_transform("bold", "collapse")

Add `.squote` and `.dquote` to `epoxy_style_inline()`

library(epoxy)
abc <- c("a", "b", "c")

epoxy(
  "{.squote abc} or {.dquote abc}",
  .style = epoxy_style_inline(
    squote = \(x) sQuote(x, q = getOption("useFancyQuotes", 0)),
    dquote = \(x) dQuote(x, q = getOption("useFancyQuotes", 0))
  )
)
#> 'a' or "a"
#> 'b' or "b"
#> 'c' or "c"

Mark `epoxy_style_collapse()` as deprecated

These have been around for a little while and I have a small amount of evidence that they've been used. I think the inline formatting is much cleaner and easier to understand.

`epoxy_style_html()`: Support attribute syntax

Currently, epoxy_style_html() supports id and class attributes, but we could support additional attributes with something like this:

{{ a(href="https://example.com") link_text }}

In the long run, it'd be nice to be able to nest replacements, e.g.

{{ a(href="{{ link_url }}") link_text }}

or

{{ a href=link_url link_text }}

or maybe

{{ a c(href = link_url, link_text) }}

Release epoxy 0.1.0

TODO:

Prepare for release:

  • git pull
  • Check current CRAN check results
  • Check if any deprecation processes should be advanced, as described in Gradual deprecation
  • Polish NEWS
  • devtools::build_readme()
  • urlchecker::url_check()
  • devtools::check(remote = TRUE, manual = TRUE)
  • devtools::check_win_devel()
  • rhub::check_for_cran()
  • revdepcheck::revdep_check(num_workers = 4)
  • Update cran-comments.md
  • git push
  • Draft blog post

Submit to CRAN:

  • usethis::use_version('minor')
  • devtools::submit_cran()
  • Approve email

Wait for CRAN...

  • Accepted 🎉
  • git push
  • usethis::use_github_release()
  • usethis::use_dev_version()
  • git push
  • Finish blog post
  • Tweet
  • Add link to blog post in pkgdown news menu

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.