I had written some R functions that I wanted to convert to an R package. One of them is called for example print.pretty.values and another print.empty.line. Package builds and installs alright, but when I run the check function I get this warning:
Found the following apparent S3 methods exported but not registered
I have read the relevant documentation and I don't want to have a print function of my class someClass. I just need to export nicely (and without warning) a function that is called print.something or plot.something.else without it being understood as an S3 method and without me having to change the name. Is there a way to define this (in the function documentation or the NAMESPACE file?)
I changed all the names of the functions to have the underscore separator (_) instead of the dot (.), following the tidyverse guidelines: https://style.tidyverse.org/syntax.html
Note that the only case that they 'allow' dots in functions are when you write function.class or class.name and in my case it wasn't like that (print.pretty.values wasn't an S3 function - I just wanted to use the dot as a separator for words in general and thus I got warnings).
Related
I found this in the NAMESPACE file for a package:
export()
When I look at reference docs for export(), all the examples I find use an argument, e.g., export(myFunc), and I cannot locate an exact man page for export(). What will the above line do?
When documenting functions in a package, one will usually use the function export implying that the function that has been specified should be exported as part of the package.
The NAMESPACE holds information about functions imported from other packages as well as those exported from the package one is writing. Hence, under the NAMESPACE file, the export(myFunc) simply refers to a function that will be part of the package. It is nowadays normally not generated by hand and is done with roxygen2. An empty export() might be a design error because as the manual states:
Exports are specified using the export directive in the NAMESPACE file. A directive of the form
export(f, g)
specifies that the variables f and g are to be exported. (Note that variable names may be
quoted, and reserved words and non-standard names such as [<-.fractions must be.)
For more intuition, look at the error that occurs when you try to use a function not exported as part of a package.
stats::group_by
Error: 'group_by' is not an exported object from 'namespace:stats'
In my work I develop R packages that export R data objects (.RData). The name of these .RData files is always the same (e.g. files.RData). These packages also define and export a function that uploads the data to my database, say upload_data(). Inside upload_data() I first load the data using data(files, package = "PACKAGE NAME") and then push it into my database.
Let's say I have two packages, package1 and package2, which live on my file system. Given a vector of the package names (c("package1", "package2")), how would I go about to call 'upload_data()' programatically? Specifically, inside a script, how would I construct a call using "::" notation that constructs and evaluates a call like this: package1::upload_data()). I tried 'call' but couldn't get it right.
You could go the route of constructing the call using :: notation and evaluating that - but it's probably just easier to directly use get and specify the package you want to grab from.
get("upload_data", envir = asNamespace("package1"))
will return the function the same as using package1::upload_data would but is much easier to deal with programatically.
I would like to add an idiosyncratically modified function to package written by someone else, with an R Script, i.e. just for the session, not permanently. The specific example is, let's say, bls_map_county2() added to the blscrapeR package. bls_map_county2 is just a copy of the bls_map_county() function with an added ... argument, for purposes of changing a few of the map drawing parameters. I have not yet inserted the additional parameters. Running the function as-is, I get the error:
Error in BLS_map_county(map_data = df, fill_rate = "unemployed_rate", :
could not find function "geom_map"
I assume this is because my function does not point to the blscrapeR namespace. How do I assign my function to the (installed, loaded) blscrapeR namespace, and is there anything else I need to do to let it access whatever machinery from the package it requires?
When I am hacking on a function in a particular package that in turn calls other functions I often use this form after the definition:
mod_func <- function( args) {body hacked}
environment(mod_func) <- environment(old_func)
But I think the function you might really want is assignInNamespace. These methods will allow the access to non-exported functions in loaded packages. They will not however succeed if the package is not loaded. So you may want to have a stopifnot() check surrounding require(pkgname).
There are two parts to this answer - first a generic answer to your question, and 2nd a specific answer for the particular function that you reference, in which the problem is something slightly different.
1) generic solution to accessing internal functions when you edit a package function
You should already have access to the package namespace, since you loaded it, so it is only the unexported functions that will give you issues.
I usually just prepend the package name with the ::: operator to the non exported functions. I.e., find every instance of a call to some_internal_function(), and replace it with PackageName:::some_internal_function(). If there are several different internal functions called within the function you are editing, you may need to do this a few times for each of the offending function calls.
The help page for ::: does contain these warnings
Beware -- use ':::' at your own risk!
and
It is typically a design mistake to use ::: in your code since the
corresponding object has probably been kept internal for a good
reason. Consider contacting the package maintainer if you feel the
need to access the object for anything but mere inspection.
But for what you are doing, in terms of temporarily hacking another function from the same package for your own use, these warnings should be safe to ignore (at you own risk, of course - as it says in the manual)
2) In the case of blscrapeR ::bls_map_county()
The offending line in this case is
ggplot2::ggplot() + geom_map(...
in which the package writers have specified the ggplot2 namespace for ggplot(), but forgotten to do so for geom_map() which is also part of ggplot2 (and not an internal function in blscrapeR ).
In this case, just load ggplot2, and you should be good to go.
You may also consider contacting the package maintainer to inform them of this error.
Is it possible to export a function in R by evaluating an expression? What I would like to write something like
my.great.fun = function(x) x
export(my.great.fun)
in a R file in a package and have my.great.fun exported.
Then you can evaluate that in a loop, conditionally, define family of functions concisely etc. The immediate application would be generating and exporting setters and getters for an S4 class in two lines of code as opposed to as many lines as there are slots. I saw the package R.MethodsS3, but the export option doesn't seem to do anything other than setting an attribute, ditto the now un-exported export function therein. setGeneric for S4 doesn't have a similar option. I am a fairly navigated R developer with several packages under my belt, so it doesn't help to point me to standard documentation about the NAMESPACE file. roxygen #export is not a solution because it doesn't work in loops, is not in the language, is not first, second or even third class in R. It seems to me we can create functions, generics of S3 and S4 flavors, methods of S3 and S4 flavors all in the language, and the only bit that is missing is the export part: omission or hole in my knowledge? Thanks
You can add the function to an environment when calling export. Then in .onLoad you attach the environment. For instance, see rex_mode in package rex. Reading packages written by the R intelligentsia pays off.
I want to write a package using S4 objects and need to register new generic functions. I want to split my code into several files - each class gets its own .R file. However their methods share of course common generic functions. Where do I need to call setGeneric() such that I can use setMethod() in any .R file of the package? Currently I get an error of the type
Error in setMethod("XXX", signature(yyy = "YYY"), definition = function(yyy, :
no existing definition for function 'XXX'
Organize your code however you see fit (e.g., an AllGenerics.R file, or a XXX-methods.R file that starts with the generic). Use the 'Collate:' field in the DESCRIPTION file to ensure that the generics are available before methods defined.