Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Export get_r_string #1526

Merged
merged 9 commits into from
Sep 24, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ export(extraction_operator_linter)
export(fixed_regex_linter)
export(function_argument_linter)
export(function_left_parentheses_linter)
export(get_r_string)
export(get_source_expressions)
export(ids_with_token)
export(ifelse_censor_linter)
Expand Down
7 changes: 5 additions & 2 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@

## New and improved features

* New `get_r_string()` helper to get the R-equivalent value of a string, especially useful for R-4-style raw strings.
Previously an internal `lintr` helper, now exported to facilitate writing custom linters (#1493, @MichaelChirico).

* `object_usage_linter()` improves lint metadata when detecting undefined infix operators, e.g. `%>%` or `:=` (#1497, @MichaelChirico)

# lintr 3.0.1
Expand All @@ -25,7 +28,7 @@

* `brace_linter()` allows opening curly braces on a new line when there is
a comment ending the preceding line (#1433 and #1434, @IndrajeetPatil).

* `seq_linter()` produces lint for `seq(...)`, since it also cannot properly
handle empty edge cases (#1468, @IndrajeetPatil).

Expand All @@ -48,7 +51,7 @@

* New `function_argument_linter()` to enforce that arguments with defaults appear last in function declarations,
see the [Tidyverse design guide](https://design.tidyverse.org/args-data-details.html) (#450, @AshesITR).

* New `allow_trailing` argument added to `assignment_linter()` to check when assignment operators are at the
end of a line, and the value is on the following line (#1491, @ashbaldry)

Expand Down
18 changes: 15 additions & 3 deletions R/utils.R
Original file line number Diff line number Diff line change
Expand Up @@ -210,9 +210,21 @@ release_bullets <- function() {
platform_independent_order <- function(x) order(tolower(gsub("_", "0", x, fixed = TRUE)))
platform_independent_sort <- function(x) x[platform_independent_order(x)]

# convert STR_CONST text() values into R strings. mainly to account for arbitrary
# character literals valid since R 4.0, e.g. R"------[ hello ]------".
# NB: this is also properly vectorized.
#' Extract text from `STR_CONST` nodes
#'
#' Convert `STR_CONST` `text()` values into R strings. This is useful to account for arbitrary
#' character literals valid since R 4.0, e.g. `R"------[hello]------"`, which is parsed in
#' R as `"hello"`. It is quite cumbersome to write XPaths allowing for strings like this,
#' so whenever your linter logic requires testing a `STR_CONST` node's value, use this
#' function.
#' NB: this is also properly vectorized on `s`, and accepts a variety of inputs. Empty inputs
#' will become `NA` outputs, which helps ensure that `length(get_r_string(s)) == length(s)`.
#'
#' @param s An input string or strings. If `s` is an `xml_node` or `xml_nodeset` and `xpath` is `NULL`,
#' extract its string value with [xml2::xml_text()]. If `s` is an `xml_node` or `xml_nodeset`
#' and `xpath` is specified, it is extracted with [xml2::xml_find_chr()].
#' @param xpath An XPath, passed on to [xml2::xml_find_chr()] after wrapping with `string()`.
#' @export
MichaelChirico marked this conversation as resolved.
Show resolved Hide resolved
get_r_string <- function(s, xpath = NULL) {
if (inherits(s, c("xml_node", "xml_nodeset"))) {
if (is.null(xpath)) {
Expand Down
1 change: 1 addition & 0 deletions _pkgdown.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ reference:
- expect_lint_free
- ids_with_token
- is_lint_level
- get_r_string
- use_lintr
- xml_nodes_to_lints

Expand Down
24 changes: 24 additions & 0 deletions man/get_r_string.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 12 additions & 0 deletions vignettes/creating_linters.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,18 @@ expect_lint("blah=1; blah=2",

It is always better to write too many tests rather than too few.

## Other utilities for writing custom linters

Besides `is_lint_level()`, `{lintr}` also exports some other helpers generally useful
for writing custom linters; these are used a lot in the internals of our own helpers,
and so they've been tested and demonstrated their utility already.

* `get_r_string()`: Whenever your linter needs to examine the value of a character
literal (e.g., whether an argument value is set to some string), use this to
extract the string exactly as R will see it. This is especially important to make
your logic robust to R-4-style raw strings like `R"-(hello)-"`, which is otherwise
difficult to express, for example as an XPath.

## Contributing to `{lintr}`

### More details about writing tests for new `{lintr}` linters
Expand Down