Просто добавление к исходному ответу. Хотя это будет работать:
MethodInfo method = typeof(Sample).GetMethod("GenericMethod");
MethodInfo generic = method.MakeGenericMethod(myType);
generic.Invoke(this, null);
Также немного опасно, что вы теряете проверку времени компиляции для GenericMethod
. Если вы позже выполните рефакторинг и переименуете GenericMethod
, этот код не заметит и не будет работать во время выполнения. Кроме того, если есть какая-либо пост-обработка сборки (например, обфускация или удаление неиспользуемых методов / классов), этот код также может сломаться.
Итак, если вы знаете метод, с которым вы связываетесь во время компиляции , и это не называется миллионы раз, поэтому накладные расходы не имеют значения, я бы изменил этот код:
Action<> GenMethod = GenericMethod<int>; //change int by any base type
//accepted by GenericMethod
MethodInfo method = this.GetType().GetMethod(GenMethod.Method.Name);
MethodInfo generic = method.MakeGenericMethod(myType);
generic.Invoke(this, null);
Хотя вы не очень красивы, у вас есть ссылка времени компиляции на GenericMethod
здесь, и если вы рефакторируете, удаляете или делаете что-либо с помощью GenericMethod
, этот код будет продолжать работать или, по крайней мере, ломаться во время компиляции (если, например, вы удалите GenericMethod
).
Другой способ сделать то же самое - создать новый класс-оболочку и создать его через Activator
. Я не знаю, есть ли лучший способ.
Я бы использовал вариант подхода @ steamer25. Дело в том, что я предпочитаю получать последний скрипт, даже когда мой сеанс был запущен через Rscript. Следующий фрагмент, если он включен в файл, предоставит переменную thisScript
, содержащую нормализованный путь скрипта. Я признаю (ab) использование source'ing, поэтому иногда я вызываю Rscript и скрипт, предоставленный в --file
аргументе, источник другого сценария, который источает другой ... Когда-нибудь я буду инвестировать в превращение моего грязного кода в пакет .
thisScript <- (function() {
lastScriptSourced <- tail(unlist(lapply(sys.frames(), function(env) env$ofile)), 1)
if (is.null(lastScriptSourced)) {
# No script sourced, checking invocation through Rscript
cmdArgs <- commandArgs(trailingOnly = FALSE)
needle <- "--file="
match <- grep(needle, cmdArgs)
if (length(match) > 0) {
return(normalizePath(sub(needle, "", cmdArgs[match]), winslash=.Platform$file.sep, mustWork=TRUE))
}
} else {
# 'source'd via R console
return(normalizePath(lastScriptSourced, winslash=.Platform$file.sep, mustWork=TRUE))
}
})()
Я просто сам это сделал. Чтобы обеспечить переносимость вашего скрипта, всегда начинайте его с:
wd <- setwd(".")
setwd(wd)
Это работает, потому что «.» переводится как команда Unix $ PWD. Присвоение этой строки объекту-символу позволяет затем вставить этот объект-символ в setwd () и Presto , ваш код будет всегда запускаться с его текущим каталогом в качестве рабочего каталога, независимо от того, на чьей машине он включен или где в файловой структуре он находится. (Дополнительный бонус: wd-объект может использоваться с file.path () (то есть file.path (wd, «output_directory»), чтобы создать стандартный выходной каталог независимо от пути к файлу, ведущего к вашей именованной директории. Это требует, чтобы вы создали новый каталог, прежде чем ссылаться на него таким образом, но этому тоже может помочь объект wd.
В качестве альтернативы следующий код выполняет то же самое:
wd <- getwd()
setwd(wd)
или, если вам не нужен путь к файлу в объекте, вы можете просто:
setwd(".")
99% случаев, которые вы могли бы просто использовать:
sys.calls()[[1]] [[2]]
Он не будет работать для сумасшедших вызовов, где сценарий не является первым аргументом, то есть source(some args, file="myscript")
. Используйте @ hadley в этих причудливых случаях.
Мне понравилось решение steamer25, поскольку оно кажется самым надежным для моих целей. Однако при отладке в RStudio (в окнах) путь не будет установлен правильно. Причина заключается в том, что если в RStudio установлена точка останова, в поиске файла используется альтернативная команда «отладочный источник», которая устанавливает путь к сценарию несколько иначе. Вот окончательная версия, которую я сейчас использую, которая учитывает это альтернативное поведение в RStudio при отладке:
# @return full path to this script
get_script_path <- function() {
cmdArgs = commandArgs(trailingOnly = FALSE)
needle = "--file="
match = grep(needle, cmdArgs)
if (length(match) > 0) {
# Rscript
return(normalizePath(sub(needle, "", cmdArgs[match])))
} else {
ls_vars = ls(sys.frames()[[1]])
if ("fileName" %in% ls_vars) {
# Source'd via RStudio
return(normalizePath(sys.frames()[[1]]$fileName))
} else {
# Source'd via R console
return(normalizePath(sys.frames()[[1]]$ofile))
}
}
}
Мне нравится этот подход:
this.file <- sys.frame(tail(grep('source',sys.calls()),n=1))$ofile
this.dir <- dirname(this.file)
Удивительно, что в R нет структуры типа «$ 0»! Вы можете сделать это с помощью вызова system () для сценария bash, написанного в R:
write.table(c("readlink -e $0"), file="scriptpath.sh",col=F, row=F, quote=F)
thisscript <- system("sh scriptpath.sh", intern = TRUE)
. Затем просто разделите имя scriptpath.sh для other.R
splitstr <- rev(strsplit(thisscript, "\\/")[[1]])
otherscript <- paste0(paste(rev(splitstr[2:length(splitstr)]),collapse="/"),"/other.R")
Это работает для меня
library(rstudioapi)
rstudioapi::getActiveDocumentContext()$path
Ответ rakensi из Получение пути к скрипту R является самым правильным и действительно блестящим IMHO. Тем не менее, это все еще хак, включающий фиктивную функцию. Я цитирую его здесь, чтобы облегчить его поиск другими.
sourceDir & lt; - getSrcDirectory (function (dummy) {dummy})
blockquote>Это дает каталог файла, в котором размещен оператор (где определена фиктивная функция). Затем он может использоваться для установки рабочей директории и использования относительных путей, например
setwd(sourceDir) source("other.R")
, или для создания абсолютных путей
source(paste(sourceDir, "/other.R", sep=""))
sourceDir
пусто.
– Contango
8 August 2017 в 06:48
Это работает для меня. Просто выгружайте его из аргументов командной строки, удаляет ненужный текст, создает имя dirname и, наконец, получает полный путь от этого:
args <- commandArgs(trailingOnly = F)
scriptPath <- normalizePath(dirname(sub("^--file=", "", args[grep("^--file=", args)])))
Вы можете обернуть r-скрипт в сценарии bash и получить путь к скрипту как переменную bash следующим образом:
#!/bin/bash
# [environment variables can be set here]
path_to_script=$(dirname $0)
R --slave<<EOF
source("$path_to_script/other.R")
EOF
Здесь существует простое решение задачи. Эта команда:
script.dir <- dirname(sys.frame(1)$ofile)
возвращает путь к текущему файлу скрипта. Он работает после сохранения сценария.
dirname(sys.frame(1)$ofile)
непосредственно из Rstudio. Он работает нормально, когда сценарий выполняется с использованием источника («other.R»), а dirname(sys.frame(1)$ofile)
находится внутри "other.R"
.
– Murta
14 July 2015 в 23:39
frame_files <- lapply(sys.frames(), function(x) x$ofile)
frame_files <- Filter(Negate(is.null), frame_files)
PATH <- dirname(frame_files[[length(frame_files)]])
Не спрашивайте меня, как это работает, потому что я забыл: /
sys.frames
возвращает среды стека вызовов, поэтому это действительно имеет смысл при вызове функции. Попробуйте, например, foo <- function() {bar <- function() print(sys.frames()); bar()}; foo()
. Я не могу понять код @ hadley, хотя в среде нет члена ofile
.
– Richie Cotton
30 November 2009 в 12:27
source("~/code/test.r")
, PATH
будет установлено на ~/desktop
. Если вы просто оцените его на верхнем уровне, он вернет NULL.
– hadley
30 November 2009 в 17:24
x$ofile
не определено, поэтому frame_files
пуст.
– Frank
4 December 2009 в 17:08
См. findSourceTraceback()
пакета R.utils , который
Находит все объекты srcfile, сгенерированные источником () во всех кадрах вызовов. Это позволяет узнать, какие файлы в настоящее время написаны с помощью source ().
Подход Steamer25 работает, но только если в пути нет пробелов. На macOS по крайней мере cmdArgs[match]
возвращает что-то вроде /base/some~+~dir~+~with~+~whitespace/
для /base/some\ dir\ with\ whitespace/
.
Я работал вокруг этого, заменив «~ + ~» простым пробелом перед его возвратом.
thisFile <- function() {
cmdArgs <- commandArgs(trailingOnly = FALSE)
needle <- "--file="
match <- grep(needle, cmdArgs)
if (length(match) > 0) {
# Rscript
path <- cmdArgs[match]
path <- gsub("\\~\\+\\~", " ", path)
return(normalizePath(sub(needle, "", path)))
} else {
# 'source'd via R console
return(normalizePath(sys.frames()[[1]]$ofile))
}
}
Очевидно, вы все равно можете расширить блокировку else, как это сделал aprstar.
Все в одном!
#' current script file (in full path)
#' @param
#' @return
#' @examples
#' works with Rscript, source() or in RStudio Run selection
#' @export
csf <- function() {
# http://stackoverflow.com/a/32016824/2292993
cmdArgs = commandArgs(trailingOnly = FALSE)
needle = "--file="
match = grep(needle, cmdArgs)
if (length(match) > 0) {
# Rscript via command line
return(normalizePath(sub(needle, "", cmdArgs[match])))
} else {
ls_vars = ls(sys.frames()[[1]])
if ("fileName" %in% ls_vars) {
# Source'd via RStudio
return(normalizePath(sys.frames()[[1]]$fileName))
} else {
if (!is.null(sys.frames()[[1]]$ofile)) {
# Source'd via R console
return(normalizePath(sys.frames()[[1]]$ofile))
} else {
# RStudio Run Selection
# http://stackoverflow.com/a/35842176/2292993
return(normalizePath(rstudioapi::getActiveDocumentContext()$path))
}
}
}
}
Я завернул и расширил ответы на этот вопрос в новую функцию thisfile()
в rprojroot . Также работает для вязания с knitr
.
У меня были проблемы с реализациями, описанными выше, так как мой скрипт управляется из символического каталога или, по крайней мере, поэтому я думаю, что вышеупомянутые решения не сработали для меня. В соответствии с ответом @ ennuikiller я завернул свой Rscript в bash. Я устанавливаю переменную пути с помощью pwd -P
, которая разрешает символические структуры каталогов. Затем передайте путь в Rscript.
Bash.sh
#!/bin/bash
# set path variable
path=`pwd -P`
#Run Rscript with path argument
Rscript foo.R $path
foo.R
args <- commandArgs(trailingOnly=TRUE)
setwd(args[1])
source(other.R)
Если вместо скрипта foo.R
, зная его местоположение пути, если вы можете изменить свой код, чтобы всегда ссылаться на все пути source
'd от общего root
, то это может быть большой помощью:
Учитывая
/app/deeply/nested/foo.R
/app/other.R
Это будет работать
#!/usr/bin/env Rscript
library(here)
source(here("other.R"))
Для определения корней проекта см. https://krlmlr.github.io/rprojroot/ .
Снятый вариант ответа Supressingfire:
source_local <- function(fname){
argv <- commandArgs(trailingOnly = FALSE)
base_dir <- dirname(substring(argv[grep("--file=", argv)], 8))
source(paste(base_dir, fname, sep="/"))
}
Обратите внимание, что пакет getopt предоставляет функцию get_Rscript_filename
, которая просто использует то же самое решение, представленное здесь, но уже написано для вас в стандартном модуле R, поэтому вам не нужно копировать и вставлять «get script» путь "в каждый скрипт, который вы пишете.
R -e "library(getopt); testscript.R"
– f1r3br4nd
20 February 2018 в 18:56
Rscript
.
– Ryan Thompson
21 February 2018 в 01:42
Я не мог заставить решение Suppressingfire работать, когда «источник» с консоли R.
Лучшее из обоих миров?
thisFile <- function() {
cmdArgs <- commandArgs(trailingOnly = FALSE)
needle <- "--file="
match <- grep(needle, cmdArgs)
if (length(match) > 0) {
# Rscript
return(normalizePath(sub(needle, "", cmdArgs[match])))
} else {
# 'source'd via R console
return(normalizePath(sys.frames()[[1]]$ofile))
}
}
Rscript
, так и с source()
внутри R. Я предлагаю сделать normalizePath()
в обеих версиях, чтобы он дал полный путь в обоих случаях.
– wch
12 November 2014 в 20:57
library(base)
мне понадобилось время, чтобы понять, что LOL
– O.rka
4 October 2016 в 18:32
Вы можете использовать функцию commandArgs
, чтобы получить все параметры, которые были переданы Rscript, фактическому интерпретатору R и найти их для --file=
. Если ваш скрипт был запущен с пути или был запущен с полным путем, script.name
ниже начнется с '/'
. В противном случае это должно быть относительно cwd
, и вы можете выполнить два пути, чтобы получить полный путь.
Edit: похоже, что вам понадобится только script.name
выше и снять финальную составляющую пути. Я удалил ненужный образец cwd()
и очистил основной скрипт и отправил свой other.R
. Просто сохраните этот скрипт и скрипт other.R
в том же каталоге, chmod +x
, и запустите основной скрипт.
main.R :
#!/usr/bin/env Rscript
initial.options <- commandArgs(trailingOnly = FALSE)
file.arg.name <- "--file="
script.name <- sub(file.arg.name, "", initial.options[grep(file.arg.name, initial.options)])
script.basename <- dirname(script.name)
other.name <- paste(sep="/", script.basename, "other.R")
print(paste("Sourcing",other.name,"from",script.name))
source(other.name)
other.R :
print("hello")
output :
burner@firefighter:~$ main.R
[1] "Sourcing /home/burner/bin/other.R from /home/burner/bin/main.R"
[1] "hello"
burner@firefighter:~$ bin/main.R
[1] "Sourcing bin/other.R from bin/main.R"
[1] "hello"
burner@firefighter:~$ cd bin
burner@firefighter:~/bin$ main.R
[1] "Sourcing ./other.R from ./main.R"
[1] "hello"
Это то, что я считаю дехман ищет.
source
, поскольку я думал, что OP хочет - но, возможно, я неправильно прочитал его / ее требование. Но я не могу un-downmod :( Извините!
– hadley
30 November 2009 в 17:26
other.name <- file.path(script.basename, "other.R")
– Jason
9 September 2014 в 15:34
#!/usr/bin/env Rscript
print("Hello")
# sad workaround but works :(
programDir <- dirname(sys.frame(1)$ofile)
source(paste(programDir,"other.R",sep='/'))
source(paste(programDir,"other-than-other.R",sep='/'))