library(testthat)
# Load already included functions if relevant pkgload::load_all(export_all = FALSE) library(readxl) library(dplyr) library(purrr)
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
#' 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( ) )
ref <- Referential$new( path = system.file("SurveyDesigner_Referential.xlsx", package = "surveyDesigner") )
ref <- Referential$new( path = system.file("SurveyDesigner_Referential.xlsx", package = "surveyDesigner") ) head(ref$data$survey) # Example by groups ref$by_groups$group_intro
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" ) ) })
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") } }
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]))
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") })
# 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" )
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.