Skip to content

Commit

Permalink
closes #228: do not hard-code globalenv() as the environment for knit…
Browse files Browse the repository at this point in the history
…() any more; the default envir is parent.frame() for knit() now
  • Loading branch information
yihui committed Jun 4, 2012
1 parent f64c872 commit 09825ee
Show file tree
Hide file tree
Showing 4 changed files with 19 additions and 15 deletions.
11 changes: 6 additions & 5 deletions R/block.R
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ block_exec = function(params) {
options = params

## eval chunks (in an empty envir if cache)
env = if (options$cache) new.env(parent = globalenv()) else globalenv()
env = if (options$cache) new.env(parent = knit_global()) else knit_global()
.knitEnv$knit_env = env # make a copy of the envir
obj.before = ls(globalenv(), all.names = TRUE) # global objects before chunk

Expand Down Expand Up @@ -172,15 +172,16 @@ block_exec = function(params) {
output = str_c(unlist(wrap(res, options)), collapse = '') # wrap all results together

res.after = run_hooks(before = FALSE, options, env) # run 'after' hooks
if (options$cache) copy_env(env, globalenv())
if (options$cache) copy_env(env, knit_global())

output = str_c(c(res.before, output, res.after), collapse = '') # insert hook results
output = if (length(output) == 0L) '' else knit_hooks$get('chunk')(output, options)
plot_counter(reset = TRUE) # restore plot number

if (options$cache) {
obj.after = ls(globalenv(), all.names = TRUE) # figure out new global objs
objs = c(ls(env, all.names = TRUE), setdiff(obj.after, obj.before))
copy_env(globalenv(), knit_global(), setdiff(obj.after, obj.before))
objs = ls(env, all.names = TRUE)
block_cache(options, output, objs)
if (options$autodep) cache$objects(objs, code, options$label, options$cache.path)
}
Expand All @@ -191,7 +192,7 @@ block_exec = function(params) {
block_cache = function(options, output, objects) {
hash = options$hash
outname = str_c('.', hash)
assign(outname, output, envir = globalenv())
assign(outname, output, envir = knit_global())
## purge my old cache and cache of chunks dependent on me
cache$purge(str_c(valid_path(options$cache.path,
c(options$label, dep_list$get(options$label))), '_*'))
Expand All @@ -218,7 +219,7 @@ inline_exec = function(block) {
owd = setwd(input_dir()); on.exit(setwd(owd))
loc = block$location
for (i in 1:n) {
res = try(eval(parse(text = code[i]), envir = globalenv()))
res = try(eval(parse(text = code[i]), envir = knit_global()))
d = nchar(input)
## replace with evaluated results
str_sub(input, loc[i, 1], loc[i, 2]) = if (length(res)) {
Expand Down
12 changes: 6 additions & 6 deletions R/cache.R
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ new_cache = function() {
cache_save = function(keys, outname, hash) {
# keys are new variables created; outname is the text output of a chunk
path = cache_path(hash)
save(list = outname, file = str_c(path, '.RData'), envir = globalenv())
save(list = outname, file = str_c(path, '.RData'), envir = knit_global())
# FIXME: after R 2.15.0, this line can be removed
keys = setdiff(keys, '.Random.seed')
tools:::makeLazyLoadDB(globalenv(), path, variables = keys)
tools:::makeLazyLoadDB(knit_global(), path, variables = keys)
}

save_objects = function(objs, label, path) {
Expand All @@ -43,10 +43,10 @@ new_cache = function() {

cache_load = function(hash) {
path = cache_path(hash)
lazyLoad(path, envir = globalenv())
lazyLoad(path, envir = knit_global())
# load output from last run if exists
if (file.exists(path2 <- str_c(path, '.RData'))) {
load(path2, envir = globalenv())
load(path2, envir = knit_global())
}
}

Expand All @@ -69,8 +69,8 @@ new_cache = function() {

## code output is stored in .[hash], so cache=TRUE won't lose output as cacheSweave does
cache_output = function(hash) {
if (exists(str_c('.', hash), envir = globalenv(), mode = 'character')) {
get(str_c('.', hash), envir = globalenv(), mode = 'character')
if (exists(str_c('.', hash), envir = knit_global(), mode = 'character')) {
get(str_c('.', hash), envir = knit_global(), mode = 'character')
} else ''
}

Expand Down
5 changes: 4 additions & 1 deletion R/output.R
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@
#' \code{\link[utils]{Stangle}})
#' @param text a character vector as an alternative way to provide the input
#' file
#' @param envir the environment in which the code chunks are to be evaluated
#' (can use \code{\link{new.env}()} to guarantee an empty new environment)
#' @return The compiled document is written into the output file, and the path
#' of the output file is returned, but if the \code{output} path is
#' \code{NULL}, the output is returned as a character vector.
Expand Down Expand Up @@ -90,7 +92,7 @@
#' ## or setwd(dirname(f)); knit(basename(f))
#'
#' purl(f) # extract R code only
knit = function(input, output = NULL, tangle = FALSE, text = NULL) {
knit = function(input, output = NULL, tangle = FALSE, text = NULL, envir = parent.frame()) {

in.file = !missing(input) && is.character(input) # is a file input
optk = opts_knit$get(); on.exit(opts_knit$set(optk), add = TRUE)
Expand Down Expand Up @@ -167,6 +169,7 @@ knit = function(input, output = NULL, tangle = FALSE, text = NULL) {

progress = opts_knit$get('progress')
if (in.file) message(ifelse(progress, '\n\n', ''), 'processing file: ', input)
.knitEnv$knit_global = envir # the envir to eval code
res = process_file(text, output)
cat(res, file = if (is.null(output)) '' else output)
dep_list$restore() # empty dependency list
Expand Down
6 changes: 3 additions & 3 deletions R/utils.R
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ comment_out = function(x, options) {
## assign string in comments to a global variable
comment_to_var = function(x, varname, pattern) {
if (str_detect(x, pattern)) {
assign(varname, str_replace(x, pattern, ''), envir = globalenv())
assign(varname, str_replace(x, pattern, ''), envir = knit_global())
return(TRUE)
}
FALSE
Expand Down Expand Up @@ -287,11 +287,11 @@ fix_options = function(options) {
## try eval an option (character) to its value
eval_opt = function(x) {
if (!is.character(x)) return(x)
eval(parse(text = x), envir = globalenv())
eval(parse(text = x), envir = knit_global())
}

## eval options as symbol/language objects
eval_lang = function(x, envir = globalenv()) {
eval_lang = function(x, envir = knit_global()) {
if (!is.symbol(x) && !is.language(x)) return(x)
eval(x, envir = envir)
}
Expand Down

0 comments on commit 09825ee

Please sign in to comment.