forked from ramnathv/htmlwidgets
-
Notifications
You must be signed in to change notification settings - Fork 1
/
scaffold.R
193 lines (181 loc) · 5.61 KB
/
scaffold.R
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
#' Create implementation scaffolding for an HTML widget
#'
#' Add the minimal code required to implement an HTML widget to an R package.
#'
#' @param name Name of widget
#' @param bowerPkg Optional name of \href{http://bower.io/}{Bower} package upon
#' which this widget is based. If you specify this parameter then bower will
#' be used to automatically download the widget's source code and dependencies
#' and add them to the widget's YAML.
#' @param edit Automatically open the widget's JavaScript source file after
#' creating the scaffolding.
#'
#' @note This function must be executed from the root directory of the package
#' you wish to add the widget to.
#'
#' @export
scaffoldWidget <- function(name, bowerPkg = NULL, edit = interactive()){
if (!file.exists('DESCRIPTION')){
stop(
"You need to create a package to house your widget first!",
call. = F
)
}
if (!file.exists('inst')){
dir.create('inst')
}
package = read.dcf('DESCRIPTION')[[1,"Package"]]
addWidgetConstructor(name, package, edit)
addWidgetYAML(name, bowerPkg, edit)
addWidgetJS(name, edit)
}
addWidgetConstructor <- function(name, package, edit){
tpl <- paste(readLines(
system.file('templates/widget_r.txt', package = 'htmlwidgets')
), collapse = "\n")
capName = function(name){
paste0(toupper(substring(name, 1, 1)), substring(name, 2))
}
if (!file.exists(file_ <- sprintf("R/%s.R", name))){
cat(
sprintf(tpl, name, name, package, name, name, name, name, name, name,
package, name, capName(name), name),
file = file_
)
message('Created boilerplate for widget constructor ', file_)
} else {
message(file_, " already exists")
}
if (edit) fileEdit(file_)
}
addWidgetYAML <- function(name, bowerPkg, edit){
tpl <- "# (uncomment to add a dependency)
# dependencies:
# - name:
# version:
# src:
# script:
# stylesheet:
"
if (!file.exists('inst/htmlwidgets')){
dir.create('inst/htmlwidgets')
}
if (!is.null(bowerPkg)){
installBowerPkg(bowerPkg)
tpl <- getConfig(bowerPkg)
}
if (!file.exists(file_ <- sprintf('inst/htmlwidgets/%s.yaml', name))){
cat(tpl, file = file_)
message('Created boilerplate for widget dependencies at ',
sprintf('inst/htmlwidgets/%s.yaml', name)
)
} else {
message(file_, " already exists")
}
if (edit) fileEdit(file_)
}
addWidgetJS <- function(name, edit){
tpl <- paste(readLines(
system.file('templates/widget_js.txt', package = 'htmlwidgets')
), collapse = "\n")
if (!file.exists(file_ <- sprintf('inst/htmlwidgets/%s.js', name))){
cat(sprintf(tpl, name), file = file_)
message('Created boilerplate for widget javascript bindings at ',
sprintf('inst/htmlwidgets/%s.js', name)
)
} else {
message(file_, " already exists")
}
if (edit) fileEdit(file_)
}
# Install bower package to inst/htmlwidgets/lib
#
# This function uses bower to install a javascript package along with
# its dependencies.
installBowerPkg <- function(pkg){
# check if bower is installed
if (findBower() == ""){
stop(
"Please install bower from http://bower.io",
call. = FALSE
)
}
#check if we are in the root directory of a package
if (!file.exists('DESCRIPTION')){
stop("You need to be in a package directory to run this!",
call. = F)
}
# set up .bowerrc to install packages to correct directory
if (!file.exists('.bowerrc')){
x = '{"directory": "inst/htmlwidgets/lib"}'
cat(x, file = '.bowerrc')
}
# Install package
message("Installing ", pkg, " using bower...", "\n\n")
cmd <- sprintf('%s install %s', findBower(), pkg)
system(cmd)
message("... Done! installing ", pkg)
}
# Try really hard to find bower in Windows
findBower <- function(){
# a slightly more robust finder of bower for windows
# which does not require PATH environment variable to be set
bowerPath = if(Sys.which("bower") == "") {
# if it does not find Sys.which('bower')
# also check APPDATA to see if found there
if(identical(.Platform$OS.type,"windows")) {
Sys.which(file.path(Sys.getenv("APPDATA"),"npm","bower."))
}
} else {
Sys.which("bower")
}
return(bowerPath)
}
# Read the bower.json file
readBower <- function(pkg, src = "inst/htmlwidgets/lib"){
bower = jsonlite::fromJSON(
file.path(src, pkg, 'bower.json')
)
spec = list(
name = basename(bower$name),
version = bower$version,
src = paste0('htmlwidgets/lib/', pkg),
script = getMinified(
bower$main[grepl('^.*\\.js$', bower$main)], basename(bower$name)
),
style = getMinified(
bower$main[grepl('^.*\\.css$', bower$main)], basename(bower$name)
)
)
deps = bower$dependencies
spec = Filter(function(x) length(x) != 0, spec)
list(spec = spec, deps = deps)
}
# Get YAML configuration for widget
getConfig <- function(pkg, src = "inst/htmlwidgets/lib"){
deps = readBower(pkg, src)$deps
all = c(names(deps),pkg)
config = lapply(all, function(pkg){
readBower(pkg, src = src)$spec
})
yaml::as.yaml(list(dependencies = config))
}
# Replace dependency with minified version if it exists
getMinified <- function(x, name, src = 'inst/htmlwidgets/lib'){
xFile = file.path(src, name, x)
ext = tools::file_ext(xFile)
minFile = paste0(tools::file_path_sans_ext(xFile), '.min.', ext)
sapply(seq_along(x), function(i){
if (file.exists(minFile[i])) {
file.path(dirname(x[i]), basename(minFile[i]))
} else {
x[i]
}
})
}
# invoke file.edit in a way that will bind to the RStudio editor
# when running inside RStudio
fileEdit <- function(file) {
fileEditFunc <- eval(parse(text = "file.edit"), envir = globalenv())
fileEditFunc(file)
}