Skip to content

Commit

Permalink
Merge pull request #117 from pbrohan/remove-check_names
Browse files Browse the repository at this point in the history
Read `as_tibble` by default.
  • Loading branch information
chainsawriot authored Jul 25, 2023
2 parents aeba10c + 0ba00e9 commit 38edd92
Show file tree
Hide file tree
Showing 22 changed files with 256 additions and 257 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/R-CMD-check.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
on:
push:
branches:
- v1*
- v2*
pull_request:
branches:
- v1*
- v2*

name: R-CMD-check

Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/test-coverage.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
on:
push:
branches:
- v1*
- v2*
pull_request:
branches:
- v1*
- v2*

name: test-coverage

Expand Down
3 changes: 2 additions & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ Imports:
stringi,
utils,
zip,
tibble
tibble,
vctrs (>= 0.4.2)
LinkingTo:
cpp11
Suggests:
Expand Down
6 changes: 5 additions & 1 deletion NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,11 @@ length(list_ods_sheets("starwars.ods"))
* `overwrite`: always TRUE
* `verbose`: always FALSE
* `na_as_string`: default to FALSE

*
## BREAKING CHANGES: read_ods now outputs as tibble by default
* Added `as_tibble` and `.name_repair` as arguments. If `as_tibble` is true, outputs as a tibble using `tibble::as_tibble()` passing on `.name_repair` (default being `"unique"`). **By default** `as_tibble` is set to TRUE.
* Removed `check_names` argument. All name repairs are now dealt with using `vctrs::vec_as_names()`. This will **significantly change** the default names given to outputs. (Names in the style of `check_names = TRUE` can be obtained by setting `.name_repair = minimal`, although this is not advised)

# readODS 1.9.0

