Git Product home page Git Product logo

whisker's Introduction

version downloads R build status Build status status

Whisker

Whisker is a {{Mustache}} implementation in R confirming to the Mustache specification. Mustache is a logicless templating language, meaning that no programming source code can be used in your templates. This may seem very limited, but Mustache is nonetheless powerful and has the advantage of being able to be used unaltered in many programming languages. It makes it very easy to write a web application in R using Mustache templates which could also be re-used for client-side rendering with "Mustache.js".

Mustache (and therefore whisker) takes a simple, but different, approach to templating compared to most templating engines. Most templating libraries, such as Sweave, knitr and brew, allow the user to mix programming code and text throughout the template. This is powerful, but ties your template directly to a programming language and makes it difficult to seperate programming code from templating code.

Whisker, on the other hand, takes a Mustache template and uses the variables of the current environment (or the supplied list) to fill in the variables.

Mustache syntax

The syntax of Mustache templates is described in https://mustache.github.io/mustache.5.html How the mustache template are used with whisker can be found in the whisker documentation, and below.

Mustache specification

Whisker conforms to the Mustache 1.1 specificaton except for delimiter switching and lambdas. We expect that these will be implented shortly.

Installation

To install whisker use the following statement in your R console

install.packages("whisker")

The latest whisker version is not yet available on CRAN, but can be installed from github:

library(devtools)

# dev_mode()
install_github("whisker", "edwindj")

Usage

whisker.render accepts a character template and a list or environment containing data to render:

