Skip to content

fix(#135): evaluate @examples extraction without inline-R side effects#136

Merged
VincentGuyader merged 3 commits into
mainfrom
fix-135-inline-r-att-from-examples
May 2, 2026
Merged

fix(#135): evaluate @examples extraction without inline-R side effects#136
VincentGuyader merged 3 commits into
mainfrom
fix-135-inline-r-att-from-examples

Conversation

@VincentGuyader
Copy link
Copy Markdown
Member

Closes #135.

Problem

att_amend_desc() (via att_from_examples()) chokes on roxygen2 markdown that contains inline R referencing a package-local function, e.g.

#' @param x `r helper("x")`

Result is a cascade per affected tag:

✖ @param failed to evaluate inline markdown code.
Caused by error in `helper()`: could not find function "helper"

The doc finishes writing, but every inline-R @param is silently skipped — output .Rd ends up wrong on a cold run.

Root cause

att_from_examples() delegates example extraction to roxygen2::parse_file(). Inside roxygen2, parse_tags() evaluates inline R using roxy_meta_get("env") %||% baseenv() — and outside a full roxygenise() call no env is set, so the lookup falls back to baseenv(). Any helper defined in the package being processed is unresolvable from baseenv().

Passing env= to parse_file() does not fix it: parse_file() only sets the env on each block via block_set_env(), but inline R evaluation reads roxy_meta_get("env") before that — the API surface roxygen2 exposes simply isn't enough to redirect inline-R lookup from outside.

Fix

Replace the parse_file() + block_get_tag_value(tag = "examples") round-trip with a focused regex extractor that pulls @examples / @examplesIf blocks straight from the source. Example detection no longer touches roxygen2's tokenizer at all, so inline R inside unrelated tags (@param, @description, …) is left strictly alone.

Side benefits:

  • The two now-unused imports roxygen2::parse_file and roxygen2::block_get_tag_value disappear from NAMESPACE (auto-regen).
  • One less coupling to roxygen2 internals.

Coverage

Added tests/testthat/test-att_from_namespace.R::"inline R in @param resolves package-local functions (#135)" — fails on main, green with this fix.

Test plan

  • Test red on baseline (could not find function "helper")
  • Test green with fix
  • devtools::test() full suite: [ FAIL 0 | WARN 0 | SKIP 1 | PASS 392 ] (modulo three test-renv_create.R pre-existing fails fixed in a separate PR — independent of this work)
  • R CMD check --as-cran: 0 ERROR, 2 WARNING (vignettes/inst/doc, unrelated build artefact), 1 NOTE (CRAN incoming for version bump)
  • Manual reprex of Chokes on inline R functions contained in roxygen2 code #135: .Rd now contains the evaluated inline-R value, no stderr noise

Version

Bumps to 1.0.1 with a NEWS entry citing #135.

`att_from_examples()` delegated example extraction to
`roxygen2::parse_file()`, which unconditionally evaluates inline R
embedded in roxygen markdown tags such as ``@param x `r helper("x")` ``.
roxygen2 evaluates that R in the env returned by `roxy_meta_get("env")`,
which falls back to `baseenv()` outside a full `roxygenise()` context;
any package-local helper is therefore unresolvable, producing a cascade
of "could not find function" messages on every affected tag.

Replace the parse_file call with a focused regex extractor that pulls
`@examples` / `@examplesIf` blocks straight from the source. Example
detection no longer touches roxygen2's tokenizer, so inline R inside
unrelated tags is left strictly alone.

NAMESPACE auto-regen drops the now-unused `roxygen2::parse_file` and
`roxygen2::block_get_tag_value` imports.

Bumps version to 1.0.1 with a NEWS entry.
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes att_from_examples() / att_amend_desc() failures caused by roxygen2 inline-R evaluation side effects during @examples extraction (issue #135), by avoiding roxygen2::parse_file() and extracting example blocks directly from source.

Changes:

  • Replace roxygen2::parse_file()-based example extraction with a regex-based @examples / @examplesIf block extractor.
  • Add a regression test ensuring inline R in @param can call a package-local helper without causing extraction failures.
  • Bump version to 1.0.1 and update NEWS + NAMESPACE imports accordingly.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
R/add_from_examples.R Switches example extraction away from roxygen2 parsing to avoid inline-R evaluation side effects.
tests/testthat/test-att_from_namespace.R Adds regression coverage for issue #135 via a dummy package scenario.
NEWS.md Documents the fix in the 1.0.1 changelog.
NAMESPACE Removes now-unused roxygen2 imports.
DESCRIPTION Bumps package version to 1.0.1.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread R/add_from_examples.R Outdated
Comment thread R/add_from_examples.R Outdated
Comment thread NEWS.md Outdated
Address Copilot review on PR #136:

- `extract_examples_lines()` was hard-coding `encoding = "UTF-8"` and
  bare-calling `readLines()`. The sibling `att_from_rscript()` uses
  `getOption("encoding")` and a `tryCatch()` that warns + returns
  `character(0)` on read failure. Mirror that pattern so a single
  unreadable source file no longer aborts the whole `att_from_examples()`
  scan, and so non-UTF8 locales (Windows) are respected by default.
- Thread an `encoding` argument through `att_from_examples()` to expose
  the same knob users already have on `att_from_rscript()`.
- NEWS: clarify that roxygen2's inline-R fallback env is `baseenv()` —
  base R is reachable, only package-local helpers are not.
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes a failure mode in att_from_examples()/att_amend_desc() where roxygen2 inline-R evaluation in unrelated tags (e.g. @param) can produce errors and lead to incorrect .Rd output when processed outside a full roxygenise() context.

Changes:

  • Replaced roxygen2::parse_file()-based example extraction with a source-scanning extractor to avoid inline-R evaluation side effects.
  • Added an encoding parameter to att_from_examples() (defaulting to getOption("encoding")) and documented it.
  • Added a regression test covering inline-R in @param resolving package-local helpers; bumped version and added NEWS entry.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
R/add_from_examples.R Switches example extraction away from roxygen2 parsing; adds encoding arg and a new internal extractor.
man/att_from_examples.Rd Documents the new encoding parameter in the public API.
tests/testthat/test-att_from_namespace.R Adds regression test for issue #135 using a modified dummy package.
NEWS.md Adds 1.0.1 release notes describing the fix for #135.
NAMESPACE Removes now-unused roxygen2 imports.
DESCRIPTION Bumps package version to 1.0.1.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread tests/testthat/test-att_from_namespace.R Outdated
Comment thread R/add_from_examples.R Outdated
Comment thread R/add_from_examples.R
Address Copilot's second review on PR #136:

- `extract_examples_lines()` was including the payload of `@examplesIf`
  (a guard condition like `requireNamespace("foo")`) in the extracted
  example text, so any package mentioned only in the guard was falsely
  detected as a dependency. Split the tag detection so `@examplesIf`
  enters example mode but discards the condition; only the body lines
  that follow are captured.
- Add a focused test asserting the @examplesIf path: the body's deps
  must be detected, the guard's must not.
- The #135 regression test appended `Roxygen: list(markdown = TRUE)` to
  the dummypackage DESCRIPTION via `c(readLines(...), new_line)`, which
  preserved the file's trailing blank line and inserted the new field
  after a blank record separator. DCF parsers may then ignore it. Trim
  trailing empty lines first.
@VincentGuyader VincentGuyader merged commit 7f6fb66 into main May 2, 2026
11 checks passed
@VincentGuyader VincentGuyader deleted the fix-135-inline-r-att-from-examples branch May 2, 2026 20:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Chokes on inline R functions contained in roxygen2 code

2 participants