Skip to content

Commit 0e848d9

Browse files
committed
Refactor code
1 parent 7a1be89 commit 0e848d9

20 files changed

+1453
-155
lines changed

DESCRIPTION

+4-2
Original file line numberDiff line numberDiff line change
@@ -14,24 +14,26 @@ BugReports: https://github.com/cgoo4/usedthese/issues
1414
Depends:
1515
R (>= 4.1)
1616
Imports:
17+
cli,
1718
conflicted (>= 1.2.0),
1819
dplyr (>= 1.1.0),
1920
highr,
21+
httr,
2022
kableExtra,
2123
knitr,
24+
lifecycle,
2225
purrr,
2326
readr,
2427
rlang,
28+
rvest,
2529
stringr,
2630
tibble,
2731
tidyr (>= 1.3.0),
2832
tidyselect,
2933
withr
3034
Suggests:
3135
covr,
32-
httr,
3336
rmarkdown,
34-
rvest,
3537
spelling,
3638
testthat (>= 3.0.0),
3739
tsibble,

NAMESPACE

+46-1
Original file line numberDiff line numberDiff line change
@@ -1 +1,46 @@
1-
exportPattern("^[[:alpha:]]+")
1+
# Generated by roxygen2: do not edit by hand
2+
3+
export(used_here)
4+
export(used_there)
5+
import(dplyr)
6+
import(rlang)
7+
importFrom(cli,cli_abort)
8+
importFrom(conflicted,conflict_scout)
9+
importFrom(highr,hi_latex)
10+
importFrom(httr,parse_url)
11+
importFrom(kableExtra,kable_styling)
12+
importFrom(knitr,current_input)
13+
importFrom(knitr,kable)
14+
importFrom(knitr,purl)
15+
importFrom(lifecycle,deprecated)
16+
importFrom(purrr,list_c)
17+
importFrom(purrr,list_flatten)
18+
importFrom(purrr,list_rbind)
19+
importFrom(purrr,map)
20+
importFrom(purrr,walk)
21+
importFrom(readr,read_lines)
22+
importFrom(rvest,html_attr)
23+
importFrom(rvest,html_element)
24+
importFrom(rvest,html_elements)
25+
importFrom(rvest,html_table)
26+
importFrom(rvest,read_html)
27+
importFrom(stringr,str_c)
28+
importFrom(stringr,str_ends)
29+
importFrom(stringr,str_extract_all)
30+
importFrom(stringr,str_flatten_comma)
31+
importFrom(stringr,str_remove)
32+
importFrom(stringr,str_replace)
33+
importFrom(tibble,as_tibble)
34+
importFrom(tibble,enframe)
35+
importFrom(tibble,tibble)
36+
importFrom(tidyr,drop_na)
37+
importFrom(tidyr,extract)
38+
importFrom(tidyr,fill)
39+
importFrom(tidyr,pivot_longer)
40+
importFrom(tidyr,separate_longer_delim)
41+
importFrom(tidyr,separate_wider_delim)
42+
importFrom(tidyr,separate_wider_regex)
43+
importFrom(tidyr,unnest)
44+
importFrom(tidyselect,everything)
45+
importFrom(utils,tail)
46+
importFrom(withr,defer)

NEWS.md

+20-13
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,42 @@
11
# usedthese (development version)
22

3+
* Refactored code.
4+
* Improved error messages using `cli_abort`.
5+
* Centralised roxygen `@importFrom` tags.
6+
* Used mocking to test without the need for an internet connection.
7+
* Added test for non-scalar `num_links`.
8+
* Updated citation.
9+
310
# usedthese 0.4.0
411

5-
* Spring clean
6-
* Default branch master to main
12+
* Spring clean.
13+
* Default branch master to main.
714

815
# usedthese 0.3.3
916

10-
* Fixed occasional `used_here()` warning
11-
* Documentation updates
17+
* Fixed occasional `used_here()` warning.
18+
* Documentation updates.
1219

1320
# usedthese 0.3.2
1421

15-
* `used_there()` fails gracefully if Internet resource unavailable
22+
* `used_there()` fails gracefully if Internet resource unavailable.
1623

