Skip to content

Commit 2cc3260

Browse files
Merge pull request #68 from wjakethompson/air
Add air formatting
2 parents 5c90149 + 69d64a1 commit 2cc3260

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+2894
-1412
lines changed

.Rbuildignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,5 @@
1414
^CRAN-SUBMISSION$
1515
^revdep$
1616
^CITATION\.cff$
17+
^[.]?air[.]toml$
18+
^\.vscode$
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# Workflow derived from https://github.com/posit-dev/setup-air/tree/main/examples
2+
3+
on:
4+
# Using `pull_request_target` over `pull_request` for elevated `GITHUB_TOKEN`
5+
# privileges, otherwise we can't set `pull-requests: write` when the pull
6+
# request comes from a fork, which is our main use case (external contributors).
7+
#
8+
# `pull_request_target` runs in the context of the target branch (`main`, usually),
9+
# rather than in the context of the pull request like `pull_request` does. Due
10+
# to this, we must explicitly checkout `ref: ${{ github.event.pull_request.head.sha }}`.
11+
# This is typically frowned upon by GitHub, as it exposes you to potentially running
12+
# untrusted code in a context where you have elevated privileges, but they explicitly
13+
# call out the use case of reformatting and committing back / commenting on the PR
14+
# as a situation that should be safe (because we aren't actually running the untrusted
15+
# code, we are just treating it as passive data).
16+
# https://securitylab.github.com/resources/github-actions-preventing-pwn-requests/
17+
pull_request_target:
18+
19+
name: format-suggest.yaml
20+
21+
jobs:
22+
format-suggest:
23+
name: format-suggest
24+
runs-on: ubuntu-latest
25+
26+
permissions:
27+
# Required to push suggestion comments to the PR
28+
pull-requests: write
29+
30+
steps:
31+
- uses: actions/checkout@v4
32+
with:
33+
ref: ${{ github.event.pull_request.head.sha }}
34+
35+
- name: Install
36+
uses: posit-dev/setup-air@v1
37+
38+
- name: Format
39+
run: air format .
40+
41+
- name: Suggest
42+
uses: reviewdog/action-suggester@v1
43+
with:
44+
level: error
45+
fail_level: error
46+
tool_name: air

.lintr

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ linters: linters_with_defaults(
33
return_linter = NULL
44
)
55
exclusions: list(
6+
"data-raw/test-data.R" = list(
7+
object_usage_linter = Inf
8+
),
69
"R/stanmodels.R",
710
"R/import-standalone-obj-type.R",
811
"R/import-standalone-types-check.R",

.vscode/extensions.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"recommendations": [
3+
"Posit.air-vscode"
4+
]
5+
}

.vscode/settings.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"[r]": {
3+
"editor.formatOnSave": true,
4+
"editor.defaultFormatter": "Posit.air-vscode"
5+
},
6+
"[quarto]": {
7+
"editor.formatOnSave": true,
8+
"editor.defaultFormatter": "quarto.quarto"
9+
}
10+
}

NAMESPACE

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ export(measr_dcm)
4444
export(measr_examples)
4545
export(measr_extract)
4646
export(measrdcm)
47+
export(ncrum)
48+
export(nida)
49+
export(nido)
4750
export(optim)
4851
export(prior)
4952
export(reliability)
@@ -76,6 +79,9 @@ importFrom(dcmstan,get_parameters)
7679
importFrom(dcmstan,hdcm)
7780
importFrom(dcmstan,independent)
7881
importFrom(dcmstan,lcdm)
82+
importFrom(dcmstan,ncrum)
83+
importFrom(dcmstan,nida)
84+
importFrom(dcmstan,nido)
7985
importFrom(dcmstan,prior)
8086
importFrom(dcmstan,stan_data)
8187
importFrom(dcmstan,unconstrained)

R/add-model-evaluation.R

Lines changed: 40 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -122,12 +122,20 @@ NULL
122122

