パッケージを作る2

  • こんな資料もウェブ上にあります
  • 説明文書を作る
    • Rd形式のファイルが説明文書
  • 昨日の実行だと(WINDOWS上R10.1)、ちょっと"package.skeleton()"の挙動が変でした。どこが変かというと、個々のオブジェクトに関する説明文書のテンプレートRdファイルができないのです・・・
    • 色々試してみましたが、"package.skeleton()"関数が呼び出している".fixPackageFileNames()"という関数に関するエラーが出たり出なかったりすること、また、関数の中身だけを実行するとうまくいくことから、次の様な関数を再定義してみました。。。
    • これだと以下の3通りのいずれも同じ出力です。
myPackage.skeleton(name="foo1",list=ls())
myPackage.skeleton(name="foo2",list=c(ls()))
myPackage.skeleton(name="foo3")
    • 実際には次のようにすれば・・・
myPackage.skeleton(name="sphere",list=ls()[which(ls()!="myPackage.skeleton")])
myPackage.skeleton<-function(name = "anRpackage", list = character(), environment = .GlobalEnv,
	     path = ".", force = FALSE, namespace = FALSE,
             code_files = character())
{

.fixPackageFileNames <- function(list) {
        ## Some object names may not be valid file names, especially
        ## replacement function names.  And if we start changing them
        ## they may collide.
        ## <NOTE>
        ## If we use given code files, we could still check whether
        ## these file are valid across platforms ...
        ## </NOTE>
        if(length(list) == 0L) return(list)
        list0 <- gsub("[[:cntrl:]\"*/:<>?\\|]", "_", list)
        wrong <- grep("^(con|prn|aux|clock\\$|nul|lpt[1-3]|com[1-4])(\\..*|)$",
                      list0)
        if(length(wrong))
            list0[wrong] <- paste("zz", list0[wrong], sep="")
        ## using grep was wrong, as could give -integer(0)
        ok <- grepl("^[[:alnum:]]", list0)
        if(any(!ok))
            list0[!ok] <- paste("z", list0[!ok], sep="")
        ## now on Mac/Windows lower/uppercase will collide too
        list1 <- tolower(list0)
        list2 <- make.unique(list1, sep="_")
        changed <- (list2 != list1)
        list0[changed] <- list2[changed]
        list0
}
    safe.dir.create <- function(path) {
        dirTest <- function(x) !is.na(isdir <- file.info(x)$isdir) & 
            isdir
        if (!dirTest(path) && !dir.create(path)) 
            stop(gettextf("cannot create directory '%s'", path), 
                domain = NA)
    }
    if (!is.logical(namespace) || length(namespace) != 1L) 
        stop("'namespace' must be a single logical")
    if (!is.character(code_files)) 
        stop("'code_files' must be a character vector")
    use_code_files <- length(code_files) > 0L
    envIsMissing <- missing(environment)
    if (missing(list)) {
        if (use_code_files) {
            environment <- new.env()
            methods::setPackageName(name, environment)
            for (cf in code_files) sys.source(cf, envir = environment)
        }
        list <- ls(environment, all.names = TRUE)
    }
    if (!is.character(list)) 
        stop("'list' must be a character vector naming R objects")
    if (use_code_files || !envIsMissing) {
        classesList <- getClasses(environment)
        classes0 <- .fixPackageFileNames(classesList)
        names(classes0) <- classesList
        methodsList <- getGenerics(environment)
        methods0 <- .fixPackageFileNames(methodsList)
        names(methods0) <- methodsList
    }
    else {
        classesList <- methodsList <- character()
    }
    usingS4 <- length(classesList) > 0L || length(methodsList) > 
        0L
    curLocale <- Sys.getlocale("LC_CTYPE")
    on.exit(Sys.setlocale("LC_CTYPE", curLocale), add = TRUE)
    if (Sys.setlocale("LC_CTYPE", "C") != "C") 
        warning("cannot turn off locale-specific chars via LC_CTYPE")
    have <- unlist(lapply(list, exists, envir = environment))
    if (any(!have)) 
        warning(sprintf(ngettext(sum(!have), "object '%s' not found", 
            "objects '%s' not found"), paste(sQuote(list[!have]), 
            collapse = ", ")), domain = NA)
    list <- list[have]
    if (!length(list)) 
        stop("no R objects specified or available")
    message("Creating directories ...")
    dir <- file.path(path, name)
    if (file.exists(dir) && !force) 
        stop(gettextf("directory '%s' already exists", dir), 
            domain = NA)
    safe.dir.create(dir)
    safe.dir.create(code_dir <- file.path(dir, "R"))
    safe.dir.create(docs_dir <- file.path(dir, "man"))
    safe.dir.create(data_dir <- file.path(dir, "data"))
    message("Creating DESCRIPTION ...")
    description <- file(file.path(dir, "DESCRIPTION"), "wt")
    cat("Package: ", name, "\n", "Type: Package\n", "Title: What the package does (short line)\n", 
        "Version: 1.0\n", "Date: ", format(Sys.time(), format = "%Y-%m-%d"), 
        "\n", "Author: Who wrote it\n", "Maintainer: Who to complain to <yourfault@somewhere.net>\n", 
        "Description: More about what it does (maybe more than one line)\n", 
        "License: What license is it under?\n", "LazyLoad: yes\n", 
        if (usingS4) 
            "Depends: methods\n", file = description, sep = "")
    close(description)
    if (namespace) {
        message("Creating NAMESPACE ...")
        out <- file(file.path(dir, "NAMESPACE"), "wt")
        writeLines("exportPattern(\"^[[:alpha:]]+\")", out)
        if (length(methodsList)) {
            cat("exportMethods(\n    ", file = out)
            cat(paste("\"", methodsList, "\"", sep = "", collapse = ",\n    "), 
                "\n)\n", file = out)
        }
        if (length(classesList)) {
            cat("exportClasses(\n    ", file = out)
            cat(paste("\"", classesList, "\"", sep = "", collapse = ",\n     "), 
                "\n)\n", file = out)
        }
        close(out)
    }
    message("Creating Read-and-delete-me ...")
    out <- file(file.path(dir, "Read-and-delete-me"), "wt")
    msg <- c("* Edit the help file skeletons in 'man', possibly combining help files for multiple functions.", 
        if (namespace) "* Edit the exports in 'NAMESPACE', and add necessary imports.", 
        "* Put any C/C++/Fortran code in 'src'.", if (namespace) "* If you have compiled code, add a useDynLib() directive to 'NAMESPACE'." else "* If you have compiled code, add a .First.lib() function in 'R' to load the shared library.", 
        "* Run R CMD build to build the package tarball.", "* Run R CMD check to check the package tarball.", 
        "", "Read \"Writing R Extensions\" for more information.")
    writeLines(strwrap(msg, exdent = 2), out)
    close(out)
    internalObjInds <- grep("^\\.", list)
    internalObjs <- list[internalObjInds]
    if (length(internalObjInds)) 
        list <- list[-internalObjInds]
    if (use_code_files) {
        list0 <- .fixPackageFileNames(list)
    }
    else {
        list0 <- list
    }
    names(list0) <- list
    if (!use_code_files) {
        message("Saving functions and data ...")
        if (length(internalObjInds)) 
            dump(internalObjs, file = file.path(code_dir, sprintf("%s-internal.R", 
                name)))
        for (item in list) {
            if (is.function(get(item, envir = environment))) 
                dump(item, file = file.path(code_dir, sprintf("%s.R", 
                  list0[item])))
            else try(save(list = item, envir = environment, file = file.path(data_dir, 
                sprintf("%s.rda", item))))
        }
    }
    else {
        message("Copying code files ...")
        file.copy(code_files, code_dir)
        R_files <- tools::list_files_with_type(code_dir, "code", 
            full.names = FALSE, OS_subdirs = "")
        code_files <- basename(code_files)
        wrong <- code_files[is.na(match(code_files, R_files))]
        if (length(wrong)) {
            warning("Invalid file name(s) for R code in ", code_dir, 
                ":\n", strwrap(paste(sQuote(wrong), collapse = ", "), 
                  indent = 2), "\n are now renamed to 'z<name>.R'")
            file.rename(from = file.path(code_dir, wrong), to = file.path(code_dir, 
                paste("z", sub("(\\.[^.]*)?$", ".R", wrong), 
                  sep = "")))
        }
    }
    message("Making help files ...")
    if (!namespace && length(internalObjInds)) {
        notNeeded <- grep(methods:::.methodsPackageMetaNamePattern, 
            internalObjs)
        notNeeded <- c(notNeeded, match(".packageName", internalObjs, 
            0L))
        if (length(notNeeded) < length(internalObjs)) {
            internalObjs <- internalObjs[-notNeeded]
            Rdfile <- file(file.path(docs_dir, sprintf("%s-internal.Rd", 
                name)), "wt")
            cat("\\name{", name, "-internal}\n", "\\title{Internal ", 
                name, " objects}\n", file = Rdfile, sep = "")
            for (item in internalObjs) {
                cat("\\alias{", item, "}\n", file = Rdfile, sep = "")
            }
            cat("\\description{Internal ", name, " objects.}\n", 
                "\\details{These are not to be called by the user.}\n", 
                "\\keyword{internal}", file = Rdfile, sep = "")
            close(Rdfile)
        }
    }
    yy <- try(suppressMessages({
        promptPackage(name, filename = file.path(docs_dir, sprintf("%s-package.Rd", 
            name)), lib.loc = path)
        sapply(list, function(item) {
            prompt(get(item, envir = environment), name = item, 
                filename = file.path(docs_dir, sprintf("%s.Rd", 
                  list0[item])))
        })
        sapply(classesList, function(item) {
            methods::promptClass(item, filename = file.path(docs_dir, 
                sprintf("%s-class.Rd", classes0[item])), where = environment)
        })
        sapply(methodsList, function(item) {
            methods::promptMethods(item, filename = file.path(docs_dir, 
                sprintf("%s-methods.Rd", methods0[item])), findMethods(item, 
                where = environment))
        })
    }))
    for (item in methodsList) {
        if (exists(item, envir = environment, inherits = FALSE)) {
            ff <- get(item, envir = environment)
            if (is(ff, "genericFunction") && !identical(ff@package, 
                name)) 
                file.remove(file.path(docs_dir, sprintf("%s.Rd", 
                  list0[item])))
        }
    }
    if (inherits(yy, "try-error")) 
        stop(yy)
    if (length(list.files(code_dir)) == 0L) 
        unlink(code_dir, recursive = TRUE)
    if (length(list.files(data_dir)) == 0L) 
        unlink(data_dir, recursive = TRUE)
    message("Done.")
    message(gettextf("Further steps are described in '%s'.", 
        file.path(dir, "Read-and-delete-me")), domain = NA)



}