[Rd] Options that are local to the package that sets them

Martin Morgan mtmorgan at fredhutch.org
Sat Nov 1 02:26:23 CET 2014


On 10/31/2014 05:55 PM, Gábor Csárdi wrote:
> On Fri, Oct 31, 2014 at 8:16 PM, William Dunlap <wdunlap at tibco.com> wrote:
>> You can put the following 3 objects, an environment and 2 functions
>> that access it, in any package that need some package-specific
>> storage (say your pkgB1 and pkgB2).
>>     .pkgLocalStorage <- new.env(parent = emptyenv())
>>     assignInPkgLocalStorage <- function(name, object) {
>>         .pkgLocalStorage[[name]] <- object
>>     }
>>     getFromPkgLocalStorage <- function(name, object) {
>>         .pkgLocalStorage[[name]]
>>     }
>> Leave the environment private and export the functions.  Then a user can
>> use them as
>>     pkgB1::assignInPkgLocalStorage("myPallete", makeAPallete(1,2,3))
>>     pkgB2::assignInPkgLocalStorage("myPallete", makeAPallete(5,6,7))
>>     pkgB1::getFromPkgLocalStorage("myPallete") # get the 1,2,3 pallete
>
> I am trying to avoid requiring pkgBn to do this kind of magic. I just
> want it to call function(s) from pkgA. But maybe something like this
> would work. In pkgBn:
>
> my_palettes <- pkgA::palette_factory()
>
> and my_palettes is a function or an environment that has the API
> functions to modify my_palettes itself (via closure if it is a
> function), e.g.
>
> my_palettes$add_palette(...)
> my_palettes$get_palette(...)
>
> or if it is a function, then
>
> my_palettes(add(...), ...)
> my_palettes(get(...), ...)
>
> etc.
>
> This would work, right? I'll try it in a minute.

You'll need pkgA to be able to know that pkgB1's invokation is to use pkgB1's 
parameters, so coupling state (parameters) with function, i.e., a class with 
methods. So a solution is to use an S4 or reference class and generator to 
encapsulate state and dispatch to appropriate functions, E.g.,

   .Plotter <- setRefClass("Plotter",
       fields=list(palette="character"),
       methods=list(
         update(palette) {
             .self$palette <- palette
         },
         plot=function(...) {
             graphics::plot(..., col=.self$palette)
         }))

   APlotter <- function(palette=c("red", "green", "blue"))
       .Plotter(palette=palette)

PkgB1, 2 would then

   plt = APlotter()
   plt$plot(mpg ~ disp, mtcars)
   plt$update(c("blue", "green"))
   plt$plot(mpg ~ disp, mtcars)

or

   .S4Plotter <- setClass("S4Plotter", representation(palette="character")
   S4Plotter <- function(palette=c("red", "blue", "green"))
   s4plot <- function(x, ...) graphics::plot(..., col=x at palette))

(make s4plot a generic with method for class S4Plotter to enforce type).

Seems like this interface could be generated automatically in .onLoad() of pkgA, 
especially if adopting a naming convention of some sort.

Martin

>
> Gabor
>
>
>> If only one of pkgB1 and pkgB2 is loaded you can leave off the pkgBn::.
>>
>> A package writer can always leave off the pkgBn:: as well.
>>
>> Bill Dunlap
>> TIBCO Software
>> wdunlap tibco.com
>>
>>
>> On Fri, Oct 31, 2014 at 4:34 PM, Gábor Csárdi <csardi.gabor at gmail.com> wrote:
>>> Dear All,
>>>
>>> I am trying to do the following, and could use some hints.
>>>
>>> Suppose I have a package called pkgA. pkgA exposes an API that
>>> includes setting some options, e.g. pkgA works with color palettes,
>>> and the user of the package can define new palettes. pkgA provides an
>>> API to manipulate these palettes, including defining them.
>>>
>>> pkgA is intended to be used in other packages, e.g. in pkgB1 and
>>> pkgB2. Now suppose pkgB1 and pkgB2 both set new palettes using pkgA.
>>> They might set palettes with the same name, of course, they do not
>>> know about each other.
>>>
>>> My question is, is there a straightforward way to implement pkgA's
>>> API, such that pkgB1 and pkgB2 do not interfere? In other words, if
>>> pkgB1 and pkgB2 both define a palette 'foo', but they define it
>>> differently, each should see her own version of it.
>>>
>>> I guess this requires that I put something (a function?) in both
>>> pkgB1's and pkgB2's package namespace. As I see it, this can only
>>> happen when pkgA's API is called from pkgB1 (and pkgB2).
>>>
>>> So at this time I could just walk up the call tree and put the palette
>>> definition in the first environment that is not pkgA's. This looks
>>> somewhat messy, and I am probably missing some caveats.
>>>
>>> Is there a better way? I have a feeling that this is already supported
>>> somehow, I just can't find out how.
>>>
>>> Thanks, Best Regards,
>>> Gabor
>>>
>>> ______________________________________________
>>> R-devel at r-project.org mailing list
>>> https://stat.ethz.ch/mailman/listinfo/r-devel
>
> ______________________________________________
> R-devel at r-project.org mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel
>


-- 
Computational Biology / Fred Hutchinson Cancer Research Center
1100 Fairview Ave. N.
PO Box 19024 Seattle, WA 98109

Location: Arnold Building M1 B861
Phone: (206) 667-2793



More information about the R-devel mailing list