* Added a `NEWS.md` file to track changes to the package.
Expand Down
67 changes: 30 additions & 37 deletions R/read_ods.R
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.change_df_with_col_row_header <- function(x, col_header, row_header) {
.change_df_with_col_row_header <- function(x, col_header, row_header, .name_repair) {
if((nrow(x) < 2 && col_header )|| (ncol(x) < 2 && row_header)) {
warning("Cannot make column/row names if this would cause the dataframe to be empty.", call. = FALSE)
return(x)
Expand All @@ -7,8 +7,15 @@
jcol <- ifelse(row_header, 2, 1)

g <- x[irow:nrow(x), jcol:ncol(x), drop=FALSE] # maintain as dataframe for single column


rownames(g) <- if(row_header) x[seq(irow, nrow(x)), 1] else NULL # don't want character row headers given by 1:nrow(g)
colnames(g) <- if(col_header) x[1, seq(jcol, ncol(x))] else cellranger::num_to_letter(seq_len(ncol(g)))
cols <- ncol(x)
if (row_header) {
cols <- cols - 1
}
col_n <- if(col_header) x[1, seq(jcol, ncol(x))] else c(rep("", cols))
colnames(g) <- vctrs::vec_as_names(unlist(col_n), repair = .name_repair)
return(g)
}

Expand Down Expand Up @@ -70,10 +77,8 @@
range = NULL,
row_names = FALSE,
strings_as_factors = FALSE,
check_names = FALSE,
verbose = FALSE,
as_tibble = FALSE,
.name_repair = "check_unique") {
as_tibble = TRUE) {
if (missing(path) || !is.character(path)) {
stop("No file path was provided for the 'path' argument. Please provide a path to a file to import.", call. = FALSE)
}
Expand All @@ -92,22 +97,14 @@
if (!is.logical(strings_as_factors)) {
stop("strings_as_factors must be of type `boolean`", call. = FALSE)
}
if (!is.logical(check_names)) {
stop("check_names must be of type `boolean`", call. = FALSE)
}
if (!is.logical(verbose)) {
stop("verbose must be of type `boolean`", call. = FALSE)
}
if (!is.logical(as_tibble)) {
stop("as_tibble must be of type `boolean", call. = FALSE)
}
if (as_tibble &&
(!(.name_repair %in% c("minimal",
"unique",
"check_unique",
"universal")) ||
is.function(.name_repair))) {
stop(".name_repair must either be one of \"minimal\", \"unique\", \"check_unique\", \"univseral\" or a function", call. = FALSE)
if (row_names && as_tibble){
stop("Tibbles do not support row names. To use row names, set as_tibble to false", call. = FALSE)
}
}

Expand All @@ -121,25 +118,22 @@
range = NULL,
row_names = FALSE,
strings_as_factors = FALSE,
check_names = FALSE,
verbose = FALSE,
as_tibble = FALSE,
.name_repair = "check_unique",
as_tibble = TRUE,
.name_repair = "unique",
flat = FALSE) {
.check_read_args(path,
sheet,
col_names,
col_types,
na,
skip,
skip,
formula_as_formula,
range,
row_names,
strings_as_factors,
check_names,
verbose,
as_tibble,
.name_repair)
as_tibble)
# Get cell range info
limits <- .standardise_limits(range, skip)
# Get sheet number.
Expand Down Expand Up @@ -194,16 +188,20 @@
}
if(strings[1] == 0 || strings[2] == 0) {
warning("empty sheet, return empty data frame.", call. = FALSE)
return(data.frame())
if(as_tibble){
return(tibble::tibble())
} else {
return(data.frame())
}
}
res <- as.data.frame(
matrix(
strings[-1:-2],
ncol = strtoi(strings[1]),
byrow = TRUE),
stringsAsFactors = FALSE)
res <- .change_df_with_col_row_header(res, col_names, row_names)
res <- data.frame(res, check.names = check_names)
res <- .change_df_with_col_row_header(res, col_names, row_names, .name_repair)
res <- data.frame(res)
if (inherits(col_types, 'col_spec')) {
res <- readr::type_convert(df = res, col_types = col_types, na = na)
} else if (length(col_types) == 0 && is.null(col_types)) {
Expand Down Expand Up @@ -243,19 +241,18 @@
#' @param range selection of rectangle using Excel-like cell range, such as \code{range = "D12:F15"} or \code{range = "R1C12:R6C15"}. Cell range processing is handled by the \code{\link[=cellranger]{cellranger}} package.
#' @param row_names logical, indicating whether the file contains the names of the rows as its first column. Default is FALSE.
#' @param strings_as_factors logical, if character columns to be converted to factors. Default is FALSE.
#' @param check_names logical, passed down to base::data.frame(). Default is FALSE.
#' @param verbose logical, if messages should be displayed. Default is FALSE.
#' @param as_tibble logical, if the output should be a tibble (as opposed to a data.frame). Default is FALSE.
#' @param as_tibble logical, if the output should be a tibble (as opposed to a data.frame). Default is TRUE.
#' @param .name_repair A string or function passed on as `.name_repair` to [tibble::as_tibble()]
#' - `"minimal"`: No name repair
#' - `"unique"` : Make sure names are unique and not empty
#' - `"check_unique"`: Check names are unique, but do not repair
#' - `"universal"` : Checks names are unique and valid R variables names in scope
#' - A function to apply custom name repair.
#'
#' Default is `"check_unique"`.
#' Default is `"unique"`.
#'
#' @return A data frame (\code{data.frame}) containing a representation of data in the (f)ods file.
#' @return A tibble (\code{tibble}) or data frame (\code{data.frame}) containing a representation of data in the (f)ods file.
#' @author Peter Brohan <peter.brohan+cran@@gmail.com>, Chung-hong Chan <chainsawtiney@@gmail.com>, Gerrit-Jan Schutten <phonixor@@gmail.com>
#' @examples
#' \dontrun{
Expand Down Expand Up @@ -283,10 +280,9 @@ read_ods <- function(path,
range = NULL,
row_names = FALSE,
strings_as_factors = FALSE,
check_names = FALSE,
verbose = FALSE,
as_tibble = FALSE,
.name_repair = "check_unique"
as_tibble = TRUE,
.name_repair = "unique"

) {
## Should use match.call but there's a weird bug if one of the variable names is 'file'
Expand All @@ -300,7 +296,6 @@ read_ods <- function(path,
range,
row_names,
strings_as_factors,
check_names,
verbose,
as_tibble,
.name_repair,
Expand All @@ -319,10 +314,9 @@ read_fods <- function(path,
range = NULL,
row_names = FALSE,
strings_as_factors = FALSE,
check_names = FALSE,
verbose = FALSE,
as_tibble = FALSE,
.name_repair = "check_unique"
as_tibble = TRUE,
.name_repair = "unique"

) {
## Should use match.call but there's a weird bug if one of the variable names is 'file'
Expand All @@ -336,7 +330,6 @@ read_fods <- function(path,
range,
row_names,
strings_as_factors,
check_names,
verbose,
as_tibble,
.name_repair,
Expand Down
7 changes: 5 additions & 2 deletions R/writeODS.R
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@
}

## https://github.com/ropensci/readODS/issues/88
.vfwrite_ods <- function(x, temp_ods_dir, sheet = "Sheet1", row_names = FALSE, col_names = FALSE, na_as_string = FALSE) {
.vfwrite_ods <- function(x, temp_ods_dir, sheet = "Sheet1", row_names = FALSE, col_names = TRUE, na_as_string = FALSE) {
templatedir <- system.file("template", package = "readODS")
file.copy(dir(templatedir, full.names = TRUE), temp_ods_dir, recursive = TRUE, copy.mode = FALSE)
con <- file(file.path(temp_ods_dir, "content.xml"), open="w", encoding = "UTF-8")
Expand All @@ -121,7 +121,7 @@
#' @param append logical, TRUE indicates that x should be appended to the existing file (path) as a new sheet. If a sheet with the same sheet_name exists, an exception is thrown. See update. Please also note that writing is slower if TRUE. Default is FALSE.
#' @param update logical, TRUE indicates that the sheet with sheet_name in the existing file (path) should be updated with the content of x. If a sheet with sheet_name does not exist, an exception is thrown. Please also note that writing is slower if TRUE. Default is FALSE.
#' @param row_names logical, TRUE indicates that row names of x are to be included in the sheet. Default is FALSE.
#' @param col_names logical, TRUE indicates that column names of x are to be included in the sheet. Default is FALSE.
#' @param col_names logical, TRUE indicates that column names of x are to be included in the sheet. Default is TRUE.
#' @param na_as_string logical, TRUE indicates that NAs are written as string.
#' @return An ODS file written to the file path location specified by the user. The value of \code{path} is also returned invisibly.
#' @author Detlef Steuer <steuer@@hsu-hh.de>, Thomas J. Leeper <thosjleeper@@gmail.com>, John Foster <john.x.foster@@nab.com.au>, Chung-hong Chan <chainsawtiney@@gmail.com>
Expand All @@ -139,6 +139,9 @@ write_ods <- function(x, path, sheet = "Sheet1", append = FALSE, update = FALSE,
temp_ods_dir <- file.path(tempdir(), stringi::stri_rand_strings(1, 20, pattern = "[A-Za-z0-9]"))
dir.create(temp_ods_dir)
on.exit(unlink(temp_ods_dir))
if (inherits(x, "tbl_df")){ #Convert to a df if currently a tibble
x <- as.data.frame(x)
}
if (!is.data.frame(x)) {
stop("x must be a data.frame.", call. = FALSE)
}
Expand Down
4 changes: 2 additions & 2 deletions README.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,9 @@ Reading from a specific range
read_ods("starwars.ods", sheet = 2, range = "A1:C11")
```

Reading as a tibble
Reading as a dataframe
```{r}
read_ods("starwars.ods", range="Sheet1!A2:C11", as_tibble = TRUE)
read_ods("starwars.ods", range="Sheet1!A2:C11", as_tibble = FALSE)
```

#### Writing
Expand Down
Loading

0 comments on commit 38edd92

Please sign in to comment.