TL;DR
- R Package development;
- Not exported utility function results in Error
could not find function
in exported one. - Basically the same problem described here
- However the solution provided there using ::: does not solve it for me, because as a consequence then R-CMD-Check throws a warning for using :::
Full Story:
I am developing a small package of R functions let's call the package foo
. I recently ran into max capacities for imports (> 20), thats why I reduced them and wrote for some packages my own work around utility functions. E.g., I removed the readr
package from my DESCRIPTION which I just used for the parse_number()
function.
Now I created a utility.R
file. The two functions in this file are:
clean_names()
number_parse()
These are not export via Roxygen. The first function (clean_names()
) works and can be called from expored / public functions.
The Problem:
However, the second function included in my utility file number_parse()
is not found from the exported functions. When I change my call to from number_parse()
to foo:::number_parse()
it works. However then the R-CMD Check fails with a warning for the use of :::
. Also if I make the second function external (roxygen @export) it works aswell. However I would prefer to leave these cheap utility functions private as they might change, get decaprecated or removed in the near future
Explanation in Pseudo Code
utility.R
This Works when called in function below, due to the addition of @export. However then it is not an internal function anymore
#' number_parse
#' @param s character or vector of characters, to be parsed to a number
#' @export
#' @NoRd
number_parse <- function(s) {
some functionality
return(out)
}
Code for the internal utlity function
So here is my naive try a the number_parse function. The problem might be related to the defintion of a function inside another function (nested functions). However I just tired moving the inner parse_oneNumber()
out of the number_parse()
it did not solve the issue sadly.
#' number_parse
#' @param s character or vector of characters, to be parsed to a number
#' @NoRd
number_parse <- function(s) {
parse_oneNumber <- function(s) {
if (length(s) == 0) return(NA)
if(!is.na(s)){
# remove all non number related characters
s <- gsub("[^0-9.-]", "", s)
# Only use the first decimal point (the digits before and after)
s <- unlist(strsplit(s,"\\."))
# Only use digits after the -
s <- gsub(".*-","-",s)
# Remove now empty strings due to multiple .
s <- s[s!=""]
# If decimal place was present concat to one string
if (length(s)>1) s <- paste0(s[1],".",s[2])
# convert
s <- as.numeric(s)
return(s)
}else{
return(NA)
}
}
# Check if multiple strings were given
if (length(s)>1) {
# if more than one string is given, iterate over strings
out <- c()
for(w in s){
tmp <- parse_oneNumber(w)
# if empty is returned (no number parseable, append NA to retain dimensions)
if(length(tmp) != 0 ) out <- c(out,tmp) else out <- c(out,NA)
}
} else {
tmp <- parse_oneNumber(s)
if(length(tmp) != 0 ) out <- tmp else out <- NA
}
return(out)
}
Update:
Separation in a new second utility2.R
file did not solve it, moving the parse_oneNumber()
function outside the number_parse
function did also not solve it (see below).
#' parse_oneNumber
#' @param s one string to be parsed to a number
#' @NoRd
parse_oneNumber <- function(s) {
# Check given argument, else return NA
if (length(s) == 0) return(NA)
if (is.na(s)) return(NA)
# remove all non number related characters
s <- gsub("[^0-9.-]", "", s)
# Only use the first decimal point (the digits before and after)
s <- unlist(strsplit(s,"\\."))
# Only use digits after the -
s <- gsub(".*-","-",s)
# Remove now empty strings due to multiple .
s <- s[s!=""]
# If decimal place was present concat to one string
if (length(s)>1) s <- paste0(s[1],".",s[2])
# convert
s <- as.numeric(s)
return(s)
}
#' number_parse
#' @param s character or vector of characters, to be parsed to a number
#' @NoRd
number_parse <- function(s) {
# Check if multiple strings were given
if (length(s)>1) {
# if more than one string is given, iterate over strings
out <- c()
for(w in s){
tmp <- parse_oneNumber(w)
# if empty is returned (no number parseable, append NA to retain dimensions)
if(length(tmp) != 0 ) out <- c(out,tmp) else out <- c(out,NA)
}
} else {
tmp <- parse_oneNumber(s)
if(length(tmp) != 0 ) out <- tmp else out <- NA
}
return(out)
}
I am getting to a point, where I guess I will just give up and parse the number_parse
function.