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)

Read our documentation on viewing source code .

Loading