-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathflat_r6_referential.Rmd
304 lines (230 loc) · 8.61 KB
/
flat_r6_referential.Rmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
---
title: "Class R6 for the referential"
output: html_document
editor_options:
chunk_output_type: console
---
```{r development, include=FALSE}
library(testthat)
```
```{r development-load}
# Load already included functions if relevant
pkgload::load_all(export_all = FALSE)
library(readxl)
library(dplyr)
library(purrr)
```
# r6_referential
The filtering of the referential should take in account the order/sequence of questions and modules.
A specific method is implemented to separate our file with begin and end group
```{r function-r6_referential}
#' Referential class is a class to load, check and manipulate the XLSForm
#' @importFrom R6 R6Class
#'
#' @export
Referential <- R6::R6Class(classname = "Referential",
public = list(
#' @description
#' read the xlsx for each sheet and return a named list
#' @param path path to the file with the full referential
#'
#' @importFrom readxl excel_sheets read_xlsx
#'
#' @return named list
initialize = function(path){
# Define path
self$path <- path
# Get sheets of xlsx
sheets <- names_of_sheet(path)
# Read the xlsx file
data <- lapply(
sheets,
function(x){
read_xlsx(path = path, sheet = x)}) |>
setNames(nm = sheets)
# TODO checking survey and other sheets
# survey have to be a xlsform
if(!contains_groups(data$survey)){
stop("the sheet 'survey' doesn't includes groups - i.e. questions organised as module")
}
self$data <- data
# Get groups
self$get_groups()
},
#' @field data named list for the referential file
data = list(),
#' @field by_groups survey modules separated by begin and end to manipulate data
by_groups = list(),
#' @field path path for the xlsx file
path = character(0),
#' @description get data by groups of begin and end
get_groups = function(){
self$by_groups <- get_groups(self$data$survey)
message("result is store in `by_groups` sub-element")
}
),
private = list(
)
)
```
```{r development-test}
ref <- Referential$new(
path = system.file("SurveyDesigner_Referential.xlsx", package = "surveyDesigner")
)
```
```{r examples-r6_referential}
ref <- Referential$new(
path = system.file("SurveyDesigner_Referential.xlsx", package = "surveyDesigner")
)
head(ref$data$survey)
# Example by groups
ref$by_groups$group_intro
```
```{r tests-r6_referential}
test_that("r6_referential works", {
ref <- Referential$new(
path = system.file("SurveyDesigner_Referential.xlsx", package = "surveyDesigner")
)
expect_true( inherits(ref, "R6") )
expect_error(
Referential$new(
path = "not_good_sheet.xlsx"
)
)
expect_error(
Referential$new(
path = "wt_xlsform_in_survey.xlsx"
)
)
})
```
# Utils for referential manipulation
```{r function-utils_xlsform}
survey_designer <- new.env()
assign(
"names_sheets",
c("referential_type",
"survey",
"choices",
"indicator",
"indicator_survey",
"indicator_choices",
"indicator_population",
"indicator_disaggregation"
),
envir = survey_designer)
#' Get groups form begin and end into a list with data and information
#'
#' @param data data from the survey sheet
#'
#' @importFrom purrr map2 set_names map
#' @importFrom dplyr slice filter
#'
#' @return list
#'
get_groups <- function(data){
# only on survey
begin_start <- grep(x = data[["type"]], "begin_")
end_stop <- grep(x = data[["type"]], "end_")
if(length(begin_start) != length(end_stop)){
stop("Miss one begin or stop in the data")
}
if(!all(begin_start < end_stop)){
stop("One begin is before a end")
}
by_begin_end <- map2(begin_start, end_stop,
function(x,y){
data_to_get <- data %>%
slice(x:y)
by_groups <- list(data = data_to_get %>%
filter(!type %in% c("begin_group", "end_group")),
information = data_to_get %>%
filter(type %in% c("begin_group", "end_group"))
)
# names(by_groups) <- by_groups[["information"]][["name"]]
by_groups
}) %>%
purrr::set_names(nm = purrr::map(., ~ .x[["information"]][["name"]][1]))
return(by_begin_end)
}
#' Get choices for one question
#'
#' @param survey data from the choices sheet
#' @param full_name the full name (i.e. concatenating groups) for the variable
#'
#' @importFrom dplyr filter select contains
#'
#' @return a data.frame to join
get_choices_for_question <- function(survey, full_name){
survey %>%
filter(list_name == full_name) %>%
select(list_name, name, label)
}
#' function to find if we manipulate a xlsform
#'
#' @param data data of the survey
#'
#' @noRd
contains_groups <- function(data){
any(grepl(x = data[["type"]], pattern = 'begin_group|begin_repeat|end_group|end_repeat'))
}
#' function to check name of sheets
#'
#' @param path path to the xlsform
#'
#' @noRd
names_of_sheet <- function(path){
sheets <- excel_sheets(path)
if(all(sheets == get("names_sheets", envir = survey_designer))){
return(sheets)
}else{
stop("Problem with the name of sheets")
}
}
```
```{r development-utils, eval = FALSE}
data <- ref$data$survey
begin_start <- grep(x = , "begin_")
end_stop <- grep(x = data[["type"]], "end_")
if(length(begin_start) != length(end_stop)){
stop("Miss one begin or stop in the data")
}
if(!all(begin_start < end_stop)){
stop("One begin is before a end")
}
by_begin_end <- purrr::map2(begin_start, end_stop,
function(x,y){
data_to_get <- data %>%
slice(x:y)
by_groups <- list(data = data_to_get %>%
filter(!type %in% c("begin_group", "end_group")),
information = data_to_get %>%
filter(type %in% c("begin_group", "end_group"))
)
# names(by_groups) <- by_groups[["information"]][["name"]]
by_groups
}) %>%
purrr::set_names(nm = purrr::map(., ~ .x[["information"]][["name"]][1]))
```
```{r tests-utils_xlsform}
test_that("utils_xlsform works", {
expect_true(inherits(get_groups, "function"))
ref <- Referential$new(
path = system.file("SurveyDesigner_Referential.xlsx", package = "surveyDesigner")
)
result <- get_groups(ref$data$survey)
expect_named(result[[1]], c("data", "information"))
expect_type(result, "list")
expect_true(inherits(get_choices_for_question, "function"))
get_choices <- get_choices_for_question(ref$data$choices, "pop_groups")
expect_type(get_choices, "list")
})
```
```{r development-inflate, eval=FALSE}
# Run but keep eval=FALSE to avoid infinite loop
# Execute in the console directly
fusen::inflate(
flat_file = "dev/flat_r6_referential.Rmd",
vignette_name = "Class R6 for the referential"
)
```