अन्य स्क्रिप्ट में आर (स्क्रिप्ट) को कैसे शामिल करें


108

मैंने एक यूटिलिटी R स्क्रिप्ट बनाई है, use.R।, जिसे मैं अपने प्रोजेक्ट में अन्य स्क्रिप्ट से उपयोग करना चाहता हूं। यह सुनिश्चित करने का उचित तरीका क्या है कि यह स्क्रिप्ट परिभाषित करने का कार्य मेरी अन्य लिपियों में कार्य करने के लिए उपलब्ध है?

मैं requireफ़ंक्शन के समान कुछ खोज रहा हूं , जो केवल एक पैकेज को लोड करता है यदि यह अभी तक लोड नहीं किया गया है। मैं कॉल नहीं करना चाहता source("util.R")क्योंकि यह स्क्रिप्ट को हर बार लोड करने के बाद इसे कहा जाएगा।

मुझे पता है कि मुझे पैकेज बनाने के लिए मुझे कुछ जवाब मिलेंगे, जैसा कि आर सोर्स कोड को व्यवस्थित करने में :) लेकिन मैं ऐसा कुछ नहीं बना रहा हूं जिसका इस्तेमाल कहीं और किया जाएगा, यह सिर्फ एक स्टैंडअलोन प्रोजेक्ट है।


37
मैं हर समय स्टैंडअलोन परियोजनाओं के लिए पैकेज बनाता हूं। यह बहुत काम नहीं है, और लाभ बहुत बड़ा है।
चलिए

जवाबों:


93

यहाँ एक संभव तरीका है। existsअपने util.Rकोड में कुछ अद्वितीय के लिए जाँच करने के लिए फ़ंक्शन का उपयोग करें ।

उदाहरण के लिए:

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

(शामिल करने के लिए संपादित mode="function", गेविन सिम्पसन ने बताया)


4
का अच्छा उपयोग exists()- mode = "function"इसे मूर्खतापूर्ण बनाने के लिए जोड़ने की जरूरत है
गेविन सिम्पसन

1
exists()आर 3.0.2 में से एक को छोड़कर एक त्रुटि फेंकने लगता है।
माइकल शुबर्ट

सही उपयोग `मौजूद है (" फू ") और जवाब संपादित किया गया था।
एंड्री

18

ऐसी कोई भी अंतर्निहित वस्तु नहीं है, क्योंकि आर कॉल को ट्रैक नहीं करता है sourceऔर यह पता लगाने में सक्षम नहीं है कि कहां से लोड किया गया था (पैकेज का उपयोग करते समय यह मामला नहीं है)। फिर भी, आप C .hफ़ाइलों में उसी विचार का उपयोग कर सकते हैं , अर्थात संपूर्ण को इसमें लपेटें:

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

 #Code

}

और फिर कोड के source("util.R")भीतर कॉल करें if, है ना?
राफालोटूफो

1
@rafalotufo आप हमेशा की तरह स्रोत ("use.R") का उपयोग करेंगे। MBq पद में कोड जाना होगा में util.R. आपने अभी-अभी जो उपयोग किया है उसके पूरे शरीर को लगा दिया है। अभी एक विशाल (यदि) कथन में, यदि यह समझ में आता है।
कीथ ट्वोमेले

10

कहते हैं कि util.Rएक समारोह का उत्पादन करता है foo()। आप यह जांच सकते हैं कि यह फ़ंक्शन वैश्विक परिवेश में उपलब्ध है या नहीं तो स्क्रिप्ट का स्रोत क्या है:

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

कि नाम के साथ कुछ भी मिल जाएगा foo। यदि आप कोई फ़ंक्शन ढूंढना चाहते हैं, तो (जैसा कि @Andrie द्वारा उल्लेख किया गया है) exists()सहायक है, लेकिन यह बताया जाना चाहिए कि वास्तव में किस प्रकार की वस्तु की तलाश है, जैसे

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

यहाँ exists()कार्रवाई में है:

> 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

इस मामले में, आप उपयोग करना चाह सकते हैं grepl(..., value=TRUE)क्योंकि आपका खोज शब्द संभवतः एक रेगेक्स नहीं है। +1, वैसे।
एंड्री

?? grepl()तर्क नहीं है value, लेकिन मुझे शायद regexp को ठीक करना चाहिए ls()...
गेविन सिम्पसन

माफ कीजिएगा यह मेरी गलती है। मेरा मतलब थाfixed=TRUE
एंड्री

@Andrie - आह, ठीक है। यह वैसे भी काम नहीं किया। मिलाते हुए दूर खींच लिया। exists()बेहतर है, लेकिन मैं देख रहा हूं कि आपने इस बीच ऐसा जवाब पोस्ट किया है।
गैविन सिम्पसन

5

आप एक फ़ंक्शन लिख सकते हैं जो फ़ाइल नाम और एक पर्यावरण नाम लेता है, यह देखने के लिए जांचता है कि फ़ाइल को पर्यावरण में लोड किया गया है sys.sourceया नहीं और फ़ाइल को स्रोत करने के लिए उपयोग करता है या नहीं।

यहाँ एक त्वरित और अप्रयुक्त कार्य है (सुधार का स्वागत है!):

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

5

यहाँ एक समारोह है जो मैंने लिखा है। यह base::sourceवैश्विक वातावरण सूची नाम की खट्टी फाइलों की एक सूची को स्टोर करने के लिए फ़ंक्शन को लपेटता है sourced। यदि आप .force=TRUEस्रोत पर कॉल करने के लिए एक तर्क प्रदान करते हैं तो यह केवल एक फ़ाइल को फिर से स्रोत करेगा । इसका तर्क हस्ताक्षर वास्तविक के समान है, source()इसलिए आपको इसका उपयोग करने के लिए अपनी स्क्रिप्ट को फिर से लिखने की आवश्यकता नहीं है।

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, ...)
  }
}

यह सुंदर बातूनी (बहुत सारे कॉल message()) है ताकि आप उन पंक्तियों को बाहर निकाल सकें यदि आप परवाह करते हैं। अनुभवी आर उपयोगकर्ताओं से किसी भी सलाह की सराहना की जाती है; मैं आर के लिए बहुत नया हूं।


0

मैंने अपना पता पूरे पते का उपयोग करके अपनी समस्या हल की जहां मेरा कोड है: इससे पहले:

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

उपरांत:

if(!exists("foo", mode="function")) source("C:/tests/utils.r")
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.