library(whisker)
template <- 
'Hello {{name}}
You have just won ${{value}}!
{{#in_ca}}
Well, ${{taxed_value}}, after taxes.
{{/in_ca}}
'

data <- list( name = "Chris"
            , value = 10000
            , taxed_value = 10000 - (10000 * 0.4)
            , in_ca = TRUE
            )

text <- whisker.render(template, data)
cat(text)
## Hello Chris
## You have just won $10000!
## Well, $6000, after taxes.

Or using a text file

library(whisker)

template <- readLines("./template.html")
data <- list( name = "Chris"
            , value = 10000
            , taxed_value = 10000 - (10000 * 0.4)
            , in_ca = TRUE
            )

writeLines(whisker.render(template, data), "./output.html")

Note

By default whisker applies html escaping on the generated text. To prevent this use {{{variable}}} (triple) in stead of {{variable}}.

template <- 
"I'm escaped: {{name}}
And I'm not: {{{name}}}"

data <- list( name = '<My Name="Nescio">')
whisker.render(template, data)

Generates:

I'm escaped: &lt;My Name=&quot;Nescio&quot;&gt;
And I'm not: <My Name="Nescio">

whisker's People

Contributors

edwindj avatar gokceneraslan avatar hadley avatar jennybc avatar mocsabnimajneb 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  avatar  avatar  avatar  avatar

whisker's Issues

Variables with a period in the name fail

Whisker seems to fail when there is a period in the name of the variable. Considering that R variables quite typically have periods in the name, this is problematic.

> whisker.render("{{user.name}}", list(user.name=342))
[1] ""
> whisker.render("{{username}}", list(username=342))
[1] "342"

If there is a way around this please let me know. I imagine it's a quick fix. Also if this is an intentional design choice that'd be good to know too. Thanks!

no example for rowSplit()

Do you happen to have a simple example to illustrate how to use rowSplit()? It would be a big help. Dank u vriendelijk!

Add me to this repo?

Hi @edwindj. As per our chat, I'm happy to take the lead on getting a release ready. It would be nice to do a few housekeeping tasks during this process, e.g. tag releases, update README & badges, etc.. To that end, maybe you could add me as a collaborator with write or admin permissions. That way I could do things, cc'ing or tagging you for awareness, but not requiring you to be involved in each step.

Variables that start with period are replaced with empty string

I was using the pattern sometimes used in the tidyverse where you name your variables something short with a period at the beginning like .v1 or .v2. This doesn't work in whisker for some reason. The variable just gets replaced by an empty string.

See your example (slightly altered) below. When I change name to .name it no longer renders:

template <- 
  'Hello {{.name}}
You have just won ${{value}}!
{{#in_ca}}
Well, ${{taxed_value}}, after taxes.
{{/in_ca}}
'

data <- list( .name = "Chris"
              , value = 10000
              , taxed_value = 10000 - (10000 * 0.4)
              , in_ca = TRUE
)

text <- whisker.render(template, data)
cat(text)
## Hello 
## You have just won $10000!
## Well, $6000, after taxes.

Feature request: function to return data frame of keys in template

It would be nice to have a function that generates a data frame of keys for a given template for programmatic generation of input data. I'm thinking something along the lines of:

template <- 
    "{{#dat}}
    count: {{count}}, spray: {{spray}}\n
    {{/dat}}" 
whisker::getKeys(template)
#>   rawkey first last   key type
#> 1   #dat     1    8   dat    #
#> 2  count    20   28 count     
#> 3  spray    38   46 spray     
#> 4   /dat    49   56   dat    /

FWIW, the functionality in {whisker} already exists, it just needs to be exposed:

template <- 
    "{{#dat}}
    count: {{count}}, spray: {{spray}}\n
    {{/dat}}" 

f <- whisker:::parseTemplate(template)
get("key", envir = environment(f))
#>   rawkey first last   key type
#> 1   #dat     1    8   dat    #
#> 2  count    20   28 count     
#> 3  spray    38   46 spray     
#> 4   /dat    49   56   dat    /

Created on 2020-09-10 by the reprex package (v0.3.0)

More examples

Total newbie here (R and whisker).
A good addition to the homepage would be an example of taking a template that is a file, and creating an output html file.
Thanks for considering

impossible to use named sections when key is unknown

Thanks for a great package. R really needs a good templating engine.

If the names of hash$people are unknown, there appears to be now way of accessing the data in it's children.

library(whisker)

hash <- list(
  people = list(
    a = list(
      first = "john",
      last = "johnsson"
    ),
    b = list(
      first = "peter",
      last = "petersson"
    ),
    c = list(
      first = "steve",
      last = "stevesson"
    )
  ),
  stuff = c(1:5)
)

template <- "
{{#people}}
<h1>Hello {{first}}</h1>
{{/people}}
"

result <- whisker::whisker.render(template = template, data = hash)
print(HTML(result))

Link to stackoverflow.

Feature request: detect non-empty lists

If I have the following data:

data <- list(users = list(list(name = "bob"), list(name = "alice")))

I might want to know if the list is empty or not. For example, this would be my desired template:

template <- "{{#users.length}}Users: {{#users}}{{name}} {{/users}}{{/users.length}}{{^users.length}}No users{{/users.length}}"

It uses .length as a conditional that is true if there are any elements and false if it's empty.

This is not an official standard mustache feature, but it is implemented in some languages. See here for details.

'>' in replacement

How can I get that work?

R> dd = list(a = '>> blim')
R> tt = "{{a}} blam blum"
R> whisker.render(tt,dd)
### [1] "&gt;&gt; blim blam blum"

I want

">> blim blam blum"

Thanks, Michel

Inconsistent treatment of newlines?

I'm hoping to use whisker for a markdown file where treatment of spaces and newlines is critical for, for example, specifying new paragraphs. I think the treatment of newlines may be inconsistent when using whisker.

For example, consider this template and calls to whisker.render:

template <- 
"{{#var}}
var is true
{{/var}}
{{^var}}
var is not true
{{/var}}"
whisker.render(template, list(var=TRUE))
whisker.render(template, list(var=FALSE))

I would expect the output to be either "var is true\n" or "var is not true\n" depending on the value of var. However, in the second case, the output has an extra newline at the start: "\nvar is not true\n".

Inconsistent newlines when section value is in a list

There is an inconsistency in the whitespace generated by these two templates:

str1 <- 'header
{{#query}}
holla
{{/query}}
footer'
str2 <- 'header
{{#obj.query}}
holla
{{/obj.query}}
footer'

(the only difference is that the section variable is within a list obj in the second version).

This version gives what I would expect:

library(whisker)
whisker.render(str1, list(query=TRUE))  # "header\nholla\nfooter"
whisker.render(str1, list(query=FALSE)) # "header\nfooter"

While the second version generates extra newlines:

library(whisker)
whisker.render(str2, list(obj=list(query=TRUE)))  # "header\n\nholla\n\nfooter"
whisker.render(str2, list(obj=list(query=FALSE))) # "header\n\nfooter"

This does not affect the version from CRAN (0.3-2).

Option to check parameters exist

I think it would be great to have the ability to turn on an option which checked to see if parameters existed, and printed a warning / died if missing, e.g. something like

 template <- "Hello {{place}}!"
 whisker.render(template, checkvars=TRUE)

produces a warning, e.g.

  Warning: variable "place" undefined in ....

Due to the possibility of nested tags, this is very hard to check externally, so something like this is hard to verify without parsing the structure of the mustache file and comparing to the structure of the R environment:

 {{#repo}}
    <b>{{name}}</b>
 {{/repo}}

This is an issue as minor typos can lead to missing variables and hard to detect errors in rendered templates.

See also discussion here: http://stackoverflow.com/questions/16595621/error-safe-templating-with-brew-whisker

templates don't recognise names containing `.`

Templates don' t handle names containing .

a.test <- 'World'
template <- template <- "Hello {{a.test}}!"
whisker.render(template)
## Error in value[[key]] : subscript out of bounds
whisker.render(template, list(a.test = a.test))
## [1] "Hello !"

mustache.github.com -> mustache.github.io

Hello,

Thank you for your work on this package!

I noticed there are a few references to mustache.github.com in the README and the About section, but it appears Github would prefer them to be mustache.github.io

Template vector, first element empty string does not work

❯ whisker.render(c("xxx", "foobar"), list())
[1] "xxx\nfoobar"

❯ whisker.render(c("", "foobar"), list())
[1] ""

I suppose I can remove the "" and add one or more \ns to the beginning of the first non-empty string in the character vector as a workaround. But still, this is a bug imo, unless I am missing something.

Lambdas

Are there any plans to implement lambdas?

Problem with {{, even when changing delimiters

I've been trying to get whisker working with LaTeX (which uses a lot of braces)

At first I thought it wouldn't be an issue since there's proper nesting:

> template <- 
+ 
+ 'Hello {{{{name}}}}
+ You have just won ${{value}}!
+ 
+ '
> text <- whisker.render(template, data)
> cat(text)
Hello 
You have just won $10000!

So I thought, fine, I'll just switch the delimeters:

> template <- 
+ '
+ {{=<% %>=}}
+ Hello {{<%name%>}}
+ You have just won ${{<%value%>}}!
+ 
+ '
> text <- whisker.render(template, data)
> cat(text)

Hello ~~~~~~~~~~~~~Chris{{
You have just won $}}10000~~~~~~~~~~~~~!

Which is a bit weird? Apologies if I'm just doing something incorrectly.

It's not clear how to use whisker to iteratively generate text

I am new to whisker but my assumption with a template is that its main purpose is to be used when iterating over a vector or list. (If you just want output of length 1 you'd just write the output directly).

But I can't work out how to feed a set of lists (eg a tibble) as the environment for whisker - the documentation isn't clear enough for me. Here's a reprex of what I'm trying. I've used purrr::pmap to show what I want, and then tried to achieve the equivalent with whisker.

suppressPackageStartupMessages(library(dplyr))
suppressPackageStartupMessages(library(stringr))
suppressPackageStartupMessages(library(purrr))
suppressPackageStartupMessages(library(whisker))

df <- tibble(
  name = c("Adam", "Barbara", "Chris"),
  home = c("Aylesbury", "Blackburn", "Coxwold"),
  url = c("adamsapples.co.uk", "barbsberries.co.uk", "coxwoldcherries.co.uk")
)

# with purrr and stringr
purrr::pmap_chr(df, ~ stringr::str_glue(
  "<li><a href=\"{..3}\">{..1} from {..2}</a></li>")) %>% 
  str_c(collapse = "\n") %>% 
  str_c("<ul>\n", ., "\n</ul>")
#> [1] "<ul>\n<li><a href=\"adamsapples.co.uk\">Adam from Aylesbury</a></li>\n<li><a href=\"barbsberries.co.uk\">Barbara from Blackburn</a></li>\n<li><a href=\"coxwoldcherries.co.uk\">Chris from Coxwold</a></li>\n</ul>"
# writeLines(output, "output.html")

# with whisker
templ <- "<li>
<a href=\"{{url}}\">{{name}} from {{home}}</a>
</li>"

# expected this to work but doesn't
whisker::whisker.render(templ, df)
#> [1] "<li>\n<a href=\"adamsapples.co.uk,barbsberries.co.uk,coxwoldcherries.co.uk\">Adam,Barbara,Chris from Aylesbury,Blackburn,Coxwold</a>\n</li>"

# trying with pmap instead - gives error
purrr::pmap_chr(df, ~ whisker::whisker.render(templ, .))
#> Error in value[[key]]: subscript out of bounds

Created on 2020-03-20 by the reprex package (v0.3.0)

R package with whisker as dependency fails CRAN checks on r-devel-windows

I wanted to bring this to your attention. We recently submitted a new release of a package, rslurm, to CRAN that has a strong dependency of whisker (>=0.3) (in the Imports field of the DESCRIPTION file). Unfortunately our package fails CRAN checks for the experimental r-devel build on Windows (r-devel-windows-x86_64-gcc10-UCRT). It looks like this is because whisker depends on markdown which isn't available on that version of R: https://www.r-project.org/nosvn/R.check/r-devel-windows-x86_64-gcc10-UCRT/whisker-00check.html

Anyway, we really appreciate the work you put into this package and it would be great if we could get this resolved so that we can continue depending on whisker in the future. Please let me know if there is anything I can do.

Any plans to push to CRAN?

Excellent work with Whisker. I use it with all my R packages. I was wondering if you had any plans to push the latest version of whisker to CRAN. Especially, the fix for empty templates is critical to the functionality of several R packages that I am authoring.

I am also curious about implementation of lambdas in Whisker. If you have already done some work, that would be useful, and I can take a crack at more implementation.

whisker does not support #sections with non empty lists

While whisker supports sections, it does not appear to support sections with non-empty lists as described in https://mustache.github.io/mustache.5.html:

Template:

{{#repo}}
  <b>{{name}}</b>
{{/repo}}

Hash:

{
  "repo": [
    { "name": "resque" },
    { "name": "hub" },
    { "name": "rip" }
  ]
}

Output:

<b>resque</b>
<b>hub</b>
<b>rip</b>

Using JSON

This closely follows the mustache documentation by usingjsonlite to convert the hash to an R object. The R object is a list with a data frame of 3 rows.

library(jsonlite)
library(whisker)

tmpl <- 
  "{{#repo}}
  <b>{{name}}</b>
  {{/repo}}"

hash <- 
  '{
    "repo": [
      { "name": "resque" },
      { "name": "hub" },
      { "name": "rip" }
    ]
  }'

data <- fromJSON(hash)  # list of data.frame not list of list


whisker.render(tmpl,data)   

This does not conform to the specification is not correct as in collapses the name column rather than returning three results. According to the specification, I would expect this result:

c("<b>resque</b>","<b>hub</b>","<b>rip</b>")

Using list-of-lists

Using a list of lists does not work either:

data <- list( repo = list( name="resque", name="hub", name="rip") )
whisker.render(tmpl,data) 
# [1] "<b>resque</b>"

Is there a way to get the parent variable in a nested loop?

I'm exploring how to set up a nested loop. Here's my template and call to whisker.render:

temp_string <- "
{{#i}}
# {{.}}
{{#j}}
## {{.}}
key = paste({{../}}, {{.}})
{{/j}}
{{/i}}"

template_contents <- strsplit(whisker::whisker.render(temp_string,
                                                      data = list(j = 1:2,
                                                                  i = letters[1:3])), "\n")[[1]]

Which results in:

# a
## 1
key = paste(, 1)
## 2
key = paste(, 2)
# b
## 1
key = paste(, 1)
## 2
key = paste(, 2)
# c
## 1
key = paste(, 1)
## 2
key = paste(, 2)

ALMOST what I need! Is there any way to get the {{../}} to pull the "parent" i?

Allowing specification of delimiters

I would like to use mustache templates with latex. But the trouble is that latex makes extensive use of { and } which interferes with mustache syntax. I read in the mustache documentation that it is possible to customize delimiters. Does whisker already support it, or can it be made to support it?

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.