123123
#' @export
124124
#' @rdname model_evaluation
125-
add_criterion <- function(x, criterion = c("loo", "waic", "aic", "bic"),
126-
overwrite = FALSE, save = TRUE, ..., r_eff = NA) {
125+
add_criterion <- function(
126+
x,
127+
criterion = c("loo", "waic", "aic", "bic"),
128+
overwrite = FALSE,
129+
save = TRUE,
130+
...,
131+
r_eff = NA
132+
) {
127133
rdcmchecks::check_S7(x, class = "measrfit")
128-
criterion <- rlang::arg_match(criterion,
129-
values = c("loo", "waic", "aic", "bic"),
130-
multiple = TRUE)
134+
criterion <- rlang::arg_match(
135+
criterion,
136+
values = c("loo", "waic", "aic", "bic"),
137+
multiple = TRUE
138+
)
131139
check_bool(overwrite)
132140
check_bool(save)
133141

@@ -181,8 +189,14 @@ add_reliability <- function(x, overwrite = FALSE, save = TRUE, ...) {
181189

182190
#' @export
183191
#' @rdname model_evaluation
184-
add_fit <- function(x, method = c("m2", "ppmc"), overwrite = FALSE,
185-
save = TRUE, ..., ci = 0.9) {
192+
add_fit <- function(
193+
x,
194+
method = c("m2", "ppmc"),
195+
overwrite = FALSE,
196+
save = TRUE,
197+
...,
198+
ci = 0.9
199+
) {
186200
rdcmchecks::check_S7(x, class = "measrfit")
187201
method <- rlang::arg_match(method, values = c("m2", "ppmc"), multiple = TRUE)
188202
check_bool(overwrite)
@@ -196,21 +210,20 @@ add_fit <- function(x, method = c("m2", "ppmc"), overwrite = FALSE,
196210
}
197211

198212
# m2 -------------------------------------------------------------------------
199-
if ("m2" %in% method &&
200-
(rlang::is_empty(x@fit$m2) || overwrite)) {
213+
if ("m2" %in% method && (rlang::is_empty(x@fit$m2) || overwrite)) {
201214
x@fit$m2 <- fit_m2(x, ci = ci, force = TRUE)
202215
}
203216

204217
# ppmc -----------------------------------------------------------------------
205218
if ("ppmc" %in% method) {
206219
ppmc_list <- fit_ppmc(x, ..., force = overwrite)
207220
x@fit <- utils::modifyList(x@fit, ppmc_list)
208-
x@fit <- lapply(names(x@fit),
209-
\(nm) {
210-
if (!nm %in% names(ppmc_list)) return(x@fit[[nm]])
211-
dplyr::select(x@fit[[nm]],
212-
dplyr::all_of(names(ppmc_list[[nm]])))
213-
}) |>
221+
x@fit <- lapply(names(x@fit), \(nm) {
222+
if (!nm %in% names(ppmc_list)) {
223+
return(x@fit[[nm]])
224+
}
225+
dplyr::select(x@fit[[nm]], dplyr::all_of(names(ppmc_list[[nm]])))
226+
}) |>
214227
rlang::set_names(nm = names(x@fit))
215228
}
216229

@@ -223,8 +236,12 @@ add_fit <- function(x, method = c("m2", "ppmc"), overwrite = FALSE,
223236

224237
#' @export
225238
#' @rdname model_evaluation
226-
add_respondent_estimates <- function(x, probs = c(0.025, 0.975),
227-
overwrite = FALSE, save = TRUE) {
239+
add_respondent_estimates <- function(
240+
x,
241+
probs = c(0.025, 0.975),
242+
overwrite = FALSE,
243+
save = TRUE
244+
) {
228245
rdcmchecks::check_S7(x, class = "measrfit")
229246
check_bool(overwrite)
230247
check_bool(save)
@@ -234,8 +251,12 @@ add_respondent_estimates <- function(x, probs = c(0.025, 0.975),
234251
}
235252

236253
if (rlang::is_empty(x@respondent_estimates) || overwrite) {
237-
x@respondent_estimates <- score(x, summary = TRUE, probs = probs,
238-
force = TRUE)
254+
x@respondent_estimates <- score(
255+
x,
256+
summary = TRUE,
257+
probs = probs,
258+
force = TRUE
259+
)
239260
}
240261

241262
# re-save model object (if applicable) ---------------------------------------

R/cdi.R

Lines changed: 70 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,10 @@ cdi <- function(model, weight_prevalence = TRUE) {
6666
cols = "name",
6767
patterns = c("pi\\[", item = "[0-9]*", ",", class = "[0-9]*", "\\]")
6868
) |>
69-
dplyr::mutate(item = as.integer(.data$item),
70-
class = as.integer(.data$class))
69+
dplyr::mutate(
70+
item = as.integer(.data$item),
71+
class = as.integer(.data$class)
72+
)
7173

7274
hamming <- profile_hamming(
7375
dplyr::select(measr_extract(model, "classes"), -"class")
@@ -76,29 +78,42 @@ cdi <- function(model, weight_prevalence = TRUE) {
7678
dplyr::select(-c("profile_1", "profile_2", "hamming")) |>
7779
colnames()
7880

79-
item_discrim <- tidyr::crossing(item = unique(pi_matrix$item),
80-
profile_1 = unique(pi_matrix$class),
81-
profile_2 = unique(pi_matrix$class)) |>
82-
dplyr::left_join(pi_matrix, by = c("item", "profile_1" = "class"),
83-
relationship = "many-to-one") |>
81+
item_discrim <- tidyr::crossing(
82+
item = unique(pi_matrix$item),
83+
profile_1 = unique(pi_matrix$class),
84+
profile_2 = unique(pi_matrix$class)
85+
) |>
86+
dplyr::left_join(
87+
pi_matrix,
88+
by = c("item", "profile_1" = "class"),
89+
relationship = "many-to-one"
90+
) |>
8491
dplyr::rename("prob_1" = "value") |>
85-
dplyr::left_join(pi_matrix, by = c("item", "profile_2" = "class"),
86-
relationship = "many-to-one") |>
92+
dplyr::left_join(
93+
pi_matrix,
94+
by = c("item", "profile_2" = "class"),
95+
relationship = "many-to-one"
96+
) |>
8797
dplyr::rename("prob_2" = "value") |>
88-
dplyr::mutate(kli = (.data$prob_1 * log(.data$prob_1 / .data$prob_2)) +
89-
((1 - .data$prob_1) *
90-
log((1 - .data$prob_1) / (1 - .data$prob_2)))) |>
91-
dplyr::left_join(hamming, by = c("profile_1", "profile_2"),
92-
relationship = "many-to-one") |>
93-
dplyr::mutate(dplyr::across(dplyr::where(is.logical),
94-
\(x) {
95-
dplyr::case_when(
96-
x & .data$hamming == 1L ~ TRUE,
97-
.default = NA
98-
)
99-
}),
100-
dplyr::across(dplyr::where(is.logical),
101-
\(x) as.integer(x) * .data$kli)) |>
98+
dplyr::mutate(
99+
kli = (.data$prob_1 * log(.data$prob_1 / .data$prob_2)) +
100+
((1 - .data$prob_1) *
101+
log((1 - .data$prob_1) / (1 - .data$prob_2)))
102+
) |>
103+
dplyr::left_join(
104+
hamming,
105+
by = c("profile_1", "profile_2"),
106+
relationship = "many-to-one"
107+
) |>
108+
dplyr::mutate(
109+
dplyr::across(dplyr::where(is.logical), \(x) {
110+
dplyr::case_when(
111+
x & .data$hamming == 1L ~ TRUE,
112+
.default = NA
113+
)
114+
}),
115+
dplyr::across(dplyr::where(is.logical), \(x) as.integer(x) * .data$kli)
116+
) |>
102117
dplyr::filter(.data$hamming > 0) |>
103118
dplyr::mutate(weight = 1 / .data$hamming)
104119

@@ -135,19 +150,23 @@ cdi <- function(model, weight_prevalence = TRUE) {
135150
test_discrim <- item_discrim |>
136151
dplyr::summarize(dplyr::across(-"item", sum))
137152

138-
list(item_discrimination = item_discrim,
139-
test_discrimination = test_discrim)
153+
list(item_discrimination = item_discrim, test_discrimination = test_discrim)
140154
}
141155

142156
profile_hamming <- function(profiles) {
143-
profile_combos <- tidyr::crossing(profile_1 = seq_len(nrow(profiles)),
144-
profile_2 = seq_len(nrow(profiles)))
145-
157+
profile_combos <- tidyr::crossing(
158+
profile_1 = seq_len(nrow(profiles)),
159+
profile_2 = seq_len(nrow(profiles))
160+
)
146161

147-
hamming <- mapply(hamming_distance, profile_combos$profile_1,
148-
profile_combos$profile_2,
149-
MoreArgs = list(profiles = profiles),
150-
SIMPLIFY = FALSE, USE.NAMES = FALSE) |>
162+
hamming <- mapply(
163+
hamming_distance,
164+
profile_combos$profile_1,
165+
profile_combos$profile_2,
166+
MoreArgs = list(profiles = profiles),
167+
SIMPLIFY = FALSE,
168+
USE.NAMES = FALSE
169+
) |>
151170
dplyr::bind_rows()
152171

153172
dplyr::bind_cols(profile_combos, hamming)
@@ -158,13 +177,25 @@ hamming_distance <- function(prof1, prof2, profiles) {
158177
pattern2 <- profiles[prof2, ]
159178

160179
pattern1 |>
161-
tidyr::pivot_longer(cols = dplyr::everything(),
162-
names_to = "att", values_to = "patt1") |>
163-
dplyr::left_join(tidyr::pivot_longer(pattern2, cols = dplyr::everything(),
164-
names_to = "att", values_to = "patt2"),
165-
by = "att", relationship = "one-to-one") |>
166-
dplyr::mutate(mismatch = .data$patt1 != .data$patt2,
167-
hamming = sum(.data$mismatch)) |>
180+
tidyr::pivot_longer(
181+
cols = dplyr::everything(),
182+
names_to = "att",
183+
values_to = "patt1"
184+
) |>
185+
dplyr::left_join(
186+
tidyr::pivot_longer(
187+
pattern2,
188+
cols = dplyr::everything(),
189+
names_to = "att",
190+
values_to = "patt2"
191+
),
192+
by = "att",
193+
relationship = "one-to-one"
194+
) |>
195+
dplyr::mutate(
196+
mismatch = .data$patt1 != .data$patt2,
197+
hamming = sum(.data$mismatch)
198+
) |>
168199
dplyr::select("att", "mismatch", "hamming") |>
169200
tidyr::pivot_wider(names_from = "att", values_from = "mismatch")
170201
}

R/data-checks.R

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,23 @@
1-
check_file <- function(x, create_dir = FALSE, check_file = TRUE,
2-
ext = NULL, allow_null = FALSE,
3-
arg = rlang::caller_arg(x),
4-
call = rlang::caller_env()) {
5-
if (allow_null && is.null(x)) return(character())
1+
check_file <- function(
2+
x,
3+
create_dir = FALSE,
4+
check_file = TRUE,
5+
ext = NULL,
6+
allow_null = FALSE,
7+
arg = rlang::caller_arg(x),
8+
call = rlang::caller_env()
9+
) {
10+
if (allow_null && is.null(x)) {
11+
return(character())
12+
}
613

714
directory <- fs::path_dir(x)
815
if (!fs::dir_exists(directory) && !create_dir) {
9-
rdcmchecks::abort_bad_argument(arg = arg,
10-
must = "be an existing directory",
11-
call = call)
16+
rdcmchecks::abort_bad_argument(
17+
arg = arg,
18+
must = "be an existing directory",
19+
call = call
20+
)
1221
} else if (!fs::dir_exists(directory) && create_dir) {
1322
fs::dir_create(directory)
1423
}
@@ -18,9 +27,11 @@ check_file <- function(x, create_dir = FALSE, check_file = TRUE,
1827
}
1928

2029
if (check_file && !fs::file_exists(x)) {
21-
rdcmchecks::abort_bad_argument(arg = arg,
22-
must = "be an existing file",
23-
call = call)
30+
rdcmchecks::abort_bad_argument(
31+
arg = arg,
32+
must = "be an existing file",
33+
call = call
34+
)
2435
}
2536

2637
return(x)

0 commit comments

Comments
 (0)