1724
# usedthese 0.3.1
1825

19-
* Patch update to fix test error
20-
* Default `used_there()` `num_links` to 30
26+
* Patch update to fix test error.
27+
* Default `used_there()` `num_links` to 30.
2128

2229
# usedthese 0.3.0
2330

24-
* Respects `include.only` and `exclude` arguments specified in `library()`
25-
* Small performance improvement with dplyr 1.1 and tidyr 1.3
26-
* Remove suggests for meta-packages tidyverse and fpp3
31+
* Respects `include.only` and `exclude` arguments specified in `library()`.
32+
* Small performance improvement with dplyr 1.1 and tidyr 1.3.
33+
* Remove suggests for meta-packages tidyverse and fpp3.
2734

2835
# usedthese 0.2.0
2936

30-
* Support use of the conflicted package
31-
* Include functions using the double-colon operator
32-
* Resolve cases of a function counted against two packages
37+
* Support use of the conflicted package.
38+
* Include functions using the double-colon operator.
39+
* Resolve cases of a function counted against two packages.
3340

3441
# usedthese 0.1.0
3542

R/globals.R

+5-4
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,18 @@ utils::globalVariables(
33
"value",
44
"name",
55
"base",
6-
"pckg_origin",
6+
"pkg_origin",
77
"n",
8-
"pckg",
8+
"pkg",
99
"func",
1010
"total",
1111
"count",
1212
"desc",
1313
"Function",
1414
"Package",
1515
"packfun",
16-
"pckg_preferred",
17-
"pckgx"
16+
"pkg_loaded",
17+
"pkg_preferred",
18+
"pkgx"
1819
)
1920
)

R/used_here.R

