Присоединение временного пространства имен к пути поиска

Этот вопрос является своего рода продолжением этого сообщения так как я до сих пор не совсем уверен, что с точки зрения надежности кода было бы не намного лучше сделать привычку печатать namespace::foo() вместо того, чтобы просто набирать foo() и молиться, чтобы вы получили желаемый результат ;-)

Актуальный вопрос

Я знаю, что это сильно противоречит «стандартным соглашениям R», но скажем так, мне любопытно ;-) Можно ли каким-то образом прикрепить временное пространство имен к пути поиска?


Мотивация

В момент, когда мой пакет mypkg все еще находится на «стадии разработки» (т.е. еще не настоящий пакет R):

  • Я хочу передать свои функции в среду mypkg вместо .GlobalEnv
  • затем присоедините mypkg к пути поиска (как истинное пространство имен, если возможно)
  • чтобы иметь возможность позвонить mypkg::foo()

Я прекрасно понимаю, что вызов :: имеет свои недостатки (он занимает больше времени, чем просто ввод имени функции и позволяет R неявно обрабатывать поиск) и / или может считаться необязательным из-за способа a) R просматривает путь поиска, и пакеты b) могут импортировать свои зависимости (т. Е. Использовать «Импорт» вместо «Зависит», не экспортируя определенные функции и т. Д.). Но я видел, как мой код вылетал как минимум дважды из-за того, что какой-то пакет перезаписывал определенные (базовые) функции, поэтому я перешел от «слепого доверия» к режиму «лучше быть безопасным, чем сожалеть»; -)

Что я пробовал

AFAIU, пространства имен в принципе не что иное, как некоторая особая среда

> 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>

И есть функция attach(), которая прикрепляет объекты к пути поиска. Вот что я подумал:

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

Полагаю, мне нужно как-то поработать с attachNamepace() и выяснить, чего он ожидает, прежде чем он будет вызван в library(). Любые идеи?


РЕДАКТИРОВАТЬ

Что касается комментария Хэдли: на самом деле мне было бы все равно, является ли присоединенная среда полноценным пространством имен или просто обычной средой, если я могу расширить :: , сохранив функцию «синтаксического поиска» ( т.е. возможность звонить pkg::foo() вместо "::"(pkg="pkg", name="foo")()).

Так выглядит функция "::":

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

Это то, что он также должен иметь возможность делать, если R обнаруживает, что pkg на самом деле не пространство имен, а просто некоторая среда, прикрепленная к пути поиска:

"::*" <- 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)
}

Это работает, но нет синтаксического шугаринга:

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

Как я смогу вызвать pkg::*foo(x=1, y=2) (не считая того факта, что ::* - действительно плохое имя для функции ;-))?


person Rappster    schedule 25.03.2013    source источник
comment
Примечание из файла справки для asNamespace: Функции поддержки внутреннего пространства имен. Не предназначен для прямого вызова.   -  person James    schedule 25.03.2013
comment
Насколько я понимаю, пакет devtools делает более или менее то, что вы описываете. Вы можете прочитать load_ALL(), чтобы понять, как @hadley решил эту проблему.   -  person Andrie    schedule 25.03.2013
comment
@Andrie: спасибо, я проверю это.   -  person Rappster    schedule 25.03.2013
comment
Непонятно, что вы пытаетесь сделать - я думаю, вы, вероятно, просто хотите присоединить среду и не беспокоиться о создании пространства имен вручную (что очень сложно, но делается в инструментах разработки, хотя и хрупким образом)   -  person hadley    schedule 26.03.2013
comment
@hadley: я хотел бы передать свои функции в mynamespace (вместо .GlobalEnv), чтобы иметь возможность вызывать mynamespace::foo() вместо foo(). Если бы мой код уже превратился в полноценный пакет, не было бы проблем. Но на этапе разработки я не могу использовать ::, так как настоящего пространства имен еще нет. Таким образом, вопрос, могу ли я создать временный.   -  person Rappster    schedule 26.03.2013
comment
Просто используйте devtools, который сделает все это за вас. Если вы хотите сделать это самостоятельно, вам придется прочитать исходный код;)   -  person hadley    schedule 26.03.2013
comment
@hadley: спасибо, я посмотрю devtools   -  person Rappster    schedule 26.03.2013


Ответы (1)


Что-то не так в вашей мотивации: ваше пространство имен НЕ должно быть привязано к пути поиска, чтобы использовать нотацию '::', на самом деле все наоборот.

Путь поиска позволяет выбирать символы, просматривая все пространства имен, прикрепленные к пути поиска.

Итак, как сказал вам Хэдли, вам просто нужно использовать devtools :: load_all (), и все ...

person Karl Forner    schedule 03.07.2013