Skip to content

Commit

Permalink
fix #2126: check file and code chunk option when checking label d…
Browse files Browse the repository at this point in the history
…uplication (#2127)

Co-authored-by: Yihui Xie <[email protected]>
  • Loading branch information
cderv and yihui authored May 17, 2022
1 parent 925b9b3 commit ca398c2
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 9 deletions.
2 changes: 2 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

- The internal function `knitr:::wrap()` has been removed from this package. If you rely on this function, you will have to use the exported function `knitr::sew()` instead.

- Duplicate chunk label error will now be thrown with code chunks using `code` or `file` chunk options (thanks, @mine-cetinkaya-rundel, #2126).

# CHANGES IN knitr VERSION 1.39

## MAJOR CHANGES
Expand Down
27 changes: 19 additions & 8 deletions R/block.R
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,7 @@ call_block = function(block) {
if (inherits(params$ref.label, 'AsIs') && is.null(params$opts.label))
params$opts.label = ref.label
}
# if chunk option 'file' is provided, read the file(s) as the chunk body;
# otherwise if 'code' is provided, use it; if neither 'file' nor 'code' is
# provided, use the chunk body
params[["code"]] = if (is.null(code_file <- params[['file']])) {
params[["code"]] %n% unlist(knit_code$get(ref.label), use.names = FALSE)
} else {
in_input_dir(xfun::read_all(code_file))
}
params[['code']] = get_code(params, label, ref.label)

# opts.label = TRUE means inheriting chunk options from ref.label
if (isTRUE(params$opts.label)) params$opts.label = ref.label
Expand Down Expand Up @@ -125,6 +118,24 @@ call_block = function(block) {
block_exec(params)
}

# if chunk option 'file' is provided, read the file(s) as the chunk body;
# otherwise if 'code' is provided, use it; if neither 'file' nor 'code' is
# provided, use the chunk body
get_code = function(params, label, ref.label) {
if (is.null(code <- params[['code']]) && is.null(file <- params[['file']]))
return(unlist(knit_code$get(ref.label), use.names = FALSE))
if (!is.null(file)) code = in_input_dir(xfun::read_all(file))
set_code(label, code)
code
}

# replace code in knit_code but preserve attributes
set_code = function(label, code) {
res = knit_code$get(label)
attributes(code) = attributes(res)
knit_code$set(setNames(list(code), label))
}

# options that should affect cache when cache level = 1,2
cache1.opts = c('code', 'eval', 'cache', 'cache.path', 'cache.globals', 'message', 'warning', 'error')
# more options affecting cache level 2
Expand Down
3 changes: 2 additions & 1 deletion R/parser.R
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ parse_block = function(code, header, params.src, markdown_mode = out_format('mar
code = parts$code

label = params$label; .knitEnv$labels = c(.knitEnv$labels, label)
if (length(code)) {
if (length(code) || length(params$file) || length(params$code)) {
if (label %in% names(knit_code$get())) {
if (identical(getOption('knitr.duplicate.label'), 'allow')) {
params$label = label = unnamed_chunk(label)
Expand All @@ -114,6 +114,7 @@ parse_block = function(code, header, params.src, markdown_mode = out_format('mar
one_string(knit_code$get(label))
)
}
code = as.character(code)
knit_code$set(setNames(list(structure(code, chunk_opts = params)), label))
}

Expand Down
20 changes: 20 additions & 0 deletions tests/testit/test-parser.R
Original file line number Diff line number Diff line change
Expand Up @@ -95,3 +95,23 @@ assert(
)

knit_code$restore()

# duplication of labels

knit_code$restore(list(a = '1+1'))

assert(
!has_error(parse_block(NULL, '', 'label = "a"')),
has_error(parse_block('2+2', '', 'label = "a"')),
has_error(parse_block(NULL, '','label = "a", code = "2+2"')),
has_error(parse_block(NULL, '','label = "a", file = "dummy.R"'))
)
op = options(knitr.duplicate.label = 'allow')
assert(
!has_error(parse_block('2+2', '', 'label = "a"')),
!has_error(parse_block(NULL, '','label = "a", code = "2+2"')),
!has_error(parse_block(NULL, '','label = "a", file = "dummy.R"'))
)
options(op)

knit_code$restore()

0 comments on commit ca398c2

Please sign in to comment.