Динамически генерировать ссылочные классы

Я пытаюсь на лету сгенерировать ссылочные классы в пакете R, и это оказалось довольно сложно. Вот используемые мной подходы и проблемы, с которыми я столкнулся:

Я создаю пакет, в котором я надеюсь иметь возможность динамически читать в схеме и автоматически генерировать связанный ссылочный класс (думаю, SOAP). Конечно, это означает, что я не смогу заранее определить свои ссылочные классы в источниках пакетов.

Сначала я попытался создать новый класс, используя простой:

myClass <- setRefClass("NewClassName", fields=list(fieldA="character"))

который, конечно, отлично работает при интерактивном выполнении, но при включении в исходный код пакета я получаю locked binding ошибку. Насколько я знаю, похоже, что это происходит потому, что при интерактивном запуске информация о классе хранится в глобальной среде, которая не заблокирована, в то время как базовая среда моего пакета заблокирована.

Затем я нашел ветку, в которой предлагалось использовать что-то вроде:

myClass <- setRefClass("NewClassName", fields=list(fieldA="character"), where=globalenv())

На самом деле это привело к сбою R / Studio, когда я пытался собрать пакет, поэтому, к сожалению, у меня нет журнала сгенерированной им ошибки, но это определенно не сработало.

Затем я попытался создать новую среду в своем пакете, которую я мог бы использовать для хранения этих ссылочных классов. Поэтому я добавил строку .classEnv <- new.env() в свои источники пакетов (не внутри какой-либо функции), а затем попытался использовать этот класс при создании нового ссылочного класса:

myClass <- setRefClass("NewClassName", fields=list(fieldA="character"), where=.classEnv) 

Казалось, что все работает нормально, но появляется следующее предупреждение:

> myClass <- setRefClass("NewClassName", where=.classEnv)
Warning message:
In getPackageName(where) :
  Created a package name, ‘2013-04-23 10:19:14’, when none found

Итак, по какой-то причине methods::getPackageName() не может определить, в каком пакете находится моя новая среда?

Есть ли способ создать новую среду по-другому, чтобы getPackageName() мог правильно распознать пакет? Могу ли я добавить какую-нибудь функцию, которая поможет мне getPackageName() обнаруживать пакет? Будет ли это работать, если я смогу справиться с предупреждением, или я неправильно использую ссылочные классы, пытаясь создать их динамически?


person Jeff Allen    schedule 23.04.2013    source источник
comment
?setRefClass говорит, что аргументы ... передаются в ?setClass, и это имеет аргумент package; вы хотите использовать свой третий подход с аргументом package='YourPackage' или что-то в этом роде?   -  person Martin Morgan    schedule 23.04.2013
comment
Спасибо за подсказку, Мартин. К сожалению, это не помогло устранить ошибку. Похоже, что имя пакета не доходит до getPackageName, откуда приходит предупреждение, если переменная .packageName еще не указана.   -  person Jeff Allen    schedule 23.04.2013


Ответы (1)


Чтобы продолжить разговор, я обнаружил, что getpackageName хранит имя пакета в скрытой .packageName переменной в указанной среде.

Таким образом, вы можете обойти предупреждение с помощью

assign(".packageName", "MyPkg", envir=.classEnv)    
myClass <- setRefClass("NewClassName", fields=classFields, where=.classEnv)

который устраняет предупреждение, но в документации говорится, что нельзя доверять переменной .packageName бесконечно долго, и я все еще чувствую, что я взламываю это и, возможно, неправильно понимаю что-то важное о ссылочных классах и их отношении к средам.

Полная информация из документации:

Имена пакетов обычно устанавливаются во время загрузки пакета сценарием INSTALL или библиотечной функцией. (В настоящее время имя хранится как объект .packageName, но не доверяйте этому в будущем.)


Изменить:

Прочитав немного дальше, вы поймете, что метод setPackageName может оказаться более надежным способом установки имени пакета для среды. Согласно документам:

setPackageName можно использовать для определения имени пакета в среде, в которой иначе его не было бы. Это позволяет вам создавать классы и / или методы в произвольной среде, но обычно предпочтительно создавать пакеты с помощью стандартных инструментов программирования R (package.skeleton и т. Д.)

Таким образом, похоже, что одним из подходящих решений было бы следующее:

setPackageName("MyPkg", .classEnv)
myClass <- setRefClass("NewClassName", fields=classFields, where=.classEnv)

Это устраняет предупреждающее сообщение и не полагается на что-либо, что задокументировано как нестабильное. Мне до сих пор непонятно, зачем это нужно, но ...

person Jeff Allen    schedule 23.04.2013