.pkgModelCurrent <- TRUE
.setPkgModels <- function(value) { ## For testing
assignInMyNamespace(".pkgModelCurrent", value)
}
.norm2 <- function(obj) {
if (inherits(obj, "rxode2")) {
if (exists(".linCmtM", obj)) {
return(get(".linCmtM", obj))
}
}
setNames(rxode2::rxModelVars(obj)$model["normModel"], NULL)
}
.isWritable <- function(path) {
if (checkmate::checkString(path)) {
if (file.exists(path)) {
return(file.access(path, mode = 2)[[1]] == 0)
}
}
FALSE
}
.rxPkgInst <- function(obj) {
.wd <- getwd()
if (regexpr(obj$package, .wd) != -1) {
.inst <- gsub(paste0("(", obj$package, ").*"), "\\1", .wd)
} else {
.inst <- system.file(package = obj$package)
}
if (.isWritable(.inst)) {
if (regexpr("inst$", .inst) != -1) {
return(.inst)
}
.inst2 <- file.path(.inst, "inst")
if (file.exists(.inst2)) {
return(.inst2)
}
.html <- file.path(.inst, "html")
if (file.exists(.html)) {
return(.inst)
}
return(.inst2)
} else {
.inst <- "~/.rxCache/"
if (.isWritable(.inst)) {
return(.inst)
}
return(rxTempDir())
}
}
.rxPkgDir <- function(obj) {
return(file.path(.rxPkgInst(obj), "rx"))
}
.rxPkgDll <- function(obj) {
obj$mdir <- .rxPkgDir(obj)
.pkgInfo <- getLoadedDLLs()[[obj$package]]
if (!all(is.null(.pkgInfo))) {
if (obj$isValid()) {
.tmp <- .pkgInfo
class(.tmp) <- "list"
return(.tmp$path)
} else {
return(file.path(obj$mdir, basename(obj$rxDll$dll)))
}
} else {
return(file.path(obj$mdir, basename(obj$rxDll$dll)))
}
}
.rxNewMvStr <- function(obj) {
gsub("[.].*", paste0("_new_", .Platform$r_arch, "_model_vars"), basename(obj$rxDll$dll))
}
.rxPkgLoaded <- function(pkg) {
.si <- sessionInfo()
return(length(intersect(pkg, c(
names(.si$otherPkgs) ## ,names(.si$loadedOnly)
))) != 0)
}
.rxUseI <- new.env(parent = emptyenv())
# 1
.rxUseI$i <- 1L
.rxUseCdir <- ""
#' Use model object in your package
#' @param obj model to save.
#' @param internal If this is run internally. By default this is FALSE
#' @inheritParams usethis::use_data
#' @return Nothing; This is used for its side effects and shouldn't be called by a user
#' @export
rxUse <- function(obj, overwrite = TRUE, compress = "bzip2",
internal = FALSE) {
rxReq("usethis")
rxReq("devtools")
internal <- internal
if (missing(obj)) {
.env <- new.env()
assign("internal", internal, .env)
assign("overwrite", overwrite, .env)
assign("compress", compress, .env)
lapply(list.files(devtools::package_file("inst/rx"), full.names = TRUE),
function(f) {
unlink(f, force = TRUE, recursive = TRUE)
})
.models <- NULL
for (.f in list.files(
path = devtools::package_file("data"),
pattern = "\\.rda$", full.names = TRUE
)) {
load(.f, envir = .env)
.f2 <- basename(.f)
.f2 <- substr(.f2, 0, nchar(.f2) - 4)
if (is(.env[[.f2]], "rxode2")) {
.env[[.f2]]$package <- NULL
.minfo(sprintf("recompile '%s'", .f2))
.models <- c(.models, .f2)
eval(parse(text = sprintf("rxUse(%s, internal=internal, overwrite=overwrite, compress=compress)", .f2)),
envir = .env
)
.docFile <- file.path(devtools::package_file("R"), paste0(.f2, "-doc.R"))
if (!file.exists(.docFile)) {
(sprintf("creating documentation '%s'", .docFile))
sink(.docFile)
.tmp <- .env[[.f2]]
.mv <- rxModelVars(.tmp)
cat(sprintf("#' %s rxode2 model\n", .f2))
cat("#'\n")
cat(sprintf(
"#' @format An \\emph{rxode2} model with %s parameters, %s ODE states, and %s calc vars.\n",
length(.tmp$params), length(.tmp$state) + .mv$extraCmt, length(.tmp$lhs)
))
cat("#'\n")
cat(sprintf("#'\\emph{Parameters (%s$params)}\n", .f2))
cat("#'\n")
cat("#' \\describe{\n")
.def <- rxInits(.tmp)
.defs <- paste0(" (default=", .def, ")")
.defs[is.na(.def)] <- ""
cat(paste(paste0("#' \\item{", .tmp$params, "}{", .defs, "}\n"), collapse = ""))
cat("#'}\n")
.state <- .tmp$state
##
if (.mv$extraCmt == 2) {
.state <- c(.state, "depot", "central")
} else if (.mv$extraCmt == 1) {
.state <- c(.state, "central")
}
if (length(.state) > 0) {
cat("#'\n")
cat(sprintf("#' \\emph{State %s$state}\n", .f2))
cat("#'\n")
cat("#' \\describe{\n")
cat(paste(paste0("#' \\item{", .state, "}{ (=", seq_along(.state), ")}\n"), collapse = ""))
cat("#' }\n")
}
.lhs <- .tmp$lhs
if (length(.lhs) > 0) {
cat("#'\n")
cat(sprintf("#' \\emph{Calculated Variables %s$lhs}\n", .f2))
cat("#'\n")
cat("#' \\describe{\n")
cat(paste(paste0("#' \\item{", .lhs, "}{}\n"), collapse = ""))
cat("#' }\n")
}
cat("#'\n")
cat("#' \\emph{Model Code}\n") # sprintf(,.f2)
cat("#'\n")
.code <- deparse(body(eval(parse(text = paste("function(){", .norm2(.tmp), "}")))))
.code[1] <- "rxode2({"
.code[length(.code)] <- "})"
cat(paste(paste0("#' ", .code, "\n"), collapse = ""))
cat("#'\n")
cat(paste(paste0("#' @seealso \\code{\\link[rxode2]{eventTable}}, \\code{\\link[rxode2]{et}}, \\code{\\link[rxode2]{rxSolve}}, \\code{\\link[rxode2]{rxode2}}\n")))
cat("#' \n")
cat("#' @examples\n")
cat("#' ## Showing the model code\n")
cat(sprintf("#' summary(%s)\n", .f2))
cat("#'\n")
cat(sprintf('"%s"\n', .f2))
sink()
}
}
}
if (!dir.exists(devtools::package_file("src"))) {
dir.create(devtools::package_file("src"), recursive = TRUE, showWarnings = FALSE)
}
.pkg <- basename(usethis::proj_get())
.rx <- loadNamespace("rxode2")
lapply(
list.files(.rxUseCdir, pattern = "[.]c", full.names = TRUE),
function(x) {
.minfo(sprintf("copy '%s'", basename(x)))
.env <- .rx$.rxUseI
.rxUseI <- .env$i
.f0 <- gsub(
"^#define (.*) _rx(.*)$",
paste0("#define \\1 _rxp", .rxUseI, "\\2"), readLines(x)
)
assign("i", .rxUseI + 1, envir = .env)
.f0 <- c("#include <rxode2.h>\n#include <rxode2_model_shared.h>", .f0)
.w <- which(.f0 == "#include \"extraC.h\"")
if (length(.w) > 0) .f0 <- .f0[-.w[1]]
writeLines(text = .f0, con = file.path(devtools::package_file("src"), basename(x)))
}
)
.inits <- paste0("R_init0_", .pkg, "_", .models)
.tmp <- paste0("{\"", .pkg, "_", .models, "_model_vars\", (DL_FUNC) &", .pkg, "_", .models, "_model_vars, 0},\\")
.tmp[length(.tmp)] <- substr(.tmp[length(.tmp)], 0, nchar(.tmp[length(.tmp)]) - 1)
.extraC <- c(
"#define compiledModelCall \\",
.tmp,
paste0("SEXP ", .pkg, "_", .models, "_model_vars();"),
paste0("void ", .inits, "();"),
paste0("void R_init0_", .pkg, "_rxode2_models(){"),
paste0(" ", .inits, "();"),
"}"
)
sink(file.path(devtools::package_file("src"), paste0(.pkg, "_compiled.h")))
if (.pkg == "rxode2") {
cat("#include <R.h>\n#include <Rinternals.h>\n#include <stdlib.h> // for NULL\n#include <R_ext/Rdynload.h>\n#include \"../inst/include/rxode2.h\"\n#include \"../inst/include/rxode2_model_shared.h\"\n")
} else {
cat("#include <R.h>\n#include <Rinternals.h>\n#include <stdlib.h> // for NULL\n#include <R_ext/Rdynload.h>\n#include <rxode2.h>\n#include <rxode2_model_shared.h>\n")
}
cat(paste(.extraC, collapse = "\n"))
cat("\n")
sink()
.files <- list.files(devtools::package_file("src"))
.files <- .files[regexpr("rxode2_model_shared", .files) == -1]
if (all(regexpr(paste0("^", .pkg), .files) != -1)) {
.minfo(sprintf("only compiled models in this package, creating '%s_init.c'", .pkg))
sink(file.path(devtools::package_file("src"), paste0(.pkg, "_init.c")))
cat("#include <R.h>\n#include <Rinternals.h>\n#include <stdlib.h> // for NULL\n#include <R_ext/Rdynload.h>\n")
cat("#include <rxode2.h>\n")
cat("#include <rxode2_model_shared.h>\n")
cat(paste0('#include "', .pkg, '_compiled.h"\n'))
cat(sprintf("void R_init_%s(DllInfo *info){\n", .pkg))
cat(sprintf(" R_init0_%s_rxode2_models();\n", .pkg))
cat(" static const R_CallMethodDef callMethods[] = {\n compiledModelCall\n {NULL, NULL, 0}\n };\n")
cat(" R_registerRoutines(info, NULL, callMethods, NULL, NULL);\n")
cat(" R_useDynamicSymbols(info,FALSE);\n")
cat("}\n")
cat(paste(paste0("void R_unload_", .pkg, "_", .models, "(DllInfo *info);\n"), collapse = ""))
cat(sprintf("void R_unload_%s(DllInfo *info){\n", .pkg))
cat(paste(paste0(" R_unload_", .pkg, "_", .models, "(info);\n"), collapse = ""))
cat("}\n")
sink()
}
if (!file.exists(devtools::package_file("R/rxUpdated.R")) && .pkg != "rxode2") {
sink(devtools::package_file("R/rxUpdated.R"))
cat(".rxUpdated <- new.env(parent=emptyenv())\n")
sink()
}
lapply(list.files(devtools::package_file("inst/rx"), full.names = TRUE),
function(f) {
unlink(f, force = TRUE, recursive = TRUE)
})
if (length(list.files(devtools::package_file("inst"))) == 0) {
unlink(devtools::package_file("inst"), recursive = TRUE, force = TRUE)
}
return(invisible(TRUE))
} else {
.tempfile <- tempfile()
.tempR <- tempfile(fileext=".R")
.expr <- bquote({
rxode2::.rxWithWd(.(getwd()), {
.modName <- .(as.character(substitute(obj)))
.pkg <- .(basename(usethis::proj_get()))
.env <- new.env(parent = baseenv())
assign(.modName, rxode2::rxode2(.(.norm2(obj)), package = .pkg, modName =.modName), .env)
writeLines(dirname(rxode2::rxC(.env[[.modName]])), .(.tempfile))
assign("internal", .(internal), .env)
assign("overwrite", .(overwrite), .env)
assign("compress", .(compress), .env)
eval(parse(text = sprintf("usethis::use_data(%s, internal=internal, overwrite=overwrite, compress=compress)", .modName)), envir = .env)
})
})
writeLines(paste(deparse(.expr), collapse="\n"), .tempR)
.cmd <- file.path(R.home("bin"), "R")
.args <- c("CMD", "BATCH", basename(.tempR))
.rxWithWd(tempdir(), {
.out <- sys::exec_internal(cmd = .cmd, args = .args, error = FALSE)
message(paste(readLines(paste0(.tempR, "out")), collapse="\n"))
})
.stderr <- rawToChar(.out$stderr)
if (!(all(.stderr == "") && length(.stderr) == 1)) {
message(paste(.stderr, sep = "\n"))
}
if (!file.exists(.tempfile)) {
stop("could not build model for inclusion in package",
call.=FALSE)
}
assignInMyNamespace(".rxUseCdir", readLines(.tempfile))
try(unlink(paste(.tempfile)), silent=TRUE)
}
}
#' Creates a package from compiled rxode2 models
#'
#' @param ... Models to build a package from
#' @param package String of the package name to create
#' @param action Type of action to take after package is created
#' @param name Full name of author
#' @param license is the type of license for the package.
#' @inheritParams usethis::create_package
#' @inheritParams rxode2
#' @author Matthew Fidler
#' @return this function returns nothing and is used for its side effects
#' @export
rxPkg <- function(..., package,
wd = getwd(),
action = c("install", "build", "binary", "create"),
license = c("gpl3", "lgpl", "mit", "agpl3"),
name = "Firstname Lastname",
fields = list()) {
if (missing(package)) {
stop("'package' needs to be specified")
}
action <- match.arg(action)
license <- match.arg(license)
.owd <- getwd()
.op <- options()
on.exit({
setwd(.owd)
options(.op)
})
.dir <- wd
if (!dir.exists(.dir)) {
dir.create(.dir)
}
setwd(.dir)
options(
usethis.description = list(`Title` = "This is generated from rxode2"),
usethis.full_name = ifelse(missing(name), getOption("usethis.full_name", "Firstname Lastname"), name)
)
.dir2 <- file.path(.dir, package)
usethis::create_package(.dir2,
fields = fields,
rstudio = FALSE,
roxygen = TRUE,
check_name = TRUE,
open = FALSE
)
setwd(.dir2)
usethis::use_package("rxode2", "LinkingTo")
usethis::use_package("rxode2", "Depends")
if (license == "gpl3") {
usethis::use_gpl3_license()
} else if (license == "lgpl") {
usethis::use_lgpl_license()
} else if (license == "agpl3") {
usethis::use_agpl3_license()
} else if (license == "mit") {
usethis::use_mit_license()
}
.p <- devtools::package_file("DESCRIPTION")
writeLines(c(
readLines(.p),
"NeedsCompilation: yes",
"Biarch: true"
), .p)
## Now use rxUse for each item
.env <- new.env()
.lst <- as.list(match.call()[-1])
.w <- which(names(.lst) == "")
.lst <- .lst[.w]
for (.i in seq_along(.lst)) {
.v <- as.character(deparse(.lst[[.i]]))
assign(.v, eval(.lst[[.i]], envir = parent.frame(1)), .env)
print(.env[[.v]])
eval(parse(text = sprintf("rxUse(%s)", .v)), envir = .env)
}
## Final rxUse to generate all code
rxUse()
.p <- file.path(devtools::package_file("R"), "rxUpdated.R")
.f <- readLines(.p)
.w <- which(regexpr("@useDynLib", .f) != -1)
if (length(.w) == 0) {
.f <- c(
paste0("#' @useDynLib ", package, ", .registration=TRUE"),
"#' @import rxode2",
.f
)
writeLines(.f, .p)
}
devtools::document()
if (!file.exists("configure.win")) {
writeLines(c(
"#!/bin/sh",
"echo \"unlink('src', recursive=TRUE);rxode2::rxUse()\" > build.R",
"${R_HOME}/bin/Rscript build.R",
"rm build.R"
), "configure.win")
}
if (!file.exists("configure")) {
writeLines(c(
"#!/bin/sh",
"echo \"unlink('src', recursive=TRUE);rxode2::rxUse()\" > build.R",
"${R_HOME}/bin/Rscript build.R",
"rm build.R"
), "configure")
if (!file.exists("configure.ac")) {
writeLines(
"## dummy autoconf script",
"configure.ac"
)
}
}
if (action == "install") {
devtools::install()
} else if (action == "build") {
devtools::build()
} else if (action == "binary") {
devtools::build(binary = TRUE)
}
invisible()
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.