+131-78
Original file line numberDiff line numberDiff line change
@@ -25,96 +25,149 @@
2525
#' # an html table with a CSS class "usedthese"
2626
#' usedthese::used_here("mean(c(1, 2, 3))\nsum(c(1, 2, 3))")
2727
#'
28-
used_here <- \(fil = knitr::current_input()) {
28+
used_here <- \(fil = current_input()) {
2929
if (is.null(fil)) {
30-
rlang::abort(
31-
"If you are knitting the current document, i.e. you clicked the Render button, then leave fil unspecified. If you are running the code chunks, then ensure you library the packages first in a fresh R session and specify the saved filename quoted.",
32-
fil = fil
33-
)
30+
cli_abort(c(
31+
"`fil` must be either `current_input()` or a saved filename",
32+
"i" = "When knitting a qmd/Rmd, `fil` defaults to `current_input()`.",
33+
"i" = "When running a code chunk, quote a saved filename.",
34+
"x" = "You specified fil = {fil}."
35+
))
3436
}
3537

3638
old <- options(knitr.duplicate.label = "allow")
37-
withr::defer(options(old))
39+
defer(options(old))
3840

39-
if (stringr::str_ends(fil, "Rmd|qmd|rmarkdown")) {
40-
purrr::walk(fil, knitr::purl, quiet = TRUE, documentation = 0)
41+
if (str_ends(fil, "Rmd|qmd|rmarkdown")) {
42+
walk(fil, purl, quiet = TRUE, documentation = 0)
43+
fil <- str_replace(fil, "Rmd|qmd|rmarkdown", "R")
44+
}
45+
46+
pkg_loaded <- .packages() |> set_names()
47+
funs_origin <- get_loaded_pkg_imports(pkg_loaded[pkg_loaded != "usedthese"])
48+
funs_scouted <- conflict_scout() |> unlist() |> bind_rows()
4149

42-
fil <- stringr::str_replace(fil, "Rmd|qmd|rmarkdown", "R")
50+
if (nrow(funs_scouted) > 0) {
51+
funs_scouted <- summarise_funs_scouted(funs_scouted)
52+
} else {
53+
funs_scouted <- tibble(pkg_preferred = "zzz", func = "zzz")
4354
}
4455

45-
pckg_loaded <- .packages() |>
46-
rlang::set_names()
56+
funs_augmented <- pkg_loaded |>
57+
get_funs_loaded() |>
58+
augment_funs_loaded(funs_origin, funs_scouted)
4759

48-
funs_loaded <- pckg_loaded |>
49-
purrr::map(\(x) base::ls(stringr::str_c("package:", x))) |>
50-
tibble::enframe("pckg_loaded", "func") |>
51-
tidyr::unnest(func)
60+
fil |>
61+
extract_highlighted_funs() |>
62+
summarise_funs_used(funs_augmented) |>
63+
print_with_class()
64+
}
5265

53-
get_mode <- \(x) {
54-
ux <- unique(x)
55-
ux[which.max(tabulate(match(x, ux)))]
56-
}
5766

58-
funs_origin <- pckg_loaded |>
59-
purrr::map(getNamespaceImports) |>
60-
purrr::list_flatten() |>
61-
tibble::enframe() |>
62-
dplyr::filter(value != "TRUE") |>
63-
tidyr::unnest(value) |>
64-
tidyr::separate_wider_delim(name, "_", names = c("pckg_loaded", "pckg_origin")) |>
65-
dplyr::rename(func = value) |>
66-
dplyr::mutate(pckg_origin = get_mode(pckg_origin), .by = func) |>
67-
dplyr::distinct()
68-
69-
funs_scouted <- conflicted::conflict_scout() |>
70-
unlist() |>
71-
dplyr::bind_rows()
7267

73-
if (nrow(funs_scouted) > 0) {
74-
funs_scouted <- funs_scouted |>
75-
tidyr::pivot_longer(tidyselect::everything(), names_to = "func") |>
76-
dplyr::mutate(func = stringr::str_remove(func, "\\d$")) |>
77-
dplyr::summarise(pckg_preferred = stringr::str_flatten_comma(value, na.rm = TRUE), .by = func)
78-
} else {
79-
funs_scouted <- tibble::tibble(pckg_preferred = "zzz", func = "zzz")
80-
}
68+
#' Get loaded functions
69+
#'
70+
#' @rdname used_here
71+
#' @usage NULL
72+
get_funs_loaded <- \(x) {
73+
map(x, \(x) ls(str_c("package:", x))) |>
74+
enframe("pkg_loaded", "func") |>
75+
unnest(func)
76+
}
8177

82-
funs_augmented <- funs_loaded |>
83-
dplyr::left_join(funs_origin, dplyr::join_by(pckg_loaded, func)) |>
84-
dplyr::left_join(funs_scouted, dplyr::join_by(func)) |>
85-
dplyr::group_by(func) |>
86-
tidyr::fill(pckg_origin, .direction = "updown") |>
87-
dplyr::mutate(
88-
pckg_loaded = dplyr::coalesce(pckg_origin, pckg_loaded),
89-
pckg_loaded = dplyr::coalesce(pckg_preferred, pckg_loaded)
90-
) |>
91-
dplyr::select(pckgx = pckg_loaded, func) |>
92-
dplyr::arrange(func, pckgx) |>
93-
dplyr::distinct(func, .keep_all = TRUE)
94-
95-
funs_coded <- fil |>
96-
readr::read_lines() |>
97-
highr::hi_latex(fallback = TRUE) |>
98-
stringr::str_extract_all("([a-zA-Z_]+::)?\\\\hlkwd\\{([^\\{\\}]*(?=\\}))") |>
99-
purrr::list_c() |>
100-
tibble::as_tibble() |>
101-
tidyr::separate_wider_regex(value, c(pckg = ".*?", "\\\\hlkwd\\{", func = ".*")) |>
102-
dplyr::mutate(pckg = stringr::str_remove(pckg, "::") |> dplyr::na_if(""))
103-
104-
funs_used <-
105-
funs_coded |>
106-
dplyr::left_join(funs_augmented, dplyr::join_by(func)) |>
107-
dplyr::mutate(pckg = dplyr::coalesce(pckg, pckgx)) |>
108-
dplyr::count(pckg, func) |>
109-
dplyr::mutate(func = stringr::str_c(func, "[", n, "]")) |>
110-
dplyr::summarise(func = stringr::str_c(func, collapse = ", "), .by = pckg) |>
111-
tidyr::drop_na()
112-
113-
funs_used |>
114-
knitr::kable(
115-
format = "html",
116-
table.attr = "class = 'usedthese'",
117-
col.names = c("Package", "Function")
78+
#' Get mode
79+
#'
80+
#' @rdname used_here
81+
#' @usage NULL
82+
get_mode <- \(x) {
83+
ux <- unique(x)
84+
ux[which.max(tabulate(match(x, ux)))]
85+
}
86+
87+
#' Get the Imports of loaded packages
88+
#'
89+
#' @rdname used_here
90+
#' @usage NULL
91+
get_loaded_pkg_imports <- \(x){
92+
map(x, getNamespaceImports) |>
93+
list_flatten() |>
94+
enframe() |>
95+
filter(value != "TRUE") |>
96+
unnest(value) |>
97+
separate_wider_delim(name, "_", names = c("pkg_loaded", "pkg_origin")) |>
98+
rename(func = value) |>
99+
mutate(pkg_origin = get_mode(pkg_origin), .by = func) |>
100+
distinct()
101+
}
102+
103+
#' Summarise functions scouted
104+
#'
105+
#' @rdname used_here
106+
#' @usage NULL
107+
summarise_funs_scouted <- \(x){
108+
pivot_longer(x, everything(), names_to = "func") |>
109+
mutate(func = str_remove(func, "\\d$")) |>
110+
summarise(
111+
pkg_preferred = str_flatten_comma(value, na.rm = TRUE),
112+
.by = func
113+
)
114+
}
115+
116+
#' Augment functions loaded
117+
#'
118+
#' @rdname used_here
119+
#' @usage NULL
120+
augment_funs_loaded <- \(x, y, z){
121+
left_join(x, y, join_by(pkg_loaded, func)) |>
122+
left_join(z, join_by(func)) |>
123+
group_by(func) |>
124+
fill(pkg_origin, .direction = "updown") |>
125+
mutate(
126+
pkg_loaded = coalesce(pkg_origin, pkg_loaded),
127+
pkg_loaded = coalesce(pkg_preferred, pkg_loaded)
118128
) |>
119-
kableExtra::kable_styling("striped")
129+
select(pkgx = pkg_loaded, func) |>
130+
arrange(func, pkgx) |>
131+
distinct(func, .keep_all = TRUE)
132+
}
133+
134+
#' Extract code-highlighted functions
135+
#'
136+
#' @rdname used_here
137+
#' @usage NULL
138+
extract_highlighted_funs <- \(x){
139+
read_lines(x) |>
140+
hi_latex(fallback = TRUE) |>
141+
str_extract_all("([a-zA-Z_]+::)?\\\\hlkwd\\{([^\\{\\}]*(?=\\}))") |>
142+
list_c() |>
143+
as_tibble() |>
144+
separate_wider_regex(value, c(pkg = ".*?", "\\\\hlkwd\\{", func = ".*")) |>
145+
mutate(pkg = str_remove(pkg, "::") |> na_if(""))
146+
}
147+
148+
#' Summarise functions used
149+
#'
150+
#' @rdname used_here
151+
#' @usage NULL
152+
summarise_funs_used <- \(x, y){
153+
left_join(x, y, join_by(func)) |>
154+
mutate(pkg = coalesce(pkg, pkgx)) |>
155+
count(pkg, func) |>
156+
mutate(func = str_c(func, "[", n, "]")) |>
157+
summarise(func = str_c(func, collapse = ", "), .by = pkg) |>
158+
drop_na()
159+
}
160+
161+
#' Print summary table with class
162+
#'
163+
#' @rdname used_here
164+
#' @usage NULL
165+
print_with_class <- \(x){
166+
kable(
167+
x,
168+
format = "html",
169+
table.attr = "class = 'usedthese'", # essential for used_here()
170+
col.names = c("Package", "Function")
171+
) |>
172+
kable_styling("striped")
120173
}

0 commit comments

Comments
 (0)