Attaching a temporary namespace to the search path

倖福魔咒の 提交于 2019-12-09 03:38:57

问题


This question is sort of a follow up to this post as I'm still not fully convinced that, with respect to code robustness, it wouldn't be far better to make typing namespace::foo() habit instead of just typing foo() and praying you get the desired result ;-)

Actual question

I'm aware that this goes heavily against "standard R conventions", but let's just say I'm curious ;-) Is it possible to attach a temporary namespace to the search path somehow?


Motivation

At a point where my package mypkg is still in "devel stage" (i.e. not a true R package yet):

  • I'd like to source my functions into an environment mypkg instead of .GlobalEnv
  • then attach mypkg to the search path (as a true namespace if possible)
  • in order to be able to call mypkg::foo()

I'm perfectly aware that calling :: has its downsides (it takes longer than simply typing a function's name and letting R handle the lookup implicitly) and/or might not be considered necessary due to the way a) R scans through the search path and b) packages may import their dependencies (i.e. using "Imports" instead of "Depends", not exporting certain functions etc). But I've seen my code crash at least twice due to the fact that some package has overwritten certain (base) functions, so I went from "blind trust" to "better-to-be-safe-than-sorry" mode ;-)

What I tried

AFAIU, namespaces are in principle nothing more than some special kind of environment

> search()
[1] ".GlobalEnv"        "package:stats"     "package:graphics" 
[4] "package:grDevices" "package:utils"     "package:datasets" 
[7] "package:methods"   "Autoloads"         "package:base"     

> asNamespace("base")
<environment: namespace:base>

And there's the attach() function that attaches objects to the search path. So here's what I thought:

temp.namespace <- new.env(parent=emptyenv())
attach(temp.namespace)
> asNamespace("temp.namespace")
Error in loadNamespace(name) : 
  there is no package called 'temp.namespace'

I guess I somehow have to work with attachNamepace() and figure out what this expects before it is called in in library(). Any ideas?


EDIT

With respect to Hadley's comment: I actually wouldn't care whether the attached environment is a full-grown namespace or just an ordinary environment as long as I could extend :: while keeping the "syntactic sugering" feature (i.e. being able to call pkg::foo() instead of "::"(pkg="pkg", name="foo")()).

This is how function "::" looks like:

> get("::")
function (pkg, name) 
{
    pkg <- as.character(substitute(pkg))
    name <- as.character(substitute(name))
    getExportedValue(pkg, name)
}

This is what it should also be able to do in case R detects that pkg is in fact not a namespace but just some environment attached to the search path:

"::*" <- function (pkg, name) 
{
    pkg <- as.character(substitute(pkg))
    name <- as.character(substitute(name))
    paths <- search()
    if (!pkg %in% paths) stop(paste("Invalid namespace environment:", pkg))
    pos <- which(paths == pkg)
    if (length(pos) > 1) stop(paste("Multiple attached envirs:", pkg))
    get(x=name, pos=pos)
}

It works, but there's no syntactic sugaring:

> "::*"(pkg="tempspace", name="foo")
function(x, y) x + y
> "::*"(pkg="tempspace", name="foo")(x=1, y=2)
[1] 3

How would I be able to call pkg::*foo(x=1, y=2) (disregarding the fact that ::* is a really bad name for a function ;-))?


回答1:


There is something wrong in your motivation: your namespace does NOT have to be attached to the search path in order to use the '::' notation, it is actually the opposite.

The search path allows symbols to be picked by looking at all namespaces attached to the search path.

So, as Hadley told you, you just have to use devtools::load_all(), that's all...



来源:https://stackoverflow.com/questions/15620404/attaching-a-temporary-namespace-to-the-search-path

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!