Bagaimana cara memasukkan skrip (sumber) R di skrip lain

108

Saya telah membuat skrip R utilitas, util.R, yang ingin saya gunakan dari skrip lain dalam proyek saya. Apa cara yang tepat untuk memastikan bahwa fungsi yang ditentukan skrip ini tersedia untuk berfungsi di skrip saya yang lain?

Saya mencari sesuatu yang mirip dengan requirefungsi tersebut, yang memuat paket hanya jika belum dimuat. Saya tidak ingin menelepon source("util.R")karena itu akan memuat skrip setiap kali dipanggil.

Saya tahu bahwa saya akan mendapatkan beberapa jawaban yang memberitahu saya untuk membuat paket, seperti dalam Mengorganisir R Source Code :) Tapi saya tidak membuat sesuatu yang akan digunakan di tempat lain, ini hanya proyek yang berdiri sendiri.

rafalotufo.dll
sumber
37
Saya membuat paket untuk proyek mandiri sepanjang waktu. Tidak banyak pekerjaan, dan manfaatnya sangat besar. Ayolah, kamu tahu kamu ingin melakukannya ...
Andrie

Jawaban:

93

Inilah salah satu cara yang mungkin. Gunakan existsfungsi tersebut untuk memeriksa sesuatu yang unik dalam util.Rkode Anda .

Sebagai contoh:

if(!exists("foo", mode="function")) source("util.R")

(Diedit untuk memasukkan mode="function", seperti yang ditunjukkan Gavin Simpson)

Andrie
sumber
4
Penggunaan yang bagus exists()- perlu mode = "function"ditambahkan untuk membuatnya sangat mudah
Gavin Simpson
1
exists()tampaknya memunculkan kesalahan kecuali mengembalikan satu di R 3.0.2.
Michael Schubert
Penggunaan yang benar adalah `ada (" foo ") dan jawabannya telah diedit.
Andrie
18

Tidak ada hal bawaan seperti itu, karena R tidak melacak panggilan ke sourcedan tidak dapat mengetahui apa yang dimuat dari mana (ini tidak terjadi saat menggunakan paket). Namun, Anda dapat menggunakan ide yang sama seperti pada .hfile C , yaitu membungkus keseluruhan dalam:

if(!exists('util_R')){
 util_R<-T

 #Code

}
mbq
sumber
dan kemudian panggil source("util.R")di dalam ifkode, bukan?
rafalotufo
1
@rafalotufo Anda akan mencari ("util.R") seperti biasa. Kode di posting mbq akan masuk ke util.R. Anda cukup meletakkan seluruh isi dari apa yang ada di util.R sekarang menjadi pernyataan if () yang besar, jika itu masuk akal.
Keith Twombley
10

Say util.Rmenghasilkan suatu fungsi foo(). Anda dapat memeriksa apakah fungsi ini tersedia di lingkungan global dan sumber skrip jika tidak:

if(identical(length(ls(pattern = "^foo$")), 0))
    source("util.R")

Itu akan menemukan apapun dengan nama itu foo. Jika Anda ingin mencari suatu fungsi, maka (seperti yang disebutkan oleh @Andrie) exists()sangat membantu tetapi perlu diberi tahu jenis objek apa yang harus dicari, mis.

if(exists("foo", mode = "function"))
    source("util.R")

Inilah exists()aksinya:

> exists("foo", mode = "function")
[1] FALSE
> foo <- function(x) x
> exists("foo", mode = "function")
[1] TRUE
> rm(foo)
> foo <- 1:10
> exists("foo", mode = "function")
[1] FALSE
Gavin Simpson
sumber
Dalam kasus ini, Anda mungkin ingin menggunakan grepl(..., value=TRUE)karena istilah pencarian Anda mungkin bukan regex. +1, ngomong-ngomong.
Andrie
?? grepl()tidak memiliki argumen value, tapi saya mungkin harus memperbaiki regexp di ls()...
Gavin Simpson
Maaf, salah saya. Maksud sayafixed=TRUE
Andrie
@Andrie - Ah, oke. Itu tidak berhasil. Terseret saat merenungkan ini. exists()lebih baik tetapi saya sekarang melihat Anda telah memposting Jawaban seperti itu sementara itu.
Gavin Simpson
5

Anda dapat menulis fungsi yang menggunakan nama file dan nama lingkungan, memeriksa untuk melihat apakah file telah dimuat ke lingkungan dan menggunakan sys.sourceuntuk sumber file jika tidak.

Berikut adalah fungsi cepat dan belum teruji (perbaikan diterima!):

include <- function(file, env) {
  # ensure file and env are provided
  if(missing(file) || missing(env))
    stop("'file' and 'env' must be provided")
  # ensure env is character
  if(!is.character(file) || !is.character(env))
    stop("'file' and 'env' must be a character")

  # see if env is attached to the search path
  if(env %in% search()) {
    ENV <- get(env)
    files <- get(".files",ENV)
    # if the file hasn't been loaded
    if(!(file %in% files)) {
      sys.source(file, ENV)                        # load the file
      assign(".files", c(file, files), envir=ENV)  # set the flag
    }
  } else {
    ENV <- attach(NULL, name=env)      # create/attach new environment
    sys.source(file, ENV)              # load the file
    assign(".files", file, envir=ENV)  # set the flag
  }
}
Joshua Ulrich
sumber
5

Ini adalah fungsi yang saya tulis. Ini membungkus base::sourcefungsi untuk menyimpan daftar file bersumber dalam daftar lingkungan global bernama sourced. Ini hanya akan mengambil kembali file jika Anda memberikan .force=TRUEargumen ke panggilan ke sumber. Tanda tangan argumennya sebaliknya identik dengan yang asli source()sehingga Anda tidak perlu menulis ulang skrip Anda untuk menggunakan ini.

warning("overriding source with my own function FYI")
source <- function(path, .force=FALSE, ...) {
  library(tools)
  path <- tryCatch(normalizePath(path), error=function(e) path)
  m<-md5sum(path)

  go<-TRUE
  if (!is.vector(.GlobalEnv$sourced)) {
    .GlobalEnv$sourced <- list()
  }
  if(! is.null(.GlobalEnv$sourced[[path]])) {
    if(m == .GlobalEnv$sourced[[path]]) {
      message(sprintf("Not re-sourcing %s. Override with:\n  source('%s', .force=TRUE)", path, path))
      go<-FALSE
    }
    else {
      message(sprintf('re-sourcing %s as it has changed from: %s to: %s', path, .GlobalEnv$sourced[[path]], m))
      go<-TRUE
    }
  } 
  if(.force) {
    go<-TRUE
    message("  ...forcing.")
  }
  if(go) {
    message(sprintf("sourcing %s", path))
    .GlobalEnv$sourced[path] <- m
    base::source(path, ...)
  }
}

Ini cukup cerewet (banyak panggilan ke message()) sehingga Anda dapat menghilangkannya jika Anda peduli. Setiap saran dari pengguna R veteran sangat dihargai; Saya cukup baru mengenal R.

Keith Twombley
sumber
0

Saya memecahkan masalah saya menggunakan seluruh alamat di mana kode saya adalah: Sebelum:

if(!exists("foo", mode="function")) source("utils.r")

Setelah:

if(!exists("foo", mode="function")) source("C:/tests/utils.r")
José Roberto Ribeiro Filho
sumber