-
Notifications
You must be signed in to change notification settings - Fork 187
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
0aefa5f
commit e969d64
Showing
11 changed files
with
143 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
#' Require usage of rep_len(x, n) over rep(x, length.out = n) | ||
#' | ||
#' `rep(x, length.out = n)` calls `rep_len(x, n)` "under the hood". The latter | ||
#' is thus more direct and equally readable. | ||
#' | ||
#' @examples | ||
#' # will produce lints | ||
#' lint( | ||
#' text = "rep(1:3, length.out = 10)", | ||
#' linters = rep_len_linter() | ||
#' ) | ||
#' | ||
#' # okay | ||
#' lint( | ||
#' text = "rep_len(1:3, 10)", | ||
#' linters = rep_len_linter() | ||
#' ) | ||
#' | ||
#' lint( | ||
#' text = "rep(1:3, each = 2L, length.out = 10L)", | ||
#' linters = rep_len_linter() | ||
#' ) | ||
#' | ||
#' @evalRd rd_tags("rep_len_linter") | ||
#' @seealso [linters] for a complete list of linters available in lintr. | ||
#' @export | ||
rep_len_linter <- make_linter_from_xpath( | ||
# count(expr) is for cases using positional matching; see ?rep. | ||
xpath = " | ||
//SYMBOL_FUNCTION_CALL[text() = 'rep'] | ||
/parent::expr | ||
/parent::expr[ | ||
( | ||
SYMBOL_SUB[text() = 'length.out'] | ||
or (not(SYMBOL_SUB) and count(expr) = 4) | ||
) | ||
and not(SYMBOL_SUB[text() = 'each'] or count(expr) = 5) | ||
] | ||
", | ||
lint_message = "Use rep_len(x, n) instead of rep(x, length.out = n)." | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
test_that("rep_len_linter skips allowed usages", { | ||
linter <- rep_len_linter() | ||
|
||
# only catch length.out usages | ||
expect_lint("rep(x, y)", NULL, linter) | ||
expect_lint("rep(1:10, 2)", NULL, linter) | ||
expect_lint("rep(1:10, 10:1)", NULL, linter) | ||
|
||
# usage of each is not compatible with rep_len; see ?rep. | ||
expect_lint("rep(x, each = 4, length.out = 50)", NULL, linter) | ||
# each is implicitly the 4th positional argument. a very strange usage | ||
# (because length.out is ignored), but doesn't hurt to catch it | ||
expect_lint("rep(a, b, length.out = c, d)", NULL, linter) | ||
# ditto for implicit length.out= | ||
expect_lint("rep(a, b, c, d)", NULL, linter) | ||
}) | ||
|
||
test_that("rep_len_linter blocks simple disallowed usages", { | ||
linter <- rep_len_linter() | ||
lint_msg <- rex::rex("Use rep_len(x, n) instead of rep(x, length.out = n).") | ||
|
||
# only catch length.out usages | ||
expect_lint("rep(x, length.out = 4L)", lint_msg, linter) | ||
|
||
# implicit times= argument; length.out has priority over times= (see ?rep), | ||
# so we still lint since it's as if times= is not supplied. | ||
# (notice here that the base behavior is odd -- one might expect output like | ||
# head(rep(1:10, 10:1), 50), but instead we get rep(1:10, length.out = 50)) | ||
expect_lint("rep(1:10, 10:1, length.out = 50)", lint_msg, linter) | ||
|
||
# ditto for explicit times= argument | ||
expect_lint("rep(1:10, times = 10:1, length.out = 50)", lint_msg, linter) | ||
|
||
# implicit usage in third argument | ||
expect_lint("rep(1:10, 10:1, 50)", lint_msg, linter) | ||
}) | ||
|
||
test_that("vectorized lints work", { | ||
lint_msg <- rex::rex("Use rep_len(x, n) instead of rep(x, length.out = n).") | ||
|
||
expect_lint( | ||
trim_some("{ | ||
rep(x, y) | ||
rep(1:10, length.out = 50) | ||
rep(x, each = 4, length.out = 50) | ||
rep(x, length.out = 50) | ||
}"), | ||
list( | ||
list(lint_msg, line_number = 3L), | ||
list(lint_msg, line_number = 5L) | ||
), | ||
rep_len_linter() | ||
) | ||
}) |