diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 0805e5af..f614f7dd 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -8,4 +8,15 @@ RUN apt-get install -y libqpdf28 qpdf ghostscript RUN install2.r --error devtools rJava RUnit zoo qpdf languageserver RUN installGithub.r r-lib/revdepcheck RUN apt-get install -y pandoc -RUN install2.r --error ggplot2 +RUN install2.r --error ggplot2 tinytex +RUN Rscript -e "{\ + library(tinytex);\ + tlmgr_install('datetime');\ + tlmgr_install('inputenc');\ + tlmgr_install('hyperref');\ + tlmgr_install('url');\ + tlmgr_install('fmtcount');\ + tlmgr_install('float');\ + tlmgr_install('natbib');\ + tinytex:::install_yihui_pkgs();\ +}" diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 0eb1be67..493b0c1a 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -8,14 +8,14 @@ "customizations": { "vscode": { // Add the IDs of extensions you want installed when the container is created. - "extensions": [ - "eamodio.gitlens", - "REditorSupport.r", - "github.vscode-pull-request-github", - "github.vscode-github-actions" - ] - } + "extensions": [ + "eamodio.gitlens", + "REditorSupport.r", + "github.vscode-pull-request-github", + "github.vscode-github-actions" + ] } + } // Use 'forwardPorts' to make a list of ports inside the container available locally. // "forwardPorts": [], @@ -28,4 +28,10 @@ // Comment out connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root. // "remoteUser": "vscode" + + // The below may help when using podman instead of docker as the container backend + // (see https://github.com/microsoft/vscode-remote-release/issues/7175#issuecomment-1645498699) + // ,"runArgs": [ + // "--log-driver=none" + // ] } diff --git a/.github/workflows/ci-tests.yml b/.github/workflows/ci-tests.yml index 7858c0f2..0a3a18ec 100644 --- a/.github/workflows/ci-tests.yml +++ b/.github/workflows/ci-tests.yml @@ -31,7 +31,6 @@ jobs: r-version: oldrel java: 17 #8 vignettes: true - xlc-repo: https://jcenter.bintray.com timezone-name: Europe/Zurich - os-name: ubuntu # windows-2019, macos-10.15] os-version: latest @@ -44,7 +43,6 @@ jobs: r-version: devel java: 17 vignettes: true - xlc-repo: https://jcenter.bintray.com timezone-name: Pacific/Marquesas - os-name: macos # TODO fix java / R interaction os-version: latest diff --git a/.lintr b/.lintr new file mode 100644 index 00000000..f3f0d12e --- /dev/null +++ b/.lintr @@ -0,0 +1,3 @@ +linters: linters_with_defaults() # see vignette("lintr") +encoding: "UTF-8" +exclusions: list("R", "demo", "inst", "tests") # disables linting with lintr, as we have not decided yet which linters to use diff --git a/DESCRIPTION b/DESCRIPTION index 5121f46d..4148cf00 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Package: XLConnect Type: Package Title: Excel Connector for R -Version: 1.0.8.9999 +Version: 1.1.0.9999 Authors@R: c(person("Mirai Solutions GmbH", role = "aut", email = "xlconnect@mirai-solutions.com"), person("Martin", "Studer", role = "cre", diff --git a/R/dataframeFromJava.R b/R/dataframeFromJava.R index 4165a505..f7c343dd 100644 --- a/R/dataframeFromJava.R +++ b/R/dataframeFromJava.R @@ -72,9 +72,13 @@ dataframeFromJava <- function(df, check.names) { res[[i]] = v } + # Apply attributes + toSet = (attributes(df))[!names(attributes(df)) %in% c("jobj", "jclass", "class", "package")] # Apply names - names(res) = columnNames + attributes(res) = toSet + names(res) = columnNames + result = data.frame(res, check.names = check.names, stringsAsFactors = FALSE) - data.frame(res, check.names = check.names, stringsAsFactors = FALSE) + result }) } diff --git a/R/extractRownames.R b/R/extractRownames.R index 740070d8..c01ae64c 100644 --- a/R/extractRownames.R +++ b/R/extractRownames.R @@ -30,7 +30,10 @@ extractRownames <- function(x, col) { if(is(x, "list")) { if(is.null(col)) col = list(NULL) - mapply(extractRownames, x, col, SIMPLIFY = FALSE) + res <- mapply(extractRownames, x, col, SIMPLIFY = FALSE) + attributes(res) <- attributes(x) + res + } else{ # use attr(x, "row.names") instead of row.names or rownames # since row.names coerces to character for backward compatibility diff --git a/R/withAttributesFromJava.R b/R/withAttributesFromJava.R new file mode 100644 index 00000000..69e11180 --- /dev/null +++ b/R/withAttributesFromJava.R @@ -0,0 +1,43 @@ +############################################################################# +# +# XLConnect +# Copyright (C) 2010-2021 Mirai Solutions GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +############################################################################# + +############################################################################# +# +# Utility function for converting XLConnect java objects with added attributes +# to R variables with the corresponding attributes. +# +# Author: Simon Poltier, Mirai Solutions GmbH +# +############################################################################# + +withAttributesFromJava <- function(jobj) { + + # jni <- .jcall(jobj, "S", "jni") + # unwrapped <- .jcall(jobj, jni, "getValue") + unwrapped <- jobj$getValue() + + allANames = .jcall(jobj, "[S", "getAttributeNames") + # allAValues = .jcall(jobj, "[S", "getAttributeValues") + + for(i in seq(along = allANames)) { + attr(unwrapped, allANames[i]) <- jobj$getAttributeValue(allANames[i]) + } + unwrapped + } \ No newline at end of file diff --git a/R/workbook.addImage.R b/R/workbook.addImage.R index 3b7f9978..6d0defd8 100644 --- a/R/workbook.addImage.R +++ b/R/workbook.addImage.R @@ -26,13 +26,13 @@ # ############################################################################# -setGeneric("addImage", - function(object, filename, name, originalSize = FALSE) standardGeneric("addImage")) +setGeneric("addImage", + function(object, filename, name, originalSize = FALSE, worksheetScope = NULL) standardGeneric("addImage")) -setMethod("addImage", - signature(object = "workbook"), - function(object, filename, name, originalSize = FALSE) { - xlcCall(object, "addImage", filename, name, originalSize) +setMethod("addImage", + signature(object = "workbook"), + function(object, filename, name, originalSize = FALSE, worksheetScope = NULL) { + xlcCall(object, "addImage", filename, name, originalSize, worksheetScope %||% .jnull()) invisible() } ) diff --git a/R/workbook.appendNamedRegion.R b/R/workbook.appendNamedRegion.R index 210e300e..e2aaf6ec 100644 --- a/R/workbook.appendNamedRegion.R +++ b/R/workbook.appendNamedRegion.R @@ -28,17 +28,17 @@ setGeneric("appendNamedRegion", function(object, data, name, header = FALSE, overwriteFormulaCells = TRUE, - rownames = NULL) standardGeneric("appendNamedRegion")) + rownames = NULL, worksheetScope = NULL) standardGeneric("appendNamedRegion")) setMethod("appendNamedRegion", signature(object = "workbook", data = "ANY"), function(object, data, name, header = FALSE, overwriteFormulaCells = TRUE, - rownames = NULL) { + rownames = NULL, worksheetScope = NULL) { if(is.character(rownames)) data <- includeRownames(data, rownames) # pass data.frame's to Java - construct RDataFrameWrapper Java object references data <- lapply(wrapList(data), dataframeToJava) - xlcCall(object, "appendNamedRegion", data, name, header, overwriteFormulaCells, .simplify = FALSE) + xlcCall(object, "appendNamedRegion", data, name, worksheetScope %||% .jnull(), header, overwriteFormulaCells, .simplify = FALSE) invisible() } ) diff --git a/R/workbook.clearNamedRegion.R b/R/workbook.clearNamedRegion.R index 4fa5eb96..fec19b0e 100644 --- a/R/workbook.clearNamedRegion.R +++ b/R/workbook.clearNamedRegion.R @@ -1,38 +1,38 @@ -############################################################################# -# -# XLConnect -# Copyright (C) 2010-2024 Mirai Solutions GmbH -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -############################################################################# - -############################################################################# -# -# Clearing a named region -# -# Author: Nicola Lambiase, Mirai Solutions GmbH -# -############################################################################# - -setGeneric("clearNamedRegion", - function(object, name) standardGeneric("clearNamedRegion")) - -setMethod("clearNamedRegion", - signature(object = "workbook", name = "character"), - function(object, name) { - xlcCall(object, "clearNamedRegion", name) - invisible() - } -) +############################################################################# +# +# XLConnect +# Copyright (C) 2010-2024 Mirai Solutions GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +############################################################################# + +############################################################################# +# +# Clearing a named region +# +# Author: Nicola Lambiase, Mirai Solutions GmbH +# +############################################################################# + +setGeneric("clearNamedRegion", + function(object, name, worksheetScope = NULL) standardGeneric("clearNamedRegion")) + +setMethod("clearNamedRegion", + signature(object = "workbook", name = "character"), + function(object, name, worksheetScope = NULL) { + xlcCall(object, "clearNamedRegion", name, worksheetScope %||% .jnull(), .simplify = FALSE) + invisible() + } +) diff --git a/R/workbook.cloneSheet.R b/R/workbook.cloneSheet.R index c72cf225..ac76470f 100644 --- a/R/workbook.cloneSheet.R +++ b/R/workbook.cloneSheet.R @@ -29,6 +29,7 @@ setGeneric("cloneSheet", function(object, sheet, name) standardGeneric("cloneSheet")) +# TODO make cloning names optional setMethod("cloneSheet", signature(object = "workbook", sheet = "numeric"), function(object, sheet, name) { diff --git a/R/workbook.createName.R b/R/workbook.createName.R index 3ad23ca1..6c4c0519 100644 --- a/R/workbook.createName.R +++ b/R/workbook.createName.R @@ -1,38 +1,38 @@ -############################################################################# -# -# XLConnect -# Copyright (C) 2010-2024 Mirai Solutions GmbH -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -############################################################################# - -############################################################################# -# -# Creating names in a workbook -# -# Author: Martin Studer, Mirai Solutions GmbH -# -############################################################################# - -setGeneric("createName", - function(object, name, formula, overwrite = FALSE) standardGeneric("createName")) - -setMethod("createName", - signature(object = "workbook"), - function(object, name, formula, overwrite = FALSE) { - xlcCall(object, "createName", name, formula, overwrite) - invisible() - } -) +############################################################################# +# +# XLConnect +# Copyright (C) 2010-2024 Mirai Solutions GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +############################################################################# + +############################################################################# +# +# Creating names in a workbook +# +# Author: Martin Studer, Mirai Solutions GmbH +# +############################################################################# + +setGeneric("createName", + function(object, name, formula, overwrite = FALSE, worksheetScope = NULL) standardGeneric("createName")) + +setMethod("createName", + signature(object = "workbook"), + function(object, name, formula, overwrite = FALSE, worksheetScope = NULL) { + xlcCall(object, "createName", name, worksheetScope %||% .jnull(), formula, overwrite) + invisible() + } +) diff --git a/R/workbook.existsName.R b/R/workbook.existsName.R index 1d6ea36e..664a1e80 100644 --- a/R/workbook.existsName.R +++ b/R/workbook.existsName.R @@ -1,37 +1,37 @@ -############################################################################# -# -# XLConnect -# Copyright (C) 2010-2024 Mirai Solutions GmbH -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -############################################################################# - -############################################################################# -# -# Checking existence of names in a workbook -# -# Author: Martin Studer, Mirai Solutions GmbH -# -############################################################################# - -setGeneric("existsName", - function(object, name) standardGeneric("existsName")) - -setMethod("existsName", - signature(object = "workbook"), - function(object, name) { - xlcCall(object, "existsName", name) - } -) +############################################################################# +# +# XLConnect +# Copyright (C) 2010-2024 Mirai Solutions GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +############################################################################# + +############################################################################# +# +# Checking existence of names in a workbook +# +# Author: Martin Studer, Mirai Solutions GmbH +# +############################################################################# + +setGeneric("existsName", + function(object, name, worksheetScope = NULL) standardGeneric("existsName")) + +setMethod("existsName", + signature(object = "workbook"), + function(object, name, worksheetScope = NULL) { + xlcCall(object, "existsName", name, worksheetScope %||% .jnull(), .withAttributes = TRUE) + } +) diff --git a/R/workbook.getDefinedNames.R b/R/workbook.getDefinedNames.R index c2904183..2fdf96a6 100644 --- a/R/workbook.getDefinedNames.R +++ b/R/workbook.getDefinedNames.R @@ -27,11 +27,11 @@ ############################################################################# setGeneric("getDefinedNames", - function(object, validOnly = TRUE) standardGeneric("getDefinedNames")) + function(object, validOnly = TRUE, worksheetScope = NULL) standardGeneric("getDefinedNames")) setMethod("getDefinedNames", signature(object = "workbook"), - function(object, validOnly = TRUE) { - xlcCall(object, "getDefinedNames", validOnly, .recycle = FALSE) + function(object, validOnly = TRUE, worksheetScope = NULL) { + xlcCall(object, "getDefinedNames", validOnly, worksheetScope %||% .jnull(), .recycle = TRUE) } ) diff --git a/R/workbook.getReferenceCoordinatesForName.R b/R/workbook.getReferenceCoordinatesForName.R index 24b15865..4cab6e9c 100644 --- a/R/workbook.getReferenceCoordinatesForName.R +++ b/R/workbook.getReferenceCoordinatesForName.R @@ -27,12 +27,14 @@ ############################################################################# setGeneric("getReferenceCoordinatesForName", - function(object, name) standardGeneric("getReferenceCoordinatesForName")) + function(object, name, worksheetScope = NULL) standardGeneric("getReferenceCoordinatesForName")) setMethod("getReferenceCoordinatesForName", signature(object = "workbook"), - function(object, name) { - res <- xlcCall(object, "getReferenceCoordinatesForName", name) + function(object, name, worksheetScope = NULL) { + # print(paste("about to xlc call get reference coordinates for name", worksheetScope)) + res <- xlcCall(object, "getReferenceCoordinatesForName", name, worksheetScope %||% .jnull()) + # print(paste("called get reference coordinates for name" , worksheetScope)) if(is.numeric(res)) { matrix(res, nrow = 2, byrow = TRUE) + 1 } else { res } } ) diff --git a/R/workbook.getReferenceFormula.R b/R/workbook.getReferenceFormula.R index 1eed1561..f7f4a648 100644 --- a/R/workbook.getReferenceFormula.R +++ b/R/workbook.getReferenceFormula.R @@ -27,11 +27,11 @@ ############################################################################# setGeneric("getReferenceFormula", - function(object, name) standardGeneric("getReferenceFormula")) + function(object, name, worksheetScope = NULL) standardGeneric("getReferenceFormula")) -setMethod("getReferenceFormula", - signature(object = "workbook"), - function(object, name) { - xlcCall(object, "getReferenceFormula", name) +setMethod("getReferenceFormula", + signature(object = "workbook"), + function(object, name, worksheetScope = NULL) { + xlcCall(object, "getReferenceFormula", name, worksheetScope %||% .jnull()) } ) diff --git a/R/workbook.readNamedRegion.R b/R/workbook.readNamedRegion.R index f87aa68b..fda8d34e 100644 --- a/R/workbook.readNamedRegion.R +++ b/R/workbook.readNamedRegion.R @@ -32,7 +32,7 @@ setGeneric("readNamedRegion", function(object, name, header = TRUE, rownames = NULL, colTypes = character(0), forceConversion = FALSE, dateTimeFormat = getOption("XLConnect.dateTimeFormat"), check.names = TRUE, useCachedValues = FALSE, keep = NULL, drop = NULL, simplify = FALSE, - readStrategy = "default") + readStrategy = "default", worksheetScope = NULL) standardGeneric("readNamedRegion")) @@ -41,28 +41,31 @@ setMethod("readNamedRegion", function(object, name, header = TRUE, rownames = NULL, colTypes = character(0), forceConversion = FALSE, dateTimeFormat = getOption("XLConnect.dateTimeFormat"), check.names = TRUE, useCachedValues = FALSE, keep = NULL, drop = NULL, simplify = FALSE, - readStrategy = "default") { + readStrategy = "default", worksheetScope = NULL) { - # returns a list of RDataFrameWrapper Java object references - sheet = as.vector(extractSheetName(getReferenceFormula(object, name))) - namedim = matrix(as.vector(t(getReferenceCoordinatesForName(object, name))), nrow=4, byrow=FALSE) - startRow = namedim[1,] - startCol = namedim[2,] - endRow = namedim[3,] - endCol = namedim[4,] - numcols = endCol-startCol+1 + # returns a list of RDataFrameWrapper Java object references + sheet = as.vector(extractSheetName(getReferenceFormula(object, name, worksheetScope))) + + namedim = matrix(as.vector(t(getReferenceCoordinatesForName(object, name, worksheetScope))), nrow=4, byrow=FALSE) + startRow = namedim[1,] + startCol = namedim[2,] + endRow = namedim[3,] + endCol = namedim[4,] + numcols = endCol-startCol+1 - subset <- getColSubset(object, sheet, startRow, endRow, startCol, endCol, header, numcols, keep, drop) - dataFrame <- xlcCall(object, "readNamedRegion", name, header, .jarray(classToXlcType(colTypes)), - forceConversion, dateTimeFormat, useCachedValues, subset, readStrategy, .simplify = FALSE) - + subset <- getColSubset(object, sheet, startRow, endRow, startCol, endCol, header, numcols, keep, drop) + + dataFrame <- xlcCall(object, "readNamedRegion", name, header, .jarray(classToXlcType(colTypes)), + forceConversion, dateTimeFormat, useCachedValues, subset, readStrategy, worksheetScope %||% .jnull(), + .simplify = FALSE, .withAttributes = TRUE + ) + # get data.frames from Java dataFrame = lapply(dataFrame, dataframeFromJava, check.names = check.names) # extract rownames dataFrame = extractRownames(dataFrame, rownames) - names(dataFrame) <- name - + names(dataFrame) <- rep(name, length.out = length(dataFrame)) # simplify dataFrame = mapply(df = dataFrame, simplify = rep(simplify, length.out = length(dataFrame)), @@ -71,7 +74,6 @@ setMethod("readNamedRegion", else df }, SIMPLIFY = FALSE ) - # Return data.frame directly in case only one data.frame is read if(length(dataFrame) == 1) dataFrame[[1]] else dataFrame diff --git a/R/workbook.removeName.R b/R/workbook.removeName.R index d26cab13..27104d08 100644 --- a/R/workbook.removeName.R +++ b/R/workbook.removeName.R @@ -27,12 +27,12 @@ ############################################################################# setGeneric("removeName", - function(object, name) standardGeneric("removeName")) + function(object, name, worksheetScope = NULL) standardGeneric("removeName")) setMethod("removeName", signature(object = "workbook"), - function(object, name) { - xlcCall(object, "removeName", name) + function(object, name, worksheetScope) { + xlcCall(object, "removeName", name, worksheetScope %||% .jnull()) invisible() } ) diff --git a/R/workbook.writeNamedRegion.R b/R/workbook.writeNamedRegion.R index 35852a01..6e17676d 100644 --- a/R/workbook.writeNamedRegion.R +++ b/R/workbook.writeNamedRegion.R @@ -27,15 +27,15 @@ ############################################################################# setGeneric("writeNamedRegion", - function(object, data, name, header = TRUE, overwriteFormulaCells = TRUE, rownames = NULL) standardGeneric("writeNamedRegion")) + function(object, data, name, header = TRUE, overwriteFormulaCells = TRUE, rownames = NULL, worksheetScope = NULL) standardGeneric("writeNamedRegion")) setMethod("writeNamedRegion", signature(object = "workbook", data = "ANY"), - function(object, data, name, header = TRUE, overwriteFormulaCells = TRUE, rownames = NULL) { + function(object, data, name, header = TRUE, overwriteFormulaCells = TRUE, rownames = NULL, worksheetScope = NULL) { data <- includeRownames(data, rownames) # pass data.frame's to Java - construct RDataFrameWrapper Java object references data <- lapply(wrapList(data), dataframeToJava) - xlcCall(object, "writeNamedRegion", data, name, header, overwriteFormulaCells, .simplify = FALSE) + xlcCall(object, "writeNamedRegion", data, name, header, overwriteFormulaCells, worksheetScope %||% .jnull(), .simplify = FALSE) invisible() } ) diff --git a/R/writeNamedRegionToFile.R b/R/writeNamedRegionToFile.R index 11762c87..2ccc3960 100644 --- a/R/writeNamedRegionToFile.R +++ b/R/writeNamedRegionToFile.R @@ -1,51 +1,54 @@ -############################################################################# -# -# XLConnect -# Copyright (C) 2010-2024 Mirai Solutions GmbH -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -############################################################################# - -############################################################################# -# -# Wrapper function to write data to an Excel file in one line. -# -# Author: Thomas Themel, Mirai Solutions GmbH -# -############################################################################# - - -writeNamedRegionToFile <- function(file, data, name, formula = NA, ..., - styleAction = XLC$STYLE_ACTION.XLCONNECT,clearNamedRegions=FALSE) { - - wb <- loadWorkbook(file, create = !file.exists(file)) - setStyleAction(wb, styleAction) - - # clear existing named regions - existingNames <- getDefinedNames(wb) - toClear <- intersect(name[clearNamedRegions], existingNames) - clearNamedRegion(wb, toClear) - - if(!is.na(formula)) { - sheets = extractSheetName(formula) - createSheet(wb, sheets[sheets != ""]) - createName(wb, name, formula) - } - - writeNamedRegion(wb, data, name, ...) - - saveWorkbook(wb) - invisible(wb) -} +############################################################################# +# +# XLConnect +# Copyright (C) 2010-2024 Mirai Solutions GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +############################################################################# + +############################################################################# +# +# Wrapper function to write data to an Excel file in one line. +# +# Author: Thomas Themel, Mirai Solutions GmbH +# +############################################################################# + + +writeNamedRegionToFile <- function(file, data, name, formula = NA , ..., worksheetScope = NULL, + styleAction = XLC$STYLE_ACTION.XLCONNECT,clearNamedRegions=FALSE) { + + wb <- loadWorkbook(file, create = !file.exists(file)) + setStyleAction(wb, styleAction) + + # clear existing named regions + nameExists <- existsName(wb, name, worksheetScope = worksheetScope) + clearExistingName <- function(n, wsScope, clearExisting) { + if(clearExisting) clearNamedRegion(wb, n, worksheetScope = wsScope) + } + mapply(clearExistingName, name, worksheetScope %||% list(NULL), nameExists & clearNamedRegions) + + + if(!is.na(formula)) { + sheets = extractSheetName(formula) + createSheet(wb, sheets[sheets != ""]) + createName(wb, name, formula, worksheetScope = worksheetScope) + } + + writeNamedRegion(wb, data, name, worksheetScope = worksheetScope, ...) + + saveWorkbook(wb) + invisible(wb) +} diff --git a/R/xlcAttributesCall.R b/R/xlcAttributesCall.R new file mode 100644 index 00000000..ea08bfb1 --- /dev/null +++ b/R/xlcAttributesCall.R @@ -0,0 +1,80 @@ +############################################################################# +# +# XLConnect +# Copyright (C) 2010-2021 Mirai Solutions GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +############################################################################# + +############################################################################# +# +# Utility function for vectorizing argument lists and default Java exception +# handling (jTryCatch) +# +# Atomic objects are replicated as is, others are wrapped in a list as defined +# by wrapList and then replicated +# +# Author: Martin Studer, Mirai Solutions GmbH +# +############################################################################# + +xlcAttributesCall <- + function(obj, + fun, + ..., + .recycle = TRUE, + .simplify = TRUE) { + res <- xlcCall(obj, fun, ..., .recycle = TRUE, .simplify = TRUE) + definedNames <- names(res)[!is.na(names(res))] + names(res) <- rep(definedNames, length.out = length(names(res))) + + jni <- mapply(function(resw) { + .jcall(resw, "S", "jni") + }, res) + + unwrapped <- mapply(function(resw, jtype) { + .jcall(resw, jtype, "getValue") + }, res, jni) + + allANames = unique(Reduce(function(resw1, resw2) { + append( + .jcall(resw1, "[S", "getAttributeNames"), + .jcall(resw2, "[S", "getAttributeNames") + ) + }, res)) + + + attributeRows <- Map(function(aName) { + Map(function(resw) { + thev <- .jcall(resw, "S", "getAttributeValue", aName) + if (is.null(thev)) + NA + else + thev + }, res) + }, allANames) + + attrMtx <- Reduce(rbind, attributeRows) + if (length(allANames) > 1) { + colnames(attrMtx) <- allANames + + Map(function(aName) { + attr(unwrapped, aName) <- attrMtx[, aName] + }, allANames) + } + else + attr(unwrapped, allANames[1]) <- attrMtx + unwrapped + } \ No newline at end of file diff --git a/R/xlcCall.R b/R/xlcCall.R index 20e6fbc1..1bfb966d 100644 --- a/R/xlcCall.R +++ b/R/xlcCall.R @@ -31,22 +31,39 @@ ############################################################################# xlcCall <- function(obj, fun, ..., .recycle = TRUE, .simplify = TRUE, - .checkWarnings = TRUE) { - f = eval(parse(text = paste("obj@jobj$", fun, sep = ""))) + .checkWarnings = TRUE, .withAttributes = FALSE) { + + g = eval(parse(text = paste("obj@jobj$", fun, sep = ""))) + f <- if (.withAttributes) function(...) withAttributesFromJava(g(...)) else g args <- list(...) - if(.recycle) { - args <- lapply(args, function(x) { - if(is.atomic(x)) x - else wrapList(x) - }) - res = jTryCatch(do.call("mapply", args = c(FUN = f, args, SIMPLIFY = .simplify))) + + if (.recycle) { + args <- lapply(args, function(x) { + if (is.atomic(x)) x + else wrapList(x) + }) + + res = jTryCatch(do.call("mapply", args = c(FUN = f, args, SIMPLIFY = FALSE))) + + if (.simplify) { + if (.withAttributes) { + res_attr <- Reduce(function(atts1, atts2) { + aNames <- unique(c(names(atts1), names(atts2))) + sapply(aNames, function(aName) { list(c(atts1[aName][[1]], atts2[aName][[1]])) }) + } ,lapply(res, attributes)) + res <- simplify2array(res) + attributes(res) <- res_attr + } else { + res <- simplify2array(res) + } + } } else { - res = jTryCatch(do.call(f, args)) + res = jTryCatch(do.call(f, args)) } - + if (.checkWarnings) { - warnings = .jcall(obj@jobj, "[S", "retrieveWarnings") - for(w in warnings) warning(w, call. = FALSE) + warnings = .jcall(obj@jobj, "[S", "retrieveWarnings") + for(w in warnings) warning(w, call. = FALSE) } res diff --git a/R/xlcOperators.R b/R/xlcOperators.R new file mode 100644 index 00000000..1cc89039 --- /dev/null +++ b/R/xlcOperators.R @@ -0,0 +1,34 @@ +############################################################################# +# +# XLConnect +# Copyright (C) 2010-2021 Mirai Solutions GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +############################################################################# +############################################################################# +# +# Operators used internally +# +# +############################################################################# + +# Replace `NULL` with a default value +# +# Operator that replaces the left-hand side with the right-hand side if the +# left-hand side is NULL. +# +`%||%` <- function(x, y) { + if (is.null(x)) y else x +} diff --git a/R/xlcWithAttributesCall.R b/R/xlcWithAttributesCall.R new file mode 100644 index 00000000..ed945fe7 --- /dev/null +++ b/R/xlcWithAttributesCall.R @@ -0,0 +1,63 @@ +############################################################################# +# +# XLConnect +# Copyright (C) 2010-2021 Mirai Solutions GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +############################################################################# + +############################################################################# +# +# Utility function for vectorizing argument lists and default Java exception +# handling (jTryCatch) +# +# Atomic objects are replicated as is, others are wrapped in a list as defined +# by wrapList and then replicated +# +# Extracts attributes from a wrapper Java type and sets them on the R object. +# +# Author: Martin Studer & Simon Poltier, Mirai Solutions GmbH +# +############################################################################# + +xlcWithAttributesCall <- function(obj, fun, ..., .recycle = TRUE, .simplify = TRUE, .checkWarnings = TRUE) { + g = eval(parse(text = paste("obj@jobj$", fun, sep = ""))) + f <- function(...) withAttributesFromJava(g(...)) + args <- list(...) + if(.recycle) { + args <- lapply(args, function(x) { + if(is.atomic(x)) x + else wrapList(x) + }) + res = jTryCatch(do.call("mapply", args = c(FUN = f, args, SIMPLIFY = FALSE))) + if(.simplify) { + res_attr <- Reduce(function(atts1, atts2) { + aNames <- unique(c(names(atts1), names(atts2))) + sapply(aNames, function(aName) { list(c(atts1[aName][[1]], atts2[aName][[1]])) }) + } ,lapply(res, attributes)) + res <- simplify2array(res) + attributes(res) <- res_attr + } + } else { + res = jTryCatch(do.call(f, args)) + } + + if (.checkWarnings) { + warnings = .jcall(obj@jobj, "[S", "retrieveWarnings") + for(w in warnings) warning(w, call. = FALSE) + } + + res +} diff --git a/inst/java/XLConnect-2.0.0-SNAPSHOT.jar b/inst/java/XLConnect-2.0.0-SNAPSHOT.jar index 874704ec..41407dba 100644 Binary files a/inst/java/XLConnect-2.0.0-SNAPSHOT.jar and b/inst/java/XLConnect-2.0.0-SNAPSHOT.jar differ diff --git a/inst/unitTests/resources/test37.xlsx b/inst/unitTests/resources/test37.xlsx new file mode 100644 index 00000000..7737684e Binary files /dev/null and b/inst/unitTests/resources/test37.xlsx differ diff --git a/inst/unitTests/resources/testWorkbookCloneSheet.xls b/inst/unitTests/resources/testWorkbookCloneSheet.xls index feea71c1..fea42428 100644 Binary files a/inst/unitTests/resources/testWorkbookCloneSheet.xls and b/inst/unitTests/resources/testWorkbookCloneSheet.xls differ diff --git a/inst/unitTests/runit.workbook.clearNamedRegion.R b/inst/unitTests/runit.workbook.clearNamedRegion.R index c21f9cdf..7d53e176 100644 --- a/inst/unitTests/runit.workbook.clearNamedRegion.R +++ b/inst/unitTests/runit.workbook.clearNamedRegion.R @@ -1,55 +1,74 @@ -############################################################################# -# -# XLConnect -# Copyright (C) 2010-2024 Mirai Solutions GmbH -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -############################################################################# - -############################################################################# -# -# Tests around clearing named regions from an Excel Workbook -# -# Author: Nicola Lambiase, Mirai Solutions GmbH -# -############################################################################# - -test.workbook.clearNamedRegion <- function() { - - # Create workbooks - wb.xls <- loadWorkbook(rsrc("resources/testWorkbookClearCells.xls"), create = FALSE) - wb.xlsx <- loadWorkbook(rsrc("resources/testWorkbookClearCells.xlsx"), create = FALSE) - - checkDf <- data.frame( - "one" = 1:5, - "two" = 6:10, - "three" = 11:15, - "four" = 16:20, - "five" = 21:25, - "six" = 26:30, - "seven" = 31:35, - stringsAsFactors = F - ) - - # Check that clearing 2 of 3 named regions in a sheet returns only the third one (*.xls) - clearNamedRegion(wb.xls, c("region1", "region2")) - res <- readWorksheet(wb.xls, "clearNamedRegion", header = TRUE) - checkEquals(res, checkDf) - - # Check that clearing 2 of 3 named regions in a sheet returns only the third one (*.xlsx) - clearNamedRegion(wb.xlsx, c("region1", "region2")) - res <- readWorksheet(wb.xlsx, "clearNamedRegion", header = TRUE) - checkEquals(res, checkDf) -} +############################################################################# +# +# XLConnect +# Copyright (C) 2010-2024 Mirai Solutions GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +############################################################################# + +############################################################################# +# +# Tests around clearing named regions from an Excel Workbook +# +# Author: Nicola Lambiase, Mirai Solutions GmbH +# +############################################################################# + +test.workbook.clearNamedRegion <- function() { + + # Create workbooks + wb.xls <- loadWorkbook(rsrc("resources/testWorkbookClearCells.xls"), create = FALSE) + wb.xlsx <- loadWorkbook(rsrc("resources/testWorkbookClearCells.xlsx"), create = FALSE) + + checkDf <- data.frame( + "one" = 1:5, + "two" = 6:10, + "three" = 11:15, + "four" = 16:20, + "five" = 21:25, + "six" = 26:30, + "seven" = 31:35, + stringsAsFactors = F + ) + + # Check that clearing 2 of 3 named regions in a sheet returns only the third one (*.xls) + clearNamedRegion(wb.xls, c("region1", "region2")) + res <- readWorksheet(wb.xls, "clearNamedRegion", header = TRUE) + checkEquals(res, checkDf) + + # Check that clearing 2 of 3 named regions in a sheet returns only the third one (*.xlsx) + clearNamedRegion(wb.xlsx, c("region1", "region2")) + res <- readWorksheet(wb.xlsx, "clearNamedRegion", header = TRUE) + checkEquals(res, checkDf) + + #reset + wb.xls <- loadWorkbook(rsrc("resources/testWorkbookClearCells.xls"), create = FALSE) + wb.xlsx <- loadWorkbook(rsrc("resources/testWorkbookClearCells.xlsx"), create = FALSE) + + # check that specifying the worksheet name doesn't find globally scoped names + checkException(clearNamedRegion(wb.xls, c("region1", "region2"), worksheetScope = "clearNamedRegion")) + + # Check that clearing 2 of 3 named regions in a sheet returns only the third one (*.xls) + clearNamedRegion(wb.xls, c("region1", "region2")) + res <- readWorksheet(wb.xls, "clearNamedRegion", header = TRUE) + checkEquals(res, checkDf) + + # Check that clearing 2 of 3 named regions in a sheet returns only the third one (*.xlsx) + clearNamedRegion(wb.xlsx, c("region1", "region2")) + res <- readWorksheet(wb.xlsx, "clearNamedRegion", header = TRUE) + checkEquals(res, checkDf) + + +} diff --git a/inst/unitTests/runit.workbook.cloneSheet.R b/inst/unitTests/runit.workbook.cloneSheet.R index dda06c01..05f19269 100644 --- a/inst/unitTests/runit.workbook.cloneSheet.R +++ b/inst/unitTests/runit.workbook.cloneSheet.R @@ -1,56 +1,57 @@ -############################################################################# -# -# XLConnect -# Copyright (C) 2010-2024 Mirai Solutions GmbH -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -############################################################################# - -############################################################################# -# -# Tests around cloning Excel worksheets -# -# Author: Martin Studer, Mirai Solutions GmbH -# -############################################################################# - -test.workbook.cloneSheet <- function() { - - # Create workbooks - wb.xls <- loadWorkbook(rsrc("resources/testWorkbookCloneSheet.xls"), create = FALSE) - wb.xlsx <- loadWorkbook(rsrc("resources/testWorkbookCloneSheet.xlsx"), create = FALSE) - - # Check cloning of worksheet (*.xls) - checkNoException(cloneSheet(wb.xls, sheet = "Test1", name = "Clone1")) - checkNoException(readWorksheet(wb.xls, sheet = "Clone1")) - - # Check cloning of worksheet (*.xlsx) - checkNoException(cloneSheet(wb.xlsx, sheet = "Test1", name = "Clone1")) - checkNoException(readWorksheet(wb.xlsx, sheet = "Clone1")) - - # Check that attempting to clone a non-existing worksheet throws an exception (*.xls) - checkException(cloneSheet(wb.xls, sheet = "NotThere", name = "MyClone")) - - # Check that attempting to clone a non-existing worksheet throws an exception (*.xlsx) - checkException(cloneSheet(wb.xlsx, sheet = "NotThere", name = "MyClone")) - - # Check that attempting to assign an invalid name to a cloned sheet throws an exception (*.xls) - checkException(cloneSheet(wb.xls, sheet = "Test1", name = "'illegal")) - - # Check that attempting to assign an invalid name to a cloned sheet throws an exception (*.xlsx) - checkException(cloneSheet(wb.xlsx, sheet = "Test1", name = "'illegal")) - -} - +############################################################################# +# +# XLConnect +# Copyright (C) 2010-2024 Mirai Solutions GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +############################################################################# + +############################################################################# +# +# Tests around cloning Excel worksheets +# +# Author: Martin Studer, Mirai Solutions GmbH +# +############################################################################# + +test.workbook.cloneSheet <- function() { + + # Create workbooks + wb.xls <- loadWorkbook(rsrc("resources/testWorkbookCloneSheet.xls"), create = FALSE) + wb.xlsx <- loadWorkbook(rsrc("resources/testWorkbookCloneSheet.xlsx"), create = FALSE) + + # Check cloning of worksheet (*.xls) + checkNoException(cloneSheet(wb.xls, sheet = "Test1", name = "Clone1")) + checkNoException(readWorksheet(wb.xls, sheet = "Clone1")) + checkNoException(readNamedRegion(wb.xls, 'testName', worksheetScope = 'Clone1')) + + # Check cloning of worksheet (*.xlsx) + checkNoException(cloneSheet(wb.xlsx, sheet = "Test1", name = "Clone1")) + checkNoException(readWorksheet(wb.xlsx, sheet = "Clone1")) + + # Check that attempting to clone a non-existing worksheet throws an exception (*.xls) + checkException(cloneSheet(wb.xls, sheet = "NotThere", name = "MyClone")) + + # Check that attempting to clone a non-existing worksheet throws an exception (*.xlsx) + checkException(cloneSheet(wb.xlsx, sheet = "NotThere", name = "MyClone")) + + # Check that attempting to assign an invalid name to a cloned sheet throws an exception (*.xls) + checkException(cloneSheet(wb.xls, sheet = "Test1", name = "'illegal")) + + # Check that attempting to assign an invalid name to a cloned sheet throws an exception (*.xlsx) + checkException(cloneSheet(wb.xlsx, sheet = "Test1", name = "'illegal")) + +} + diff --git a/inst/unitTests/runit.workbook.createName.R b/inst/unitTests/runit.workbook.createName.R index 4075532d..b98ef610 100644 --- a/inst/unitTests/runit.workbook.createName.R +++ b/inst/unitTests/runit.workbook.createName.R @@ -35,12 +35,12 @@ test.workbook.createName <- function() { # Check that creating a legal name works ok (*.xls) # (this test assumes 'existsName' is working fine) createName(wb.xls, "Test", "Test!$C$5") - checkTrue(existsName(wb.xls, "Test")) + checkEquals(existsName(wb.xls, "Test"), TRUE, check.attributes = FALSE) # Check that creating a legal name works ok (*.xlsx) # (this test assumes 'existsName' is working fine) createName(wb.xlsx, "Test", "Test!$C$5") - checkTrue(existsName(wb.xlsx, "Test")) + checkEquals(existsName(wb.xlsx, "Test"), TRUE, check.attributes = FALSE) # Check that trying to create an illegal name throws # an exception (*.xls) @@ -72,19 +72,19 @@ test.workbook.createName <- function() { createName(wb.xls, "CurrentlyHere", "CurrentlyHere!$D$8") createName(wb.xls, "CurrentlyHere", "NowThere!$C$3", overwrite = TRUE) # TODO: Should actually rather check that new formula is correct - checkTrue(existsName(wb.xls, "CurrentlyHere")) + checkEquals(existsName(wb.xls, "CurrentlyHere"), TRUE, check.attributes = FALSE) # Check that overwriting an existing name works ok (*.xlsx) createName(wb.xlsx, "CurrentlyHere", "CurrentlyHere!$D$8") createName(wb.xlsx, "CurrentlyHere", "NowThere!$C$3", overwrite = TRUE) # TODO: Should actually rather check that new formula is correct - checkTrue(existsName(wb.xlsx, "CurrentlyHere")) + checkEquals(existsName(wb.xlsx, "CurrentlyHere"), TRUE, check.attributes = FALSE) # Check that after trying to write a name with an illegal formula # (which throws an exception), the name remains available (*.xls) checkException(createName(wb.xls, "aName", "Test!A1A4")) checkNoException(createName(wb.xls, "aName", "Test!A1")) - checkTrue(existsName(wb.xls, "aName")) + checkEquals(existsName(wb.xls, "aName"), TRUE, check.attributes = FALSE) # Check that after trying to write a name with an illegal formula # (which throws an exception), the name remains available (*.xlsx) @@ -93,6 +93,6 @@ test.workbook.createName <- function() { # name with an invalid formula does not throw an exception anymore! # checkException(createName(wb.xlsx, "aName", "Test!A1A4")) # checkNoException(createName(wb.xlsx, "aName", "Test!A1")) - # checkTrue(existsName(wb.xlsx, "aName")) + # checkEquals(existsName(wb.xlsx, "aName"), TRUE, check.attributes = FALSE) } diff --git a/inst/unitTests/runit.workbook.existsName.R b/inst/unitTests/runit.workbook.existsName.R index b185d517..4280b36c 100644 --- a/inst/unitTests/runit.workbook.existsName.R +++ b/inst/unitTests/runit.workbook.existsName.R @@ -33,22 +33,24 @@ test.workbook.existsName <- function() { wb.xlsx <- loadWorkbook(rsrc("resources/testWorkbookExistsNameAndSheet.xlsx"), create = FALSE) # Check that the following names exists (*.xls) - checkTrue(existsName(wb.xls, "AA")) - checkTrue(existsName(wb.xls, "BB")) - checkTrue(existsName(wb.xls, "CC")) + checkEquals(existsName(wb.xls, "AA"), TRUE, check.attributes = FALSE) + checkEquals(existsName(wb.xls, "BB"), TRUE, check.attributes = FALSE) + checkEquals(existsName(wb.xls, "CC"), TRUE, check.attributes = FALSE) # Check that the following do NOT exists (*.xls) - checkTrue(!existsName(wb.xls, "DD")) - checkTrue(!existsName(wb.xls, "'illegal name")) - checkTrue(!existsName(wb.xls, "%&$$-^~@afk20 235-??a?")) + checkEquals(existsName(wb.xls, "DD"), FALSE, check.attributes = FALSE) + checkEquals(existsName(wb.xls, "'illegal name"), FALSE, check.attributes = FALSE) + checkEquals(existsName(wb.xls, "%&$$-^~@afk20 235-??a?"), FALSE, check.attributes = FALSE) # Check that the following names exists (*.xlsx) - checkTrue(existsName(wb.xlsx, "AA")) - checkTrue(existsName(wb.xlsx, "BB")) - checkTrue(existsName(wb.xlsx, "CC")) + checkEquals(existsName(wb.xlsx, "AA"), TRUE, check.attributes = FALSE) + checkEquals(existsName(wb.xlsx, "BB"), TRUE, check.attributes = FALSE) + checkEquals(existsName(wb.xlsx, "CC"), TRUE, check.attributes = FALSE) # Check that the following do NOT exists (*.xlsx) - checkTrue(!existsName(wb.xlsx, "DD")) - checkTrue(!existsName(wb.xlsx, "'illegal name")) - checkTrue(!existsName(wb.xlsx, "%&$$-^~@afk20 235-??a?")) + checkEquals(existsName(wb.xlsx, "DD"), FALSE, check.attributes = FALSE) + checkEquals(existsName(wb.xlsx, "'illegal name"), FALSE, check.attributes = FALSE) + checkEquals(existsName(wb.xlsx, "%&$$-^~@afk20 235-??a?"), FALSE, check.attributes = FALSE) + + # TODO check with attributes - where was the name found ? } diff --git a/inst/unitTests/runit.workbook.readNamedRegion.R b/inst/unitTests/runit.workbook.readNamedRegion.R index b3d2b6bc..de0c7cfe 100644 --- a/inst/unitTests/runit.workbook.readNamedRegion.R +++ b/inst/unitTests/runit.workbook.readNamedRegion.R @@ -47,6 +47,15 @@ test.workbook.readNamedRegion <- function() { # Check that the read named region equals the defined data.frame (*.xlsx) res <- readNamedRegion(wb.xlsx, "Test", header = TRUE) checkEquals(res, checkDf) + + # Check that the same works when explicitly specifying global scope (*.xls) + res <- readNamedRegion(wb.xls, "Test", header = TRUE, worksheetScope = "") + checkEquals(res, checkDf) + + # Check that the same works when explicitly specifying global scope (*.xlsx) + res <- readNamedRegion(wb.xlsx, "Test", header = TRUE, worksheetScope = "") + checkEquals(res, checkDf) + # Check that attempting to read a non-existing named region throws an exception (*.xls) checkException(readNamedRegion(wb.xls, "NameThatDoesNotExist")) @@ -387,4 +396,18 @@ test.workbook.readNamedRegion <- function() { expected = data.frame(B = 1:5, row.names = letters[1:5]) res <- readNamedRegionFromFile(rsrc("resources/testBug49.xlsx"), name = "test", rownames = "A") checkEquals(expected, res) + + # Check that named region can be read within a worksheet scope (see github issue #37) + + wb37xlsx <- loadWorkbook(rsrc("resources/test37.xlsx"), create = FALSE) + read1 <- readNamedRegion(wb37xlsx, 'Bla', worksheetScope = 'Sheet1') + read2 <- readNamedRegion(wb37xlsx, 'Bla', worksheetScope = 'Sheet2') + checkEquals(colnames(read1), c("bla1")) + checkEquals(colnames(read2), c("bla2")) + readBoth <- readNamedRegion(wb37xlsx, 'Bla', worksheetScope = c('Sheet1', 'Sheet2')) + checkEquals(colnames(readBoth[[1]]), 'bla1') + checkEquals(colnames(readBoth[[2]]), 'bla2') + + checkException(readNamedRegion(wb37xlsx, 'Bla', worksheetScope = 'Sheet3')) } + diff --git a/inst/unitTests/runit.writeAndReadNamedRegion.R b/inst/unitTests/runit.writeAndReadNamedRegion.R index ed69330b..c11b4978 100644 --- a/inst/unitTests/runit.writeAndReadNamedRegion.R +++ b/inst/unitTests/runit.writeAndReadNamedRegion.R @@ -36,12 +36,32 @@ test.writeAndReadNamedRegion <- function() { testDataFrame <- function(wb, df, lref) { namedRegion <- deparse(substitute(df)) createSheet(wb, name = namedRegion) - createName(wb, name = namedRegion, formula = paste(namedRegion, lref, sep = "!")) - writeNamedRegion(wb, df, name = namedRegion, header = TRUE) - res <- readNamedRegion(wb, namedRegion) + createName(wb, name = namedRegion, formula = paste(namedRegion, lref, sep = "!"), worksheetScope = namedRegion) + writeNamedRegion(wb, df, name = namedRegion, worksheetScope = namedRegion, header = TRUE) + res <- readNamedRegion(wb, namedRegion, worksheetScope = namedRegion) checkEquals(normalizeDataframe(df, replaceInf = TRUE), res, check.attributes = FALSE, check.names = TRUE) } + testDataFrameNameScope <- function(wb, df, lref) { + namedRegion <- paste(deparse(substitute(df)), "1", sep = "") + worksheetScopeName <- paste(namedRegion, "2", sep = "") + createSheet(wb, name = namedRegion) + createSheet(wb, name = worksheetScopeName) + createName(wb, name = namedRegion, formula = paste(namedRegion, lref, sep = "!"), worksheetScope = worksheetScopeName) + writeNamedRegion(wb, df, name = namedRegion, worksheetScope = worksheetScopeName, header = TRUE) + res <- readNamedRegion(wb, namedRegion, worksheetScope = worksheetScopeName) + checkEquals(normalizeDataframe(df, replaceInf = TRUE), res, check.attributes = FALSE, check.names = TRUE) + } + + testDataFrameGlobalExplicit <- function(wb, df, lref) { + namedRegion <- paste(deparse(substitute(df)), "forGlobal", sep = "") + createSheet(wb, name = namedRegion) + createName(wb, name = namedRegion, formula = paste(namedRegion, lref, sep = "!"), worksheetScope = "") + writeNamedRegion(wb, df, name = namedRegion, worksheetScope = "", header = TRUE) + res <- readNamedRegion(wb, namedRegion, worksheetScope = "") + checkEquals(normalizeDataframe(df, replaceInf = TRUE), res, check.attributes = FALSE, check.names = TRUE) + } + if(getOption("FULL.TEST.SUITE")) { # built-in dataset mtcars (*.xls) testDataFrame(wb.xls, mtcars, "$C$8") @@ -58,11 +78,21 @@ test.writeAndReadNamedRegion <- function() { # built-in dataset attenu (*.xlsx) testDataFrame(wb.xlsx, attenu, "$A$8") + # built-in dataset attenu (*.xls) - explicit global scope + testDataFrameGlobalExplicit(wb.xls, attenu, "$A$8") + # built-in dataset attenu (*.xlsx) - explicit global scope + testDataFrameGlobalExplicit(wb.xlsx, attenu, "$A$8") + # built-in dataset ChickWeight (*.xls) testDataFrame(wb.xls, ChickWeight, "$BQ$7") # built-in dataset ChickWeight (*.xlsx) testDataFrame(wb.xlsx, ChickWeight, "$BQ$7") + # built-in dataset ChickWeight (*.xls) - explicit global scope + testDataFrameGlobalExplicit(wb.xls, ChickWeight, "$BQ$7") + # built-in dataset ChickWeight (*.xlsx) - explicit global scope + testDataFrameGlobalExplicit(wb.xlsx, ChickWeight, "$BQ$7") + # built-in dataset CO2 (*.xls) CO = CO2 # CO2 seems to be an illegal name testDataFrame(wb.xls, CO, "$L$1") @@ -84,10 +114,20 @@ test.writeAndReadNamedRegion <- function() { # built-in dataset morley (*.xlsx) testDataFrame(wb.xlsx, morley, "$K$4") + # built-in dataset morley (*.xls) + testDataFrameNameScope(wb.xls, morley, "$K$4") + # built-in dataset morley (*.xlsx) + testDataFrameNameScope(wb.xlsx, morley, "$K$4") + # built-in dataset swiss (*.xls) testDataFrame(wb.xls, swiss, "$M$2") # built-in dataset swiss (*.xlsx) testDataFrame(wb.xlsx, swiss, "$M$2") + + # built-in dataset swiss (*.xls) + testDataFrameNameScope(wb.xls, swiss, "$M$2") + # built-in dataset swiss (*.xlsx) + testDataFrameNameScope(wb.xlsx, swiss, "$M$2") } # custom test dataset diff --git a/inst/unitTests/runit.writeNamedRegionToFile.R b/inst/unitTests/runit.writeNamedRegionToFile.R index ec2fbd67..010581f5 100644 --- a/inst/unitTests/runit.writeNamedRegionToFile.R +++ b/inst/unitTests/runit.writeNamedRegionToFile.R @@ -139,7 +139,6 @@ test.writeNamedRegionToFile <- function() { formula = "'My Cars'!$A$1", header = TRUE)) checkTrue(file.exists(file2.xlsx)) - # test clearNamedRegions testClearNamedRegions <- function(file, df) { df.short <- df[1,] @@ -155,10 +154,46 @@ test.writeNamedRegionToFile <- function() { # overwrite name with shorter version & clearing writeNamedRegionToFile(file, data=df.short, name="cdfRegion", clearNamedRegions=TRUE) # should be cleared - #checkEquals(nrow(readNamedRegionFromFile(file, name="cdfRegion")), 1) - #checkEquals(nrow(readWorksheetFromFile(file, sheet="cdf")), 1) + checkEquals(nrow(readNamedRegionFromFile(file, name="cdfRegion")), 1) + checkEquals(nrow(readWorksheetFromFile(file, sheet="cdf")), 1) } testClearNamedRegions(file.xls, cdf) testClearNamedRegions(file.xlsx, cdf) + + testClearNamedRegionsScoped <- function(file, df) { + scope <- c('scope1', 'scope2') + clearParam <- c(TRUE, FALSE) + df.short <- df[1,] + + wb <- loadWorkbook(file, create = TRUE) + createSheet(wb, scope) + saveWorkbook(wb, file) + + writeNamedRegionToFile(file, data=df, name="cdfRegionScoped", formula=paste(scope[1], "A1", sep="!"), worksheetScope = scope[1]) + writeNamedRegionToFile(file, data=df, name="cdfRegionScoped", formula=paste(scope[2], "A1", sep="!"), worksheetScope = scope[2]) + # overwrite named region with shorter version + writeNamedRegionToFile(file, data=df.short, name="cdfRegionScoped", worksheetScope = scope) + # default behaviour: not cleared, only named region is shortened + checkEquals(nrow(readNamedRegionFromFile(file, name="cdfRegionScoped", worksheetScope = scope)[[1]]), 1) + checkEquals(nrow(readNamedRegionFromFile(file, name="cdfRegionScoped", worksheetScope = scope)[[2]]), 1) + checkEquals(nrow(readWorksheetFromFile(file, sheet=scope)[[1]]), nrow(df)) + checkEquals(nrow(readWorksheetFromFile(file, sheet=scope)[[2]]), nrow(df)) + + # rewrite longer version + writeNamedRegionToFile(file, data=df, name="cdfRegionScoped", worksheetScope = scope) + # overwrite name with shorter version & clearing + writeNamedRegionToFile(file, data=df.short, name="cdfRegionScoped", clearNamedRegions=clearParam, worksheetScope = scope) + # should be cleared + checkEquals(nrow(readNamedRegionFromFile(file, name="cdfRegionScoped", worksheetScope = scope)[[1]]), 1) + checkEquals(nrow(readNamedRegionFromFile(file, name="cdfRegionScoped", worksheetScope = scope)[[2]]), 1) + checkEquals(nrow(readWorksheetFromFile(file, sheet=scope)[[1]]), 1) + checkEquals(nrow(readWorksheetFromFile(file, sheet=scope)[[2]]), nrow(df)) + } + + scopedfile.xls <- "testWriteNamedRegionToFileWorkbookScoped.xls" + scopedfile.xlsx <- "testWriteNamedRegionToFileWorkbookScoped.xlsx" + + testClearNamedRegionsScoped(scopedfile.xls, cdf) + testClearNamedRegionsScoped(scopedfile.xlsx, cdf) } diff --git a/man/addImage-methods.Rd b/man/addImage-methods.Rd index 6c3503bf..a951688a 100644 --- a/man/addImage-methods.Rd +++ b/man/addImage-methods.Rd @@ -8,7 +8,7 @@ Adds an image to a worksheet using a named region. } \usage{ - \S4method{addImage}{workbook}(object, filename, name, originalSize) + \S4method{addImage}{workbook}(object, filename, name, originalSize, worksheetScope) } \arguments{ @@ -20,6 +20,8 @@ Adds an image to a worksheet using a named region. inserted in the top left corner of the named region and not scaled. Otherwise, the image is scaled to fit the named region. The default value for \code{originalSize} is \code{FALSE}.} + \item{worksheetScope}{Optional - the name of the worksheet in which the name is scoped; + useful if different sheets have scoped regions with the same name.} } \author{ diff --git a/man/clearNamedRegion-methods.Rd b/man/clearNamedRegion-methods.Rd index a817dc19..ef075ef8 100644 --- a/man/clearNamedRegion-methods.Rd +++ b/man/clearNamedRegion-methods.Rd @@ -1,65 +1,71 @@ -\name{clearNamedRegion-methods} -\docType{methods} -\alias{clearNamedRegion} -\alias{clearNamedRegion-methods} -\alias{clearNamedRegion,workbook,character-method} -\title{Clearing named regions in a workbook} -\description{ -Clears named regions in a \code{\linkS4class{workbook}}. -} -\usage{ - \S4method{clearNamedRegion}{workbook,character}(object, name) -} - -\arguments{ - \item{object}{The \code{\linkS4class{workbook}} to use} - \item{name}{The name of the named region to clear} -} - -\details{ -Clearing a named region/range means to clear all the cells associated with that named -region. Clearing named regions can be useful if (named) data sets in a worksheet need -to be replaced, i.e. data is first read, modified in R and finally written back to the -the same named region. Without clearing the named region first, (parts of) the original -data may still be visible if they occupied a larger range in the worksheet. -} - -\author{ -Nicola Lambiase\cr -Mirai Solutions GmbH \url{https://mirai-solutions.ch} -} -\seealso{ -\code{\linkS4class{workbook}}, \code{\link[=clearSheet-methods]{clearSheet}}, -\code{\link[=clearRange-methods]{clearRange}}, -\code{\link[=clearRangeFromReference-methods]{clearRangeFromReference}}, -\code{\link[=clearSheet-methods]{clearSheet}} -} -\examples{ - \dontrun{ -# mtcars xlsx file from demoFiles subfolder of -# package XLConnect -demoExcelFile <- system.file("demoFiles/mtcars.xlsx", - package = "XLConnect") - -# Load workbook -wb <- loadWorkbook(demoExcelFile) - -# Read named region 'mtcars' -data <- readNamedRegion(wb, name = "mtcars", header = TRUE) - -# Only consider cars with a weight >= 5 -data <- data[data$wt >= 5, ] - -# Clear original named region -clearNamedRegion(wb, name = "mtcars") - -# Write subsetted data back -# Note: this is covering a smaller area now - -# writeNamedRegion automatically redefines the named region -# to the size/area of the data -writeNamedRegion(wb, data = data, name = "mtcars", - header = TRUE) -} -} -\keyword{methods} -\keyword{utilities} +\name{clearNamedRegion-methods} +\docType{methods} +\alias{clearNamedRegion} +\alias{clearNamedRegion-methods} +\alias{clearNamedRegion,workbook,character-method} +\title{Clearing named regions in a workbook} +\description{ +Clears named regions in a \code{\linkS4class{workbook}}. +} +\usage{ + \S4method{clearNamedRegion}{workbook,character}(object, name, worksheetScope) +} + +\arguments{ + \item{object}{The \code{\linkS4class{workbook}} to use} + \item{name}{The name of the named region to clear} + \item{worksheetScope}{Optional - the name of the worksheet in which the region is scoped; + useful if different sheets have scoped regions with the same name.} +} + +\details{ +Clearing a named region/range means to clear all the cells associated with that named +region. Clearing named regions can be useful if (named) data sets in a worksheet need +to be replaced, i.e. data is first read, modified in R and finally written back to the +the same named region. Without clearing the named region first, (parts of) the original +data may still be visible if they occupied a larger range in the worksheet. + +If \code{worksheetScope} is unspecified, the first matching name found anywhere in the workbook +will be cleared. Otherwise, only a name specifically scoped to the worksheet may be cleared. +To only clear a name in global scope, pass \code{""} as the value. +} + +\author{ +Nicola Lambiase\cr +Mirai Solutions GmbH \url{https://mirai-solutions.ch} +} +\seealso{ +\code{\linkS4class{workbook}}, \code{\link[=clearSheet-methods]{clearSheet}}, +\code{\link[=clearRange-methods]{clearRange}}, +\code{\link[=clearRangeFromReference-methods]{clearRangeFromReference}}, +\code{\link[=clearSheet-methods]{clearSheet}} +} +\examples{ + \dontrun{ +# mtcars xlsx file from demoFiles subfolder of +# package XLConnect +demoExcelFile <- system.file("demoFiles/mtcars.xlsx", + package = "XLConnect") + +# Load workbook +wb <- loadWorkbook(demoExcelFile) + +# Read named region 'mtcars' +data <- readNamedRegion(wb, name = "mtcars", header = TRUE) + +# Only consider cars with a weight >= 5 +data <- data[data$wt >= 5, ] + +# Clear original named region +clearNamedRegion(wb, name = "mtcars") + +# Write subsetted data back +# Note: this is covering a smaller area now - +# writeNamedRegion automatically redefines the named region +# to the size/area of the data +writeNamedRegion(wb, data = data, name = "mtcars", + header = TRUE) +} +} +\keyword{methods} +\keyword{utilities} diff --git a/man/createName-methods.Rd b/man/createName-methods.Rd index 9c19e535..b32778a1 100644 --- a/man/createName-methods.Rd +++ b/man/createName-methods.Rd @@ -1,75 +1,77 @@ -\name{createName-methods} -\docType{methods} -\alias{createName} -\alias{createName-methods} -\alias{createName,workbook-method} -\title{Creating names in a workbook} -\description{ -Creates a name for a specified formula in a \code{\linkS4class{workbook}}. -} -\usage{ -\S4method{createName}{workbook}(object, name, formula, overwrite) -} - -\arguments{ - \item{object}{The \code{\linkS4class{workbook}} to use} - \item{name}{The name's name to create} - \item{formula}{Excel formula specifying the name} - \item{overwrite}{If a name with the same \code{name} already exists - and \code{overwrite = TRUE}, then this name is removed first before - the new one is created. If a name already exists and - \code{overwrite = FALSE}, then an exception is thrown. The default - value for \code{overwrite} is \code{FALSE}.} -} - -\details{ -Creates a name named \code{name} for the specified \code{formula}. - -The \code{formula} should be specified as you would type it -in Excel. Make sure that the worksheets, functions, ... -exist that you are referring to in the \code{formula}. - -The \code{name}, \code{formula} and \code{overwrite} arguments are -vectorized such that multiple names can be created in one method call. -} - -\references{ -What are named regions/ranges?\cr -\url{https://www.officearticles.com/excel/named_ranges_in_microsoft_excel.htm}\cr -How to create named regions/ranges?\cr -\url{https://www.youtube.com/watch?v=iAE9a0uRtpM} -} -\author{ -Martin Studer\cr -Mirai Solutions GmbH \url{https://mirai-solutions.ch} -} -\seealso{ -\code{\linkS4class{workbook}}, -\code{\link[=removeName-methods]{removeName}}, -\code{\link[=existsName-methods]{existsName}}, -\code{\link[=getDefinedNames-methods]{getDefinedNames}},\cr -\code{\link[=readNamedRegion-methods]{readNamedRegion}}, -\code{\link[=writeNamedRegion-methods]{writeNamedRegion}} -} -\examples{\dontrun{ -# Load workbook (create if not existing) -wb <- loadWorkbook("createName.xlsx", create = TRUE) - -# Create a worksheet named 'mtcars' -createSheet(wb, name = "mtcars") - -# Create a named region called 'mtcars' on the sheet called 'mtcars' -createName(wb, name = "mtcars", formula = "mtcars!$A$1") - -# Write built-in data set 'mtcars' to the above defined named region -writeNamedRegion(wb, mtcars, name = "mtcars") - -# Save workbook -saveWorkbook(wb) - -# clean up -file.remove("createName.xlsx") -} -} -\keyword{methods} -\keyword{utilities} +\name{createName-methods} +\docType{methods} +\alias{createName} +\alias{createName-methods} +\alias{createName,workbook-method} +\title{Creating names in a workbook} +\description{ +Creates a name for a specified formula in a \code{\linkS4class{workbook}}. +} +\usage{ +\S4method{createName}{workbook}(object, name, formula, overwrite, worksheetScope) +} + +\arguments{ + \item{object}{The \code{\linkS4class{workbook}} to use} + \item{name}{The name's name to create} + \item{formula}{Excel formula specifying the value / data the name refers to} + \item{overwrite}{If a name with the same \code{name} already exists + and \code{overwrite = TRUE}, then this name is removed first before + the new one is created. If a name already exists and + \code{overwrite = FALSE}, then an exception is thrown. The default + value for \code{overwrite} is \code{FALSE}.} + \item{worksheetScope}{Optional - specific worksheet the name should be scoped to. + If unspecified the name will be scoped to the whole workbook.} +} + +\details{ +Creates a name named \code{name} for the specified \code{formula}. + +The \code{formula} should be specified as you would type it +in Excel. Make sure that the worksheets, functions, ... +exist that you are referring to in the \code{formula}. + +The \code{name}, \code{formula} and \code{overwrite} arguments are +vectorized such that multiple names can be created in one method call. +} + +\references{ +What are named regions/ranges?\cr +\url{https://www.officearticles.com/excel/named_ranges_in_microsoft_excel.htm}\cr +How to create named regions/ranges?\cr +\url{https://www.youtube.com/watch?v=iAE9a0uRtpM} +} +\author{ +Martin Studer\cr +Mirai Solutions GmbH \url{https://mirai-solutions.ch} +} +\seealso{ +\code{\linkS4class{workbook}}, +\code{\link[=removeName-methods]{removeName}}, +\code{\link[=existsName-methods]{existsName}}, +\code{\link[=getDefinedNames-methods]{getDefinedNames}},\cr +\code{\link[=readNamedRegion-methods]{readNamedRegion}}, +\code{\link[=writeNamedRegion-methods]{writeNamedRegion}} +} +\examples{\dontrun{ +# Load workbook (create if not existing) +wb <- loadWorkbook("createName.xlsx", create = TRUE) + +# Create a worksheet named 'mtcars' +createSheet(wb, name = "mtcars") + +# Create a named region called 'mtcars' on the sheet called 'mtcars' +createName(wb, name = "mtcars", formula = "mtcars!$A$1") + +# Write built-in data set 'mtcars' to the above defined named region +writeNamedRegion(wb, mtcars, name = "mtcars") + +# Save workbook +saveWorkbook(wb) + +# clean up +file.remove("createName.xlsx") +} +} +\keyword{methods} +\keyword{utilities} diff --git a/man/existsName-methods.Rd b/man/existsName-methods.Rd index 11ad2e14..a54fabbe 100644 --- a/man/existsName-methods.Rd +++ b/man/existsName-methods.Rd @@ -1,49 +1,54 @@ -\name{existsName-methods} -\docType{methods} -\alias{existsName} -\alias{existsName-methods} -\alias{existsName,workbook-method} -\title{Checking existence of names in a workbook} -\description{ -Checks the existence of a name in a \code{\linkS4class{workbook}}. -} - -\usage{ -\S4method{existsName}{workbook}(object, name) -} - -\arguments{ - \item{object}{The \code{\linkS4class{workbook}} to use} - \item{name}{The name to check for} -} - -\details{ -Returns \code{TRUE} if the specified \code{name} exists and \code{FALSE} -otherwise. Note that the \code{name} argument is vectorized and -therefore multiple names can be checked for existence in one method call. -} - -\author{ -Martin Studer\cr -Mirai Solutions GmbH \url{https://mirai-solutions.ch} -} -\seealso{ -\code{\linkS4class{workbook}}, \code{\link[=createName-methods]{createName}}, \code{\link[=removeName-methods]{removeName}}, -\code{\link[=getDefinedNames-methods]{getDefinedNames}}, \code{\link[=readNamedRegion-methods]{readNamedRegion}},\cr -\code{\link[=writeNamedRegion-methods]{writeNamedRegion}} -} -\examples{ -\dontrun{ -# mtcars xlsx file from demoFiles subfolder of package XLConnect -mtcarsFile <- system.file("demoFiles/mtcars.xlsx", package = "XLConnect") - -# Load workbook -wb <- loadWorkbook(mtcarsFile) - -# Check if the name 'mtcars' exists -# (should return TRUE since the name is defined as 'mtcars!$A$1:$K$33') -existsName(wb, name = "mtcars") -} -} -\keyword{methods} -\keyword{utilities} +\name{existsName-methods} +\docType{methods} +\alias{existsName} +\alias{existsName-methods} +\alias{existsName,workbook-method} +\title{Checking existence of names in a workbook} +\description{ +Checks the existence of a name in a \code{\linkS4class{workbook}}. +} + +\usage{ +\S4method{existsName}{workbook}(object, name, worksheetScope) +} + +\arguments{ + \item{object}{The \code{\linkS4class{workbook}} to use} + \item{name}{The name to check for} + \item{worksheetScope}{Optional - the specific worksheet to check} +} + +\details{ +Returns \code{TRUE} if the specified \code{name} exists and \code{FALSE} +otherwise. Note that the \code{name} argument is vectorized and +therefore multiple names can be checked for existence in one method call. + +If \code{worksheetScope} is provided, TRUE will be returned only if a matching +name exists in the local scope of the specified sheet. To explicitly match only + in the global scope, pass \code{""} as the value. +} + +\author{ +Martin Studer\cr +Mirai Solutions GmbH \url{https://mirai-solutions.ch} +} +\seealso{ +\code{\linkS4class{workbook}}, \code{\link[=createName-methods]{createName}}, \code{\link[=removeName-methods]{removeName}}, +\code{\link[=getDefinedNames-methods]{getDefinedNames}}, \code{\link[=readNamedRegion-methods]{readNamedRegion}},\cr +\code{\link[=writeNamedRegion-methods]{writeNamedRegion}} +} +\examples{ +\dontrun{ +# mtcars xlsx file from demoFiles subfolder of package XLConnect +mtcarsFile <- system.file("demoFiles/mtcars.xlsx", package = "XLConnect") + +# Load workbook +wb <- loadWorkbook(mtcarsFile) + +# Check if the name 'mtcars' exists +# (should return TRUE since the name is defined as 'mtcars!$A$1:$K$33') +existsName(wb, name = "mtcars") +} +} +\keyword{methods} +\keyword{utilities} diff --git a/man/getDefinedNames-methods.Rd b/man/getDefinedNames-methods.Rd index 619296f6..f6b21c43 100644 --- a/man/getDefinedNames-methods.Rd +++ b/man/getDefinedNames-methods.Rd @@ -8,7 +8,7 @@ Retrieves the defined names in a \code{\linkS4class{workbook}}. } \usage{ -\S4method{getDefinedNames}{workbook}(object, validOnly) +\S4method{getDefinedNames}{workbook}(object, validOnly, worksheetScope) } \arguments{ @@ -17,6 +17,8 @@ Retrieves the defined names in a \code{\linkS4class{workbook}}. are returned. Valid references are ones not starting with #REF! or #NULL! - which could result e.g. due to a missing sheet reference. The default value for \code{validOnly} is \code{TRUE}.} + \item{worksheetScope}{Optional - the name of the worksheet in which the names are scoped; + for names in the global scope, use the value \code{""}} } \author{ diff --git a/man/getReferenceCoordinatesForName-methods.Rd b/man/getReferenceCoordinatesForName-methods.Rd index 10c854cd..eebb21c3 100644 --- a/man/getReferenceCoordinatesForName-methods.Rd +++ b/man/getReferenceCoordinatesForName-methods.Rd @@ -8,13 +8,18 @@ Queries the coordinates of an Excel name in a \code{\linkS4class{workbook}}. } \usage{ -\S4method{getReferenceCoordinatesForName}{workbook}(object,name) +\S4method{getReferenceCoordinatesForName}{workbook}(object,name, worksheetScope) } \arguments{ \item{object}{The \code{\linkS4class{workbook}} to use} \item{name}{The name to query. This argument is vectorized such that multiple names can be queried with one method call.} + \item{worksheetScope}{Optional, the name of the worksheet to use for resolving the named region} +} +\details{ + If \code{worksheetScope} is defined, only coordinates for a name scoped strictly to the specified worksheet are + returned. To explicitly match only if the name is in the global scope, pass \code{""} as the value. } \author{ diff --git a/man/getReferenceFormula-methods.Rd b/man/getReferenceFormula-methods.Rd index 87296536..bee3c393 100644 --- a/man/getReferenceFormula-methods.Rd +++ b/man/getReferenceFormula-methods.Rd @@ -8,13 +8,15 @@ Queries the reference formula of an Excel name in a \code{\linkS4class{workbook}}. } \usage{ -\S4method{getReferenceFormula}{workbook}(object,name) +\S4method{getReferenceFormula}{workbook}(object,name, worksheetScope) } \arguments{ \item{object}{The \code{\linkS4class{workbook}} to use} \item{name}{The name to query. This argument is vectorized such that multiple names can be queried with one method call.} + \item{worksheetScope}{Optional - the name of the worksheet in which the name is scoped; + if undefined any name can be returned. To specify global scope, use the value \code{""}} } \author{ diff --git a/man/readNamedRegion-methods.Rd b/man/readNamedRegion-methods.Rd index 2d637005..6a7f1ea4 100644 --- a/man/readNamedRegion-methods.Rd +++ b/man/readNamedRegion-methods.Rd @@ -8,8 +8,9 @@ Reads named regions from a \code{\linkS4class{workbook}}. } \usage{ -\S4method{readNamedRegion}{workbook}(object, name, header, rownames, colTypes, forceConversion, -dateTimeFormat, check.names, useCachedValues, keep, drop, simplify, readStrategy) +\S4method{readNamedRegion}{workbook}(object, name, header, rownames, colTypes, +forceConversion, dateTimeFormat, check.names, useCachedValues, keep, drop, simplify, +readStrategy, worksheetScope) } \arguments{ @@ -79,6 +80,7 @@ dateTimeFormat, check.names, useCachedValues, keep, drop, simplify, readStrategy fractional days represent hours, minutes, and seconds) and only blank cells are recognized as missing (missing value identifiers as set in \code{\link[=setMissingValue-methods]{setMissingValue}} are ignored) }} + \item{worksheetScope}{Optional, the name of the worksheet to use for resolving the named region} } \details{ @@ -92,6 +94,9 @@ When reading dates, if your system uses a time zone that has / had daylight savi certain dates / timestamps will not be read exactly as they were written. See \url{https://poi.apache.org/apidocs/dev/org/apache/poi/ss/usermodel/DateUtil.html#getJavaDate-double-} +If \code{worksheetScope} is unspecified, the contents of the name found anywhere in the workbook will be read. +Otherwise, only a name specifically scoped to the specified sheet may be read. +To read only names defined in the global scope, pass \code{""} as the value. } \references{ What are named regions/ranges?\cr diff --git a/man/removeName-methods.Rd b/man/removeName-methods.Rd index faf2a6d8..4daff01b 100644 --- a/man/removeName-methods.Rd +++ b/man/removeName-methods.Rd @@ -8,17 +8,20 @@ Removes a name from a \code{\linkS4class{workbook}}. } \usage{ -\S4method{removeName}{workbook}(object,name) +\S4method{removeName}{workbook}(object,name,worksheetScope) } \arguments{ \item{object}{The \code{\linkS4class{workbook}} to use} \item{name}{The name to delete} + \item{worksheetScope}{Optional - the name of the worksheet in which the name is scoped; + useful if different sheets have scoped regions with the same name.} } \details{ Removes the name named \code{name} from the specified workbook \code{object} if it does exist. Multiple names can be specified to be removed. +Use \code{worksheetScope = ""} to only target names defined in the global scope. } \author{ Martin Studer\cr diff --git a/man/writeNamedRegionToFile.Rd b/man/writeNamedRegionToFile.Rd index d5c8070f..6311a822 100644 --- a/man/writeNamedRegionToFile.Rd +++ b/man/writeNamedRegionToFile.Rd @@ -5,7 +5,7 @@ Writes named regions to an Excel file. } \usage{ -writeNamedRegionToFile(file, data, name, formula=NA, ..., +writeNamedRegionToFile(file, data, name, formula=NA, ..., worksheetScope = NULL, styleAction = XLC$STYLE_ACTION.XLCONNECT, clearNamedRegions=FALSE) } \arguments{ @@ -16,6 +16,7 @@ styleAction = XLC$STYLE_ACTION.XLCONNECT, clearNamedRegions=FALSE) the named region identified by the corresponding entry of \code{name}. Use this if you want to create the document from scratch instead of writing to a template!} +\item{worksheetScope}{The scope of validity for the named region. If not specified, the named region has global scope.} \item{...}{Additional arguments passed to \code{\link[=writeNamedRegion-methods]{writeNamedRegion}}} \item{styleAction}{Style action to be used when writing the data.\cr The default is \code{XLC$STYLE_ACTION.XLCONNECT}. diff --git a/man/xlcCall.Rd b/man/xlcCall.Rd index 1546b4c3..548cacd5 100644 --- a/man/xlcCall.Rd +++ b/man/xlcCall.Rd @@ -8,20 +8,20 @@ Performs automatic argument vectorization, provides default Java exception and warnings handling for \pkg{XLConnect}. } \usage{ -xlcCall(obj, fun, ..., .recycle = TRUE, .simplify = TRUE, .checkWarnings = TRUE) +xlcCall(obj, fun, ..., .recycle = TRUE, .simplify = TRUE, .checkWarnings = TRUE, .withAttributes = FALSE) } \arguments{ \item{obj}{ \pkg{XLConnect} S4 object (e.g \code{\linkS4class{workbook}}, \code{\linkS4class{cellstyle}}) which has a slot \code{jobj} representing a \pkg{rJava} \code{jobjRef} object whose method represented by the argument \code{fun} should be called. -} + } \item{fun}{ Name of Java method to be called. -} + } \item{\dots}{ Arguments to the Java method to be called. -} + } \item{.recycle}{ If \code{TRUE} (default), arguments passed through \dots will be automatically vectorized using \code{\link{mapply}} and \code{fun} will be called the appropriate amount of times. @@ -31,10 +31,13 @@ xlcCall(obj, fun, ..., .recycle = TRUE, .simplify = TRUE, .checkWarnings = TRUE) \item{.simplify}{ Only relevant if \code{.recycle = TRUE}. Argument to internal \code{\link{mapply}} to set if there should be an attempt to reduce the result to a vector or matrix. -} + } \item{.checkWarnings}{ Whether to check for warnings registered on the underlying Java object. } + \item{.withAttributes}{ + Whether the function being called returns a Java object with attributes. If so, the attributes will be processed and set on the resulting R object. + } } \details{ This function makes use of \code{\link{mapply}} to perform automatic argument vectorization. Non-atomic arguments are