Skip to content

Commit eb51153

Browse files
committed
Use new renderTemplate function for scaffold instead of sprintf
1 parent be51515 commit eb51153

File tree

7 files changed

+62
-39
lines changed

7 files changed

+62
-39
lines changed

R/scaffold.R

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,15 @@ slurp <- function(file) {
5151
), collapse = "\n")
5252
}
5353

54+
# Perform a series of pattern replacements on str.
55+
# Example: renderTemplate("foo ${x} bar ${y} baz ${x}", list(x = 1, y = 2))
56+
# Produces: "foo 1 bar 2 baz 1"
57+
renderTemplate <- function(str, substitutions) {
58+
Reduce(function(str, name) {
59+
gsub(paste0("\\$\\{", name, "\\}"), substitutions[[name]], str)
60+
}, names(substitutions), str)
61+
}
62+
5463
capName = function(name){
5564
paste0(toupper(substring(name, 1, 1)), substring(name, 2))
5665
}
@@ -59,7 +68,7 @@ addWidgetConstructor <- function(name, package, edit){
5968
tpl <- slurp('templates/widget_r.txt')
6069
if (!file.exists(file_ <- sprintf("R/%s.R", name))){
6170
cat(
62-
sprintf(tpl, name, name, package, name, name, name, name, name, name, package, name, capName(name), name, name, name),
71+
renderTemplate(tpl, list(name = name, package = package, capName = capName(name))),
6372
file = file_
6473
)
6574
message('Created boilerplate for widget constructor ', file_)
@@ -93,7 +102,7 @@ addWidgetYAML <- function(name, edit){
93102
}
94103

95104
addPackageJSON <- function(npmPkg) {
96-
tpl <- sprintf(slurp('templates/widget_package.json.txt'), npmPkg)
105+
tpl <- renderTemplate(slurp('templates/widget_package.json.txt'), list(npmPkg = npmPkg))
97106
if (!file.exists('package.json')) {
98107
cat(tpl, file = 'package.json')
99108
message('Created package.json')
@@ -103,7 +112,7 @@ addPackageJSON <- function(npmPkg) {
103112
}
104113

105114
addWebpackConfig <- function(name) {
106-
tpl <- sprintf(slurp('templates/widget_webpack.config.js.txt'), name, name)
115+
tpl <- renderTemplate(slurp('templates/widget_webpack.config.js.txt'), list(name = name))
107116
if (!file.exists('webpack.config.js')) {
108117
cat(tpl, file = 'webpack.config.js')
109118
message('Created webpack.config.js')
@@ -120,7 +129,7 @@ addWidgetJS <- function(name, edit){
120129
dir.create('srcjs')
121130
}
122131
if (!file.exists(file_ <- sprintf('srcjs/%s.js', name))){
123-
cat(sprintf(tpl, name), file = file_)
132+
cat(renderTemplate(tpl, list(name = name)), file = file_)
124133
message('Created boilerplate for widget javascript bindings at ',
125134
sprintf('srcjs/%s.js', name)
126135
)
@@ -131,7 +140,7 @@ addWidgetJS <- function(name, edit){
131140
}
132141

133142
addExampleApp <- function(name) {
134-
tpl <- sprintf(slurp('templates/widget_app.R.txt'), name, name, capName(name), name)
143+
tpl <- renderTemplate(slurp('templates/widget_app.R.txt'), list(name = name, capName = capName(name)))
135144
if (!file.exists('app.R')) {
136145
cat(tpl, file = 'app.R')
137146
message('Created example app.R')

inst/templates/widget_app.R.txt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
library(shiny)
2-
library(%s)
2+
library(${name})
33

44
ui <- fluidPage(
55
titlePanel("reactR HTMLWidget Example"),
6-
%sOutput('widgetOutput')
6+
${name}Output('widgetOutput')
77
)
88

99
server <- function(input, output, session) {
10-
output$widgetOutput <- render%s(
11-
%s("Hello world!")
10+
output$widgetOutput <- render${capName}(
11+
${name}("Hello world!")
1212
)
1313
}
1414

inst/templates/widget_js.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
import { reactWidget } from 'reactR';
22

3-
reactWidget('%s', 'output', {});
3+
reactWidget('${name}', 'output', {});

inst/templates/widget_package.json.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"private": true,
33
"dependencies": {
4-
%s
4+
${npmPkg}
55
},
66
"devDependencies": {
77
"webpack": "^4.27.1",

inst/templates/widget_r.txt

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,53 +5,53 @@
55
#' @import htmlwidgets
66
#'
77
#' @export
8-
%s <- function(message, width = NULL, height = NULL, elementId = NULL) {
8+
${name} <- function(message, width = NULL, height = NULL, elementId = NULL) {
99

1010
# describe a React component to send to the browser for rendering.
1111
component <- reactR::reactMarkup(htmltools::tag("div", list(message)))
1212

1313
# create widget
1414
htmlwidgets::createWidget(
15-
name = '%s',
15+
name = '${name}',
1616
component,
1717
width = width,
1818
height = height,
19-
package = '%s',
19+
package = '${package}',
2020
elementId = elementId
2121
)
2222
}
2323

24-
#' Shiny bindings for %s
24+
#' Shiny bindings for ${name}
2525
#'
26-
#' Output and render functions for using %s within Shiny
26+
#' Output and render functions for using ${name} within Shiny
2727
#' applications and interactive Rmd documents.
2828
#'
2929
#' @param outputId output variable to read from
3030
#' @param width,height Must be a valid CSS unit (like \code{'100\%%'},
3131
#' \code{'400px'}, \code{'auto'}) or a number, which will be coerced to a
3232
#' string and have \code{'px'} appended.
33-
#' @param expr An expression that generates a %s
33+
#' @param expr An expression that generates a ${name}
3434
#' @param env The environment in which to evaluate \code{expr}.
3535
#' @param quoted Is \code{expr} a quoted expression (with \code{quote()})? This
3636
#' is useful if you want to save an expression in a variable.
3737
#'
38-
#' @name %s-shiny
38+
#' @name ${name}-shiny
3939
#'
4040
#' @export
41-
%sOutput <- function(outputId, width = '100%%', height = '400px'){
42-
htmlwidgets::shinyWidgetOutput(outputId, '%s', width, height, package = '%s')
41+
${name}Output <- function(outputId, width = '100%%', height = '400px'){
42+
htmlwidgets::shinyWidgetOutput(outputId, '${name}', width, height, package = '${package}')
4343
}
4444

45-
#' @rdname %s-shiny
45+
#' @rdname ${name}-shiny
4646
#' @export
47-
render%s <- function(expr, env = parent.frame(), quoted = FALSE) {
47+
render${capName} <- function(expr, env = parent.frame(), quoted = FALSE) {
4848
if (!quoted) { expr <- substitute(expr) } # force quoted
49-
htmlwidgets::shinyRenderWidget(expr, %sOutput, env, quoted = TRUE)
49+
htmlwidgets::shinyRenderWidget(expr, ${name}Output, env, quoted = TRUE)
5050
}
5151

5252
#' Called by HTMLWidgets to produce the widget's root element.
53-
#' @rdname %s-shiny
54-
%s_html <- function(id, style, class, ...) {
53+
#' @rdname ${name}-shiny
54+
${name}_html <- function(id, style, class, ...) {
5555
tagList(
5656
reactR::html_dependency_react(),
5757
reactR::html_dependency_reacttools(),

inst/templates/widget_webpack.config.js.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
var path = require('path');
22

33
module.exports = {
4-
entry: path.join(__dirname, 'srcjs', '%s.js'),
4+
entry: path.join(__dirname, 'srcjs', '${name}.js'),
55
output: {
66
path: path.join(__dirname, 'inst', 'htmlwidgets'),
7-
filename: '%s.js'
7+
filename: '${name}.js'
88
},
99
module: {
1010
rules: [

inst/www/react-tools/react-tools.js

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ window.reactR = (function () {
2020
args.push(tag.children[i]);
2121
}
2222
}
23-
return React.createElement.apply(null, args);
23+
return React.createElement.apply(React, args);
2424
}
2525

2626
var defaultOptions = {
@@ -46,12 +46,19 @@ window.reactR = (function () {
4646

4747
function formatDimension(dim, options) {
4848
if (options.appendPx) {
49-
return dim.toString() + 'px';
49+
return dim + 'px';
5050
} else {
5151
return dim;
5252
}
5353
}
5454

55+
function isTag(value) {
56+
return (typeof value === 'object')
57+
&& value.hasOwnProperty('name')
58+
&& value.hasOwnProperty('attribs')
59+
&& value.hasOwnProperty('children');
60+
}
61+
5562
/**
5663
* Creates an HTMLWidget that is updated by rendering a React component.
5764
* React component constructors are made available by specifying them by
@@ -67,15 +74,16 @@ window.reactR = (function () {
6774
name: name,
6875
type: type,
6976
factory: function (el, width, height) {
70-
var lastValue;
71-
renderValue = (function (value) {
72-
if (actualOptions.renderOnResize) {
73-
value.tag.attribs[actualOptions["widthProperty"]] = formatDimension(width);
74-
value.tag.attribs[actualOptions["heightProperty"]] = formatDimension(height);
75-
lastValue = value;
76-
}
77-
ReactDOM.render(hydrate(components, value.tag), el);
78-
});
77+
var lastValue,
78+
renderValue = (function (value) {
79+
// TODO Handle strings naturally
80+
if (actualOptions.renderOnResize) {
81+
value.tag.attribs[actualOptions["widthProperty"]] = formatDimension(width);
82+
value.tag.attribs[actualOptions["heightProperty"]] = formatDimension(height);
83+
lastValue = value;
84+
}
85+
ReactDOM.render(hydrate(components, value.tag), el);
86+
});
7987
return {
8088
renderValue: renderValue,
8189
resize: function (newWidth, newHeight) {
@@ -92,6 +100,12 @@ window.reactR = (function () {
92100

93101
return {
94102
reactWidget: reactWidget,
95-
hydrate: hydrate
103+
hydrate: hydrate,
104+
__internal: {
105+
defaultOptions: defaultOptions,
106+
mergeOptions: mergeOptions,
107+
formatDimension: formatDimension,
108+
isTag: isTag
109+
}
96110
};
97111
})()

0 commit comments

Comments
 (0)