1
|
|
###########################################################################/**
|
2
|
|
# @RdocDefault rcat
|
3
|
|
# @alias rcat.RspString
|
4
|
|
# @alias rcat.RspDocument
|
5
|
|
# @alias rcat.RspRSourceCode
|
6
|
|
# @alias rcat.function
|
7
|
|
# @alias rcat.expression
|
8
|
|
# @alias rsource
|
9
|
|
# @alias rsource.default
|
10
|
|
# @alias rsource.RspString
|
11
|
|
# @alias rsource.RspDocument
|
12
|
|
# @alias rsource.RspRSourceCode
|
13
|
|
# @alias rsource.function
|
14
|
|
# @alias rsource.expression
|
15
|
|
#
|
16
|
|
# @title "Evaluates an RSP string and outputs the generated string"
|
17
|
|
#
|
18
|
|
# \description{
|
19
|
|
# @get "title".
|
20
|
|
# }
|
21
|
|
#
|
22
|
|
# \usage{
|
23
|
|
# @usage rcat,default
|
24
|
|
# @usage rsource,default
|
25
|
|
# }
|
26
|
|
#
|
27
|
|
# \arguments{
|
28
|
|
# \item{...}{A @character string with RSP markup.}
|
29
|
|
# \item{file, path}{Alternatively, a file, a URL or a @connection from
|
30
|
|
# with the strings are read.
|
31
|
|
# If a file, the \code{path} is prepended to the file, iff given.}
|
32
|
|
# \item{envir}{The @environment in which the RSP string is
|
33
|
|
# preprocessed and evaluated.}
|
34
|
|
# \item{args}{A named @list of arguments assigned to the environment
|
35
|
|
# in which the RSP string is parsed and evaluated.
|
36
|
|
# See @see "R.utils::cmdArgs".}
|
37
|
|
# \item{output}{A @connection, or a pathname where to direct the output.
|
38
|
|
# If \code{""}, the output is sent to the standard output.}
|
39
|
|
# \item{buffered}{If @TRUE, and \code{output=""}, then the RSP output is
|
40
|
|
# outputted as soon as possible, if possible.}
|
41
|
|
# \item{append}{Only applied if \code{output} specifies a pathname.
|
42
|
|
# If @TRUE, then the output is appended to the file, otherwise
|
43
|
|
# the files content is overwritten.}
|
44
|
|
# \item{verbose}{See @see "R.utils::Verbose".}
|
45
|
|
# }
|
46
|
|
#
|
47
|
|
# \value{
|
48
|
|
# Returns (invisibly) the outputted @see "RspStringProduct".
|
49
|
|
# }
|
50
|
|
#
|
51
|
|
# \section{Processing RSP strings from the command line}{
|
52
|
|
# Using @see "Rscript" and \code{rcat()}, it is possible to process
|
53
|
|
# an RSP string and output the result from the command line. For example,
|
54
|
|
#
|
55
|
|
# \code{Rscript -e "R.rsp::rcat('A random integer in [1,<\%=K\%>]: <\%=sample(1:K, size=1)\%>')" --args --K=50}
|
56
|
|
#
|
57
|
|
# parses and evaluates the RSP string and outputs the result to
|
58
|
|
# standard output.
|
59
|
|
# A CLI-friendly alternative to the above is:
|
60
|
|
#
|
61
|
|
# \code{Rscript -e R.rsp::rcat "A random integer in [1,<\%=K\%>]: <\%=sample(1:K, size=1)\%>" --args --K=50}
|
62
|
|
# }
|
63
|
|
#
|
64
|
|
# \section{rsource()}{
|
65
|
|
# The \code{rsource(file, ...)} is a convenient wrapper
|
66
|
|
# for \code{rcat(file=file, ..., output="", buffered=FALSE)}.
|
67
|
|
# As an analogue, \code{rsource()} is to an RSP file what
|
68
|
|
# \code{source()} is to an R script file.
|
69
|
|
# }
|
70
|
|
#
|
71
|
|
# @examples "../incl/rcat.Rex"
|
72
|
|
#
|
73
|
|
# @author
|
74
|
|
#
|
75
|
|
# \seealso{
|
76
|
|
# To store the output in a string (instead of displaying it), see
|
77
|
|
# @see "rstring".
|
78
|
|
# For evaluating and postprocessing an RSP document and
|
79
|
|
# writing the output to a file, see @see "rfile".
|
80
|
|
# }
|
81
|
|
#
|
82
|
|
# @keyword print
|
83
|
|
# @keyword IO
|
84
|
|
# @keyword file
|
85
|
|
#*/###########################################################################
|
86
|
|
setMethodS3("rcat", "default", function(..., file=NULL, path=NULL, envir=parent.frame(), args="*", output="", buffered=TRUE, append=FALSE, verbose=FALSE) {
|
87
|
|
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
88
|
|
# Validate arguments
|
89
|
|
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
90
|
|
# Argument 'file' & 'path':
|
91
|
1
|
if (inherits(file, "connection")) {
|
92
|
1
|
} else if (is.character(file)) {
|
93
|
1
|
if (!is.null(path)) {
|
94
|
0
|
file <- file.path(path, file)
|
95
|
|
}
|
96
|
1
|
if (!isUrl(file)) {
|
97
|
1
|
file <- Arguments$getReadablePathname(file, absolute=TRUE)
|
98
|
|
}
|
99
|
|
}
|
100
|
|
|
101
|
|
# Argument 'verbose':
|
102
|
1
|
verbose <- Arguments$getVerbose(verbose)
|
103
|
1
|
if (verbose) {
|
104
|
1
|
pushState(verbose)
|
105
|
1
|
on.exit(popState(verbose))
|
106
|
|
}
|
107
|
|
|
108
|
|
|
109
|
1
|
verbose && enter(verbose, "rcat() for default")
|
110
|
|
|
111
|
1
|
if (is.null(file)) {
|
112
|
1
|
s <- RspString(...)
|
113
|
|
} else {
|
114
|
1
|
verbose && cat(verbose, "Input file: ", file)
|
115
|
1
|
s <- .readText(file)
|
116
|
1
|
s <- RspString(s, source=file, ...)
|
117
|
1
|
s <- setMetadata(s, name="source", value=file)
|
118
|
|
}
|
119
|
1
|
verbose && cat(verbose, "Length of RSP string: ", nchar(s))
|
120
|
|
|
121
|
1
|
res <- rcat(s, output=output, buffered=buffered, append=append, envir=envir, args=args, verbose=verbose)
|
122
|
|
|
123
|
1
|
verbose && exit(verbose)
|
124
|
|
|
125
|
1
|
invisible(res)
|
126
|
|
}) # rcat()
|
127
|
|
|
128
|
|
|
129
|
|
setMethodS3("rcat", "RspString", function(..., envir=parent.frame(), args="*", output="", buffered=TRUE, append=FALSE, verbose=FALSE) {
|
130
|
|
# Argument 'buffered':
|
131
|
1
|
if (!buffered) {
|
132
|
1
|
isStdout <- FALSE
|
133
|
1
|
if (is.character(output) && output == "") {
|
134
|
1
|
isStdout <- TRUE
|
135
|
0
|
} else if (inherits(output, "connection")) {
|
136
|
0
|
ci <- summary(output)
|
137
|
0
|
isStdout <- identical(ci$class, "terminal") &&
|
138
|
0
|
identical(ci$description, "stdout")
|
139
|
|
}
|
140
|
1
|
if (!isStdout) {
|
141
|
0
|
throw("Argument 'buffered' must be TRUE unless 'output' directs to the standard output.")
|
142
|
|
}
|
143
|
|
}
|
144
|
|
|
145
|
|
# Argument 'verbose':
|
146
|
1
|
verbose <- Arguments$getVerbose(verbose)
|
147
|
1
|
if (verbose) {
|
148
|
1
|
pushState(verbose)
|
149
|
1
|
on.exit(popState(verbose))
|
150
|
|
}
|
151
|
|
|
152
|
1
|
verbose && enter(verbose, "rcat() for RspString")
|
153
|
|
|
154
|
1
|
outputP <- ifelse(buffered, "RspStringProduct", "stdout")
|
155
|
1
|
verbose && printf(verbose, "Buffered: %s\n", buffered)
|
156
|
1
|
verbose && printf(verbose, "Type of output: %s\n", outputP)
|
157
|
1
|
verbose && cat(verbose, "Arguments:")
|
158
|
1
|
verbose && str(verbose, args)
|
159
|
|
|
160
|
1
|
s <- rstring(..., envir=envir, args=args, output=outputP,
|
161
|
1
|
verbose=less(verbose, 10))
|
162
|
|
|
163
|
1
|
verbose && cat(verbose, "Result:")
|
164
|
1
|
verbose && str(verbose, s)
|
165
|
|
|
166
|
1
|
if (!is.null(s)) {
|
167
|
1
|
verbose && enter(verbose, "Outputting")
|
168
|
1
|
outputT <- output
|
169
|
1
|
if (is.character(output)) {
|
170
|
1
|
if (output == "")
|
171
|
1
|
outputT <- "<stdout>"
|
172
|
|
} else {
|
173
|
1
|
outputT <- "<connection>"
|
174
|
|
}
|
175
|
1
|
verbose && printf(verbose, "Output: %s\n", outputT)
|
176
|
1
|
verbose && printf(verbose, "Appending: %s\n", append)
|
177
|
1
|
verbose && printf(verbose, "String: (nchars = %d) %s\n", nchar(s), sQuote(substring(s, first = 1L, last = 60L)))
|
178
|
|
|
179
|
1
|
tryCatch({
|
180
|
|
## WORKAROUND: Avoid infinite loop of warnings on "invalid char string
|
181
|
|
## in output conversion" by cat(). Reported to R-devel on 2017-01-03
|
182
|
|
## https://stat.ethz.ch/pipermail/r-devel/2017-January/073571.html
|
183
|
1
|
oopts <- options(warn = 2)
|
184
|
1
|
on.exit(options(oopts))
|
185
|
|
|
186
|
1
|
base::cat(s, file=output, append=append)
|
187
|
1
|
}, error = function(ex) {
|
188
|
0
|
pattern <- gettextf("invalid char string in output conversion")
|
189
|
0
|
msg <- conditionMessage(ex)
|
190
|
0
|
if (any(grepl(pattern, msg))) {
|
191
|
0
|
options(oopts)
|
192
|
0
|
msg <- sprintf("Failed to output RSP product (<string of length %s character> with encoding %s) under encoding %s using cat(), because %s. Used writeBin(charToRaw(.)) as a fallback, but please validate output.", nchar(s), hpaste(sQuote(unique(Encoding(s)))), sQuote(getOption("encoding")), sQuote(msg))
|
193
|
0
|
warning(msg)
|
194
|
0
|
r <- charToRaw(s)
|
195
|
0
|
writeBin(r, con = output)
|
196
|
|
} else {
|
197
|
0
|
throw(msg)
|
198
|
|
}
|
199
|
|
})
|
200
|
|
|
201
|
1
|
verbose && exit(verbose)
|
202
|
|
}
|
203
|
|
|
204
|
1
|
verbose && exit(verbose)
|
205
|
|
|
206
|
1
|
invisible(s)
|
207
|
|
}) # rcat()
|
208
|
|
|
209
|
|
|
210
|
|
setMethodS3("rcat", "RspDocument", rcat.RspString)
|
211
|
|
setMethodS3("rcat", "RspRSourceCode", rcat.RspString)
|
212
|
|
setMethodS3("rcat", "RspShSourceCode", rcat.RspString)
|
213
|
|
setMethodS3("rcat", "function", rcat.RspString)
|
214
|
|
setMethodS3("rcat", "expression", rcat.RspString)
|