Title: | Get Executing Script's Path |
---|---|
Description: | Determine the path of the executing script. Compatible with a few popular GUIs: 'Rgui', 'RStudio', 'VSCode', 'Jupyter', 'Emacs', and 'Rscript' (shell). Compatible with several functions and packages: 'source()', 'sys.source()', 'debugSource()' in 'RStudio', 'compiler::loadcmp()', 'utils::Sweave()', 'box::use()', 'knitr::knit()', 'plumber::plumb()', 'shiny::runApp()', 'package:targets', and 'testthat::source_file()'. |
Authors: | Iris Simmons |
Maintainer: | Iris Simmons <[email protected]> |
License: | MIT + file LICENSE |
Version: | 2.5.0 |
Built: | 2024-10-02 06:41:27 UTC |
Source: | CRAN |
Determine the path of the executing script.
Compatible with a few popular GUIs:
Compatible with several functions and packages:
source()
debugSource
()
in ‘RStudio’
box::use()
The most important functions from package:this.path are
this.path()
, this.dir()
, here()
,
and this.proj()
:
this.path()
returns the normalized path of the script
in which it is written.
this.dir()
returns the directory of
this.path()
.
here()
constructs file paths against
this.dir()
.
this.proj()
constructs file paths against the project
root of this.dir()
.
New additions include:
LINENO()
returns the line number of the executing
expression.
shFILE()
looks through the command line arguments,
extracting FILE from either of the following: -f
FILE or --file=FILE
set.sys.path()
implements this.path()
for
any source()
-like functions outside of the builtins.
with_init.file()
allows this.path()
and related
to be used in a user profile.
package:this.path also provides functions for constructing and manipulating file paths:
path.join()
, basename2()
, and
dirname2()
are drop in replacements for
file.path()
, basename()
, and
dirname()
which better handle drives and
network shares.
splitext()
, removeext()
,
ext()
, and ext<-()
split a path into root and
extension, remove a file extension, get an extension, or set an extension
for a file path.
path.split()
, path.split.1()
, and
path.unsplit()
split the path to a file into components.
relpath()
, rel2here()
, and
rel2proj()
turn absolute paths into relative paths.
This package started from a stack overflow posting:
https://stackoverflow.com/questions/1815606/determine-path-of-the-executing-script/64129649#64129649
If you like this package, please consider upvoting my answer so that more
people will see it! If you have an issue with this package, please use
bug.report(package = "this.path")
to
report your issue.
Iris Simmons
Maintainer: Iris Simmons <[email protected]>
basename2()
removes all of the path up to and including the last path
separator (if any).
dirname2()
returns the part of the path
up to but excluding the
last path separator, or "."
if there is no path separator.
basename2(path) dirname2(path)
basename2(path) dirname2(path)
path |
character vector, containing path names. |
Tilde-expansion (see ?path.expand()
) of the path will
be performed.
Trailing path separators are removed before dissecting the path, and for
dirname2()
any trailing file separators are removed from the result.
A character vector of the same length as path
.
If path
is an empty string, then both dirname2()
and
basename2()
return an emty string.
\
and /
are accepted as
path separators, and dirname2()
does NOT translate the path
separators.
Recall that a network share looks like "//host/share"
and a drive
looks like "d:"
.
For a path which starts with a network share or drive, the path specification
is the portion of the string immediately afterward, e.g.
"/path/to/file"
is the path specification of
"//host/share/path/to/file"
and "d:/path/to/file"
. For a path
which does not start with a network share or drive, the path specification is
the entire string.
The path specification of a network share will always be empty or absolute,
but the path specification of a drive does not have to be, e.g.
"d:file"
is a valid path despite the fact that the path specification
does not start with "/"
.
If the path specification of path
is empty or is "/"
, then
dirname2()
will return path
and basename2()
will return
an empty string.
If path
is an empty string, then both dirname2()
and
basename2()
return an emty string.
Recall that a network share looks like "//host/share"
.
For a path which starts with a network share, the path specification is the
portion of the string immediately afterward, e.g. "/path/to/file"
is
the path specification of "//host/share/path/to/file"
. For a path
which does not start with a network share, the path specification is the
entire string.
If the path specification of path
is empty or is "/"
, then
dirname2()
will return path
and basename2()
will return
an empty string.
path <- c("/usr/lib", "/usr/", "usr", "/", ".", "..") x <- cbind(path, dirname = dirname2(path), basename = basename2(path)) print(x, quote = FALSE, print.gap = 3)
path <- c("/usr/lib", "/usr/", "usr", "/", ".", "..") x <- cbind(path, dirname = dirname2(path), basename = basename2(path)) print(x, quote = FALSE, print.gap = 3)
Add check.path("path/to/file")
to the start of your script to
initialize this.path()
and check that it is returning the
expected path.
check.path(...) check.dir(...) check.proj(...)
check.path(...) check.dir(...) check.proj(...)
... |
further arguments passed to |
check.proj()
is a specialized version of check.path()
that
checks the path up to the project root.
if the expected path / / directory matches this.path()
/ /
this.dir()
, then TRUE
invisibly, otherwise an error is thrown.
# ## I have a project called 'EOAdjusted' # ## # ## Within this project, I have a folder called 'code' # ## where I place all of my scripts. # ## # ## One of these scripts is called 'provrun.R' # ## # ## So, at the top of that R script, I could write: # # # this.path::check.path("EOAdjusted", "code", "provrun.R") # # ## or: # # this.path::check.path("EOAdjusted/code/provrun.R")
# ## I have a project called 'EOAdjusted' # ## # ## Within this project, I have a folder called 'code' # ## where I place all of my scripts. # ## # ## One of these scripts is called 'provrun.R' # ## # ## So, at the top of that R script, I could write: # # # this.path::check.path("EOAdjusted", "code", "provrun.R") # # ## or: # # this.path::check.path("EOAdjusted/code/provrun.R")
These functions improve the user experience of other packages.
## enchances 'package:box' with_script_path(expr, local = FALSE, n = 0, envir = parent.frame(n + 1), matchThisEnv = getOption("topLevelEnvironment"), srcfile = if (n) sys.parent(n) else 0) ## enchances 'package:rprojroot' make_fix_file(criterion, local = FALSE, n = 0, envir = parent.frame(n + 1), matchThisEnv = getOption("topLevelEnvironment"), srcfile = if (n) sys.parent(n) else 0)
## enchances 'package:box' with_script_path(expr, local = FALSE, n = 0, envir = parent.frame(n + 1), matchThisEnv = getOption("topLevelEnvironment"), srcfile = if (n) sys.parent(n) else 0) ## enchances 'package:rprojroot' make_fix_file(criterion, local = FALSE, n = 0, envir = parent.frame(n + 1), matchThisEnv = getOption("topLevelEnvironment"), srcfile = if (n) sys.parent(n) else 0)
expr |
an expression to evaluate after setting the current script in
package:box; most commonly a call to
|
criterion |
argument passed to
|
local , n , envir , matchThisEnv , srcfile
|
See
|
with_script_path()
improves the experience of package:box; it
sets the current script in package:box to this.path()
using box::set_script_path()
, then evaluates
its argument, most commonly a package:box import statement.
make_fix_file()
improves the experience of package:rprojroot; it
looks for a project root starting with this.dir()
, then makes a
function that constructs file paths against said project root.
for with_script_path()
, the result of evaluating expr
.
for make_fix_file()
, a function with formals (..., .. = 0)
that
returns a character vector.
# this.path::with_script_path( # box::use( # <import 1>, # <import 2>, # <...> # ) # ) # ## replace 'rprojroot::is_r_package' with desired criterion # # fix_file <- this.path::make_fix_file(rprojroot::is_r_package)
# this.path::with_script_path( # box::use( # <import 1>, # <import 2>, # <...> # ) # ) # ## replace 'rprojroot::is_r_package' with desired criterion # # fix_file <- this.path::make_fix_file(rprojroot::is_r_package)
splitext()
splits an extension from a path.
removeext()
removes an extension from a path.
ext()
gets the extension of a path.
ext<-()
sets the extension of a path.
splitext(path, compression = FALSE) removeext(path, compression = FALSE) ext(path, compression = FALSE) ext(path, compression = FALSE) <- value
splitext(path, compression = FALSE) removeext(path, compression = FALSE) ext(path, compression = FALSE) ext(path, compression = FALSE) <- value
path |
character vector, containing path names. |
compression |
should compression extensions |
value |
a character vector, typically of length
|
Tilde-expansion (see ?path.expand()
) of the path will
be performed.
Trailing path separators are removed before dissecting the path.
Except for path <- NA_character_
, it will always be true that
path == paste0(removeext(path), ext(path))
.
for splitext()
, a matrix with 2
rows and
length(path)
columns. The first row will be the roots of the paths,
the second row will be the extensions of the paths.
for removeext()
and ext()
, a character vector the same length
as path
.
for ext<-()
, the updated object.
splitext(character(0)) splitext("") splitext("file.ext") path <- c("file.tar.gz", "file.tar.bz2", "file.tar.xz") splitext(path, compression = FALSE) splitext(path, compression = TRUE) path <- "this.path_2.5.0.tar.gz" ext(path) <- ".png" path path <- "this.path_2.5.0.tar.gz" ext(path, compression = TRUE) <- ".png" path
splitext(character(0)) splitext("") splitext("file.ext") path <- c("file.tar.gz", "file.tar.bz2", "file.tar.xz") splitext(path, compression = FALSE) splitext(path, compression = TRUE) path <- "this.path_2.5.0.tar.gz" ext(path) <- ".png" path path <- "this.path_2.5.0.tar.gz" ext(path, compression = TRUE) <- ".png" path
here()
constructs file paths starting with this.dir()
.
this.proj()
constructs file paths starting with the project root of
this.dir()
.
reset.proj()
resets the path cache of this.proj()
. This can be
useful if you create a new project that you would like to be detected without
restarting your R session.
here(..., local = FALSE, n = 0, envir = parent.frame(n + 1), matchThisEnv = getOption("topLevelEnvironment"), srcfile = if (n) sys.parent(n) else 0, .. = 0) this.proj(..., local = FALSE, n = 0, envir = parent.frame(n + 1), matchThisEnv = getOption("topLevelEnvironment"), srcfile = if (n) sys.parent(n) else 0) reset.proj() ## alias for 'here' ici(..., local = FALSE, n = 0, envir = parent.frame(n + 1), matchThisEnv = getOption("topLevelEnvironment"), srcfile = if (n) sys.parent(n) else 0, .. = 0)
here(..., local = FALSE, n = 0, envir = parent.frame(n + 1), matchThisEnv = getOption("topLevelEnvironment"), srcfile = if (n) sys.parent(n) else 0, .. = 0) this.proj(..., local = FALSE, n = 0, envir = parent.frame(n + 1), matchThisEnv = getOption("topLevelEnvironment"), srcfile = if (n) sys.parent(n) else 0) reset.proj() ## alias for 'here' ici(..., local = FALSE, n = 0, envir = parent.frame(n + 1), matchThisEnv = getOption("topLevelEnvironment"), srcfile = if (n) sys.parent(n) else 0, .. = 0)
... |
further arguments passed to |
local , n , envir , matchThisEnv , srcfile
|
See
|
.. |
the number of directories to go back. |
For this.proj()
, the project root has the same criterion as
here::here()
, but unlike here::here()
, this.proj()
supports sub-projects and multiple projects in use at once. Additionally,
this.proj()
is independent of working directory, whereas
here::here()
relies on the working directory being set somewhere
within the project when package:here is loaded. Arguably, this makes it
better than here::here()
.
A character vector of the arguments concatenated term-by-term.
tmpdir <- tempfile(pattern = "dir") dir.create(tmpdir) writeLines("this file signifies that its directory is the project root", this.path::path.join(tmpdir, ".here")) FILE.R <- this.path::path.join(tmpdir, "src", "R", "script1.R") dir.create(this.path::dirname2(FILE.R), recursive = TRUE) this.path:::.writeCode({ this.path::this.path() this.path::this.proj() ## use 'here' to run another script located nearby this.path::here("script2.R") ## or maybe to read input from a file this.path::here(.. = 2, "input", "data1.csv") ## but sometimes it is easier to use the project root ## this allows you to move the R script up or down ## a directory without changing the .. number this.path::this.proj("input", "data1.csv") }, FILE.R) source(FILE.R, echo = TRUE) unlink(tmpdir, recursive = TRUE)
tmpdir <- tempfile(pattern = "dir") dir.create(tmpdir) writeLines("this file signifies that its directory is the project root", this.path::path.join(tmpdir, ".here")) FILE.R <- this.path::path.join(tmpdir, "src", "R", "script1.R") dir.create(this.path::dirname2(FILE.R), recursive = TRUE) this.path:::.writeCode({ this.path::this.path() this.path::this.proj() ## use 'here' to run another script located nearby this.path::here("script2.R") ## or maybe to read input from a file this.path::here(.. = 2, "input", "data1.csv") ## but sometimes it is easier to use the project root ## this allows you to move the R script up or down ## a directory without changing the .. number this.path::this.proj("input", "data1.csv") }, FILE.R) source(FILE.R, echo = TRUE) unlink(tmpdir, recursive = TRUE)
Get the line number of the executing expression.
LINENO(n = 0, envir = parent.frame(n + 1), matchThisEnv = getOption("topLevelEnvironment"), srcfile = if (n) sys.parent(n) else 0)
LINENO(n = 0, envir = parent.frame(n + 1), matchThisEnv = getOption("topLevelEnvironment"), srcfile = if (n) sys.parent(n) else 0)
n , envir , matchThisEnv , srcfile
|
See |
LINENO()
only works if the expressions have a
srcref
.
Scripts run with Rscript
do not store their srcref
, even when
getOption("keep.source")
is TRUE
.
For source()
and sys.source()
, make sure to supply argument
keep.source = TRUE
directly, or set options "keep.source"
and
"keep.source.pkgs"
to TRUE
.
For debugSource
()
in ‘RStudio’, it has no argument keep.source
, so set
option "keep.source"
to TRUE
before calling.
For compiler::loadcmp()
, the srcref
is never stored for the compiled
code, there is nothing that can be done.
For utils::Sweave()
, the srcref
is never stored, there is nothing
that can be done.
For knitr::knit()
, the srcref
is never stored, there is nothing that
can be done. I am looking into a fix.
For package:targets, set option "keep.source"
to TRUE
before
calling associated functions.
For box::use()
, plumber::plumb()
, shiny::runApp()
, and
testthat::source_file()
, the srcref
is always stored.
integer; NA_integer_
if the line number is not found.
You can get a more accurate line number by wrapping LINENO()
in
braces:
{ LINENO() }
FILE.R <- tempfile(fileext = ".R") writeLines(c(" LINENO() LINENO() ## LINENO() respects #line directives #line 15 LINENO() #line 1218 cat(sprintf('invalid value %d at %s, line %d\\n', -5, try.this.path(), LINENO())) "), FILE.R) if (getRversion() >= "4.3.0") { source(FILE.R, echo = TRUE, verbose = FALSE, max.deparse.length = Inf, keep.source = TRUE) } else { this.path:::.source(FILE.R, echo = TRUE, verbose = FALSE, max.deparse.length = Inf, keep.source = TRUE) } unlink(FILE.R)
FILE.R <- tempfile(fileext = ".R") writeLines(c(" LINENO() LINENO() ## LINENO() respects #line directives #line 15 LINENO() #line 1218 cat(sprintf('invalid value %d at %s, line %d\\n', -5, try.this.path(), LINENO())) "), FILE.R) if (getRversion() >= "4.3.0") { source(FILE.R, echo = TRUE, verbose = FALSE, max.deparse.length = Inf, keep.source = TRUE) } else { this.path:::.source(FILE.R, echo = TRUE, verbose = FALSE, max.deparse.length = Inf, keep.source = TRUE) } unlink(FILE.R)
OS.type
is a list of TRUE
/ / FALSE
values dependent on
the platform under which this package was built.
OS.type
OS.type
A list with at least the following components:
AIX |
Built under IBM AIX. |
HPUX |
Built under Hewlett-Packard HP-UX. |
linux |
Built under some distribution of Linux. |
darwin |
Built under Apple OSX and iOS (Darwin). |
iOS.simulator |
Built under iOS in Xcode simulator. |
iOS |
Built under iOS on iPhone, iPad, etc. |
macOS |
Built under OSX. |
solaris |
Built under Solaris (SunOS). |
cygwin |
Built under Cygwin POSIX under Microsoft Windows. |
windows |
Built under Microsoft Windows. |
win64 |
Built under Microsoft Windows (64-bit). |
win32 |
Built under Microsoft Windows (32-bit). |
UNIX |
Built under a UNIX-style OS. |
path.functions()
accepts a pathname and constructs a set of
path-related functions, similar to this.path()
and associated.
path.functions(file, local = FALSE, n = 0, envir = parent.frame(n + 1), matchThisEnv = getOption("topLevelEnvironment"), srcfile = if (n) sys.parent(n) else 0)
path.functions(file, local = FALSE, n = 0, envir = parent.frame(n + 1), matchThisEnv = getOption("topLevelEnvironment"), srcfile = if (n) sys.parent(n) else 0)
file |
a character string giving the pathname of the file or URL. |
local , n , envir , matchThisEnv , srcfile
|
See |
An environment with at least the following bindings:
this.path |
Function with formals |
this.dir |
Function with no formals which returns the directory of the
|
here |
Function with formals |
this.proj |
Function with formals |
rel2here , rel2proj
|
Functions with formals |
LINENO |
Function with no formals which returns the line number of the executing
expression in |
Construct the path to a file from components / / paths in a platform-DEPENDENT way.
path.join(...)
path.join(...)
... |
character vectors. |
When constructing a path to a file, the last absolute path is selected and
all trailing components are appended. This is different from
file.path()
where all trailing paths are treated as
components.
A character vector of the arguments concatenated term-by-term and separated
by "/"
.
path.join("/", "test1") path.join("/path/to/file1", "/path/to/file2") path.join("//host-name/share-name/path/to/file1", "/path/to/file2") path.join("testing", "/testing", "~", "~/testing", "//host", "//host/share", "//host/share/path/to/file", "not-an-abs-path") path.join("/test1", "test2", "test3") path.join("test1", "/test2", "test3", "//host/share/test4", "test5", "/test6", "test7", "test8", "test9")
path.join("/", "test1") path.join("/path/to/file1", "/path/to/file2") path.join("//host-name/share-name/path/to/file1", "/path/to/file2") path.join("testing", "/testing", "~", "~/testing", "//host", "//host/share", "//host/share/path/to/file", "not-an-abs-path") path.join("/test1", "test2", "test3") path.join("test1", "/test2", "test3", "//host/share/test4", "test5", "/test6", "test7", "test8", "test9")
Split the path to a file into components in a platform-DEPENDENT way.
path.split(path) path.split.1(path) path.unsplit(...)
path.split(path) path.split.1(path) path.unsplit(...)
path |
character vector. |
... |
character vectors, or one list of character vectors. |
for path.split()
, a list of character vectors.
for path.split.1()
and path.unsplit()
, a character vector.
path.unsplit()
is NOT the same as path.join()
.
path <- c( NA, "", paste0("https://raw.githubusercontent.com/ArcadeAntics/PACKAGES/", "src/contrib/Archive/this.path/this.path_1.0.0.tar.gz"), "//host/share/path/to/file", "//host/share/", "//host//share", "/path/to/file", "~/path/to/file", "path/to/file", ## paths with character encodings `Encoding<-`("path/to/fil\xe9", "latin1"), "/home/iris/Documents/\u03b4.R" ) print(x <- path.split(path)) print(path.unsplit(x))
path <- c( NA, "", paste0("https://raw.githubusercontent.com/ArcadeAntics/PACKAGES/", "src/contrib/Archive/this.path/this.path_1.0.0.tar.gz"), "//host/share/path/to/file", "//host/share/", "//host//share", "/path/to/file", "~/path/to/file", "path/to/file", ## paths with character encodings `Encoding<-`("path/to/fil\xe9", "latin1"), "/home/iris/Documents/\u03b4.R" ) print(x <- path.split(path)) print(path.unsplit(x))
When working with this.path, you will be dealing with a lot of absolute
paths. These paths are not portable for saving within files nor tables, so
convert them to relative paths with relpath()
.
relpath(path, relative.to = getwd()) rel2here(path, local = FALSE, n = 0, envir = parent.frame(n + 1), matchThisEnv = getOption("topLevelEnvironment"), srcfile = if (n) sys.parent(n) else 0) rel2proj(path, local = FALSE, n = 0, envir = parent.frame(n + 1), matchThisEnv = getOption("topLevelEnvironment"), srcfile = if (n) sys.parent(n) else 0)
relpath(path, relative.to = getwd()) rel2here(path, local = FALSE, n = 0, envir = parent.frame(n + 1), matchThisEnv = getOption("topLevelEnvironment"), srcfile = if (n) sys.parent(n) else 0) rel2proj(path, local = FALSE, n = 0, envir = parent.frame(n + 1), matchThisEnv = getOption("topLevelEnvironment"), srcfile = if (n) sys.parent(n) else 0)
path |
character vector of file / / URL pathnames. |
relative.to |
character string; the file / / URL pathname to make
|
local , n , envir , matchThisEnv , srcfile
|
See
|
Tilde-expansion (see ?path.expand()
) is first done on
path
and relative.to
.
If path
and relative.to
are equivalent, "."
will be
returned. If path
and relative.to
have no base in common, the
normalized
path
will be returned.
character vector of the same length as path
.
## Not run: relpath( c( ## paths which are equivalent will return "." "/home/effective_user/Documents/this.path/man", ## paths which have no base in common return as themselves paste0("https://raw.githubusercontent.com/ArcadeAntics/", "this.path/main/tests/sys-path-with-urls.R"), "//host-name/share-name/path/to/file", "/home/effective_user/Documents/testing", "/home/effective_user", "/home/effective_user/Documents/R/thispath.R" ), relative.to = "/home/effective_user/Documents/this.path/man" ) ## End(Not run)
## Not run: relpath( c( ## paths which are equivalent will return "." "/home/effective_user/Documents/this.path/man", ## paths which have no base in common return as themselves paste0("https://raw.githubusercontent.com/ArcadeAntics/", "this.path/main/tests/sys-path-with-urls.R"), "//host-name/share-name/path/to/file", "/home/effective_user/Documents/testing", "/home/effective_user", "/home/effective_user/Documents/R/thispath.R" ), relative.to = "/home/effective_user/Documents/this.path/man" ) ## End(Not run)
set.gui.path()
can be used to implement this.path()
for
arbitrary GUIs. This is similar to set.sys.path()
which can be
used to implement sys.path()
for arbitrary source()
-like
functions.
set.gui.path(...) thisPathNotExistsError(..., call. = TRUE, domain = NULL, call = .getCurrentCall()) thisPathNotFoundError(..., call. = TRUE, domain = NULL, call = .getCurrentCall())
set.gui.path(...) thisPathNotExistsError(..., call. = TRUE, domain = NULL, call = .getCurrentCall()) thisPathNotFoundError(..., call. = TRUE, domain = NULL, call = .getCurrentCall())
... , call. , domain , call
|
See details. |
thisPathNotExistsError()
and thisPathNotFoundError()
are
provided for use inside set.gui.path()
, and should not be used
elsewhere.
If no arguments are passed to set.gui.path()
, the default behaviour
will be restored.
If one argument is passed to set.gui.path()
, it must be a function
that returns the path of the active document in your GUI. It must accept the
following arguments: (verbose, original, for.msg, contents)
(default
values are unnecessary). This makes sense for a GUI which can edit and run R
code from several different documents such as RGui, RStudio, VSCode, and
Emacs.
If two or three arguments are passed to set.gui.path()
, they must be
the name of the GUI, the path of the active document, and optionally a
function to get the contents of the document. If provided, the function must
accept at least one argument which will be the normalized path of the
document. This makes sense for a GUI which can edit and run R code from only
one document such as Jupyter and shell.
It is best to call this function as a user hook.
setHook(packageEvent("this.path"), function(pkgname, pkgpath) { this.path::set.gui.path(<...>) }, action = "prepend")
An example for a GUI which can run code from multiple documents:
evalq(envir = new.env(parent = .BaseNamespaceEnv), { .guiname <- "myGui" .custom_gui_path <- function(verbose, original, for.msg, contents) { if (verbose) cat("Source: document in", .guiname, "\n") ## your GUI needs to know which document is active ## and some way to retrieve that document from R doc <- <.myGui_activeDocument()> ## if no documents are open, 'doc' should be NULL ## or some other object to represent no documents open if (is.null(doc)) { if (for.msg) NA_character_ else stop(this.path::thisPathNotExistsError( "R is running from ", .guiname, " with no documents open\n", " (or document has no path)")) } else if (contents) { ## somehow, get and return the contents of the document <doc$contents> } else { ## somehow, get the path of the document path <- <doc$path> if (nzchar(path)) { ## if the path is not normalized, this will normalize it if (isTRUE(original)) path else normalizePath(path, "/", TRUE) # ## otherwise, you could just do: # path } else if (for.msg) ## return "Untitled" possibly translated gettext("Untitled", domain = "RGui", trim = FALSE) else stop(this.path::thisPathNotFoundError( "document in ", .guiname, " does not exist")) } } ## recommended to prevent tampering lockEnvironment(environment(), bindings = TRUE) setHook(packageEvent("this.path"), function(pkgname, pkgpath) { this.path::set.gui.path(.custom_gui_path) }, action = "prepend") })
An example for a GUI which can run code from only one document:
evalq(envir = new.env(parent = .BaseNamespaceEnv), { .guiname <- "myGui" .path <- "~/example.R" .custom_get_contents <- function(path) { ## get the contents of the document readLines(path, warn = FALSE) } ## recommended to prevent tampering lockEnvironment(environment(), bindings = TRUE) setHook(packageEvent("this.path"), function(pkgname, pkgpath) { this.path::set.gui.path(.guiname, .path, .custom_get_contents) }, action = "prepend") # ## if your GUI does not have/need a .custom_get_contents # ## function, then this works just as well: # setHook(packageEvent("this.path"), function(pkgname, pkgpath) { # this.path::set.gui.path(.guiname, .path) # }, action = "prepend") })
a list of the previous settings for set.gui.path()
, similar to
options()
.
this.path()
does some guess work to determine the path of the
executing notebook in ‘Jupyter’. This involves listing all the files
in the initial working directory, filtering those which are R notebooks,
then filtering those with contents matching the top-level expression.
This could possibly select the wrong file if the same top-level expression is
found in another file. As such, you can use set.jupyter.path()
to
declare the executing ‘Jupyter’ notebook's filename.
set.jupyter.path(...)
set.jupyter.path(...)
... |
further arguments passed to |
This function may only be called from a top-level context in ‘Jupyter’. It is recommended that you do NOT provide an absolute path. Instead, provide just the basename and the directory will be determined by the initial working directory.
character string, invisibly; the declared path for ‘Jupyter’.
# ## if you opened the file "~/file50b816a24ec1.ipynb", the initial # ## working directory should be "~". You can write: # # set.jupyter.path("file50b816a24ec1.ipynb") # # ## and then this.path() will return "~/file50b816a24ec1.ipynb"
# ## if you opened the file "~/file50b816a24ec1.ipynb", the initial # ## working directory should be "~". You can write: # # set.jupyter.path("file50b816a24ec1.ipynb") # # ## and then this.path() will return "~/file50b816a24ec1.ipynb"
sys.path()
is implemented to work with these functions and
packages:
source()
debugSource
()
in ‘RStudio’
box::use()
set.sys.path()
can be used to implement sys.path()
for any
other source()
-like functions.
set.env.path()
and set.src.path()
can be used alongside
set.sys.path()
to implement env.path()
and
src.path()
, thereby fully implementing
this.path()
. Note that set.env.path()
only makes sense
if the code is being modularized, see Examples.
unset.sys.path()
will undo a call to set.sys.path()
. You will
need to use this if you wish to call set.sys.path()
multiple times
within a function.
set.sys.path.function()
is a special variant of set.sys.path()
to be called within callr::r()
on a function with an appropriate
srcref
.
with_sys.path()
is a convenient way to evaluate code within the
context of a file. Whereas set.sys.path()
can only be used within a
function, with_sys.path()
can only be used outside a function.
See ?sys.path(local = TRUE)
which returns the path of the
executing script, confining the search to the local environment in which
set.sys.path()
was called.
wrap.source()
should not be used, save for one specific use-case. See
details.
set.sys.path(file, path.only = FALSE, character.only = path.only, file.only = path.only, conv2utf8 = FALSE, allow.blank.string = FALSE, allow.clipboard = !file.only, allow.stdin = !file.only, allow.url = !file.only, allow.file.uri = !path.only, allow.unz = !path.only, allow.pipe = !file.only, allow.terminal = !file.only, allow.textConnection = !file.only, allow.rawConnection = !file.only, allow.sockconn = !file.only, allow.servsockconn = !file.only, allow.customConnection = !file.only, ignore.all = FALSE, ignore.blank.string = ignore.all, ignore.clipboard = ignore.all, ignore.stdin = ignore.all, ignore.url = ignore.all, ignore.file.uri = ignore.all, Function = NULL, ofile) set.env.path(envir, matchThisEnv = getOption("topLevelEnvironment")) set.src.path(srcfile) unset.sys.path() set.sys.path.function(fun) with_sys.path(file, expr, ...) wrap.source(expr, path.only = FALSE, character.only = path.only, file.only = path.only, conv2utf8 = FALSE, allow.blank.string = FALSE, allow.clipboard = !file.only, allow.stdin = !file.only, allow.url = !file.only, allow.file.uri = !path.only, allow.unz = !path.only, allow.pipe = !file.only, allow.terminal = !file.only, allow.textConnection = !file.only, allow.rawConnection = !file.only, allow.sockconn = !file.only, allow.servsockconn = !file.only, allow.customConnection = !file.only, ignore.all = FALSE, ignore.blank.string = ignore.all, ignore.clipboard = ignore.all, ignore.stdin = ignore.all, ignore.url = ignore.all, ignore.file.uri = ignore.all)
set.sys.path(file, path.only = FALSE, character.only = path.only, file.only = path.only, conv2utf8 = FALSE, allow.blank.string = FALSE, allow.clipboard = !file.only, allow.stdin = !file.only, allow.url = !file.only, allow.file.uri = !path.only, allow.unz = !path.only, allow.pipe = !file.only, allow.terminal = !file.only, allow.textConnection = !file.only, allow.rawConnection = !file.only, allow.sockconn = !file.only, allow.servsockconn = !file.only, allow.customConnection = !file.only, ignore.all = FALSE, ignore.blank.string = ignore.all, ignore.clipboard = ignore.all, ignore.stdin = ignore.all, ignore.url = ignore.all, ignore.file.uri = ignore.all, Function = NULL, ofile) set.env.path(envir, matchThisEnv = getOption("topLevelEnvironment")) set.src.path(srcfile) unset.sys.path() set.sys.path.function(fun) with_sys.path(file, expr, ...) wrap.source(expr, path.only = FALSE, character.only = path.only, file.only = path.only, conv2utf8 = FALSE, allow.blank.string = FALSE, allow.clipboard = !file.only, allow.stdin = !file.only, allow.url = !file.only, allow.file.uri = !path.only, allow.unz = !path.only, allow.pipe = !file.only, allow.terminal = !file.only, allow.textConnection = !file.only, allow.rawConnection = !file.only, allow.sockconn = !file.only, allow.servsockconn = !file.only, allow.customConnection = !file.only, ignore.all = FALSE, ignore.blank.string = ignore.all, ignore.clipboard = ignore.all, ignore.stdin = ignore.all, ignore.url = ignore.all, ignore.file.uri = ignore.all)
expr |
for for |
file |
a
|
path.only |
must |
character.only |
must |
file.only |
must |
conv2utf8 |
if |
allow.blank.string |
may |
allow.clipboard |
may |
allow.stdin |
may |
allow.url |
may |
allow.file.uri |
may |
allow.unz , allow.pipe , allow.terminal , allow.textConnection , allow.rawConnection , allow.sockconn , allow.servsockconn
|
may
|
allow.customConnection |
may |
ignore.all , ignore.blank.string , ignore.clipboard , ignore.stdin , ignore.url , ignore.file.uri
|
ignore the special meaning of these types of strings, treating it as a path instead? |
Function |
character vector of length |
ofile |
a
|
envir , matchThisEnv
|
arguments passed to
|
srcfile |
source file in which to assign a pathname. |
fun |
function with a |
... |
further arguments passed to |
set.sys.path()
should be added to the body of your source()
-like
function before reading / / evaluating the expressions.
wrap.source()
, unlike set.sys.path()
, does not accept an
argument file
. Instead, an attempt is made to extract the file from
expr
, after which expr
is evaluated. It is assumed that the
file is the first argument of the function, as is the case with most
source()
-like functions. The function of the call is evaluated, its
formals()
are retrieved,
and then the arguments of expr
are searched for a name matching the
name of the first formal argument. If a match cannot be found by name, the
first unnamed argument is taken instead. If no such argument exists, the file
is assumed missing.
wrap.source()
does non-standard evaluation and does some guess work to
determine the file. As such, it is less desirable than set.sys.path()
when the option is available. I can think of exactly one scenario in which
wrap.source()
might be preferable: suppose there is a
source()
-like function sourcelike()
in a foreign package (a
package for which you do not have write permission). Suppose that you write
your own function in which the formals are (...)
to wrap
sourcelike()
:
wrapper <- function (...) { ## possibly more args to wrap.source() wrap.source(sourcelike(...)) }
This is the only scenario in which wrap.source()
is preferable, since
extracting the file from the ...
list would be a pain. Then again,
you could simply change the formals of wrapper()
from (...)
to (file, ...)
. If this does not describe your exact scenario, use
set.sys.path()
instead.
for set.sys.path()
, if file
is a path, then the normalized
path with the same attributes, otherwise file
itself. The return value
of set.sys.path()
should be assigned to a variable before use,
something like:
{ file <- set.sys.path(file, ...) sourcelike(file) }
for wrap.source()
, the result of evaluating expr
.
ofile
can be used when the file
argument supplied to
set.sys.path()
is not the same as the file
argument supplied to
the source()
-like function:
sourcelike <- function (file) { ofile <- file if (!is.character(ofile) || length(ofile) != 1) stop(gettextf("'%s' must be a character string", "file")) ## if the file exists, do nothing if (file.exists(file)) { } ## look for the file in the home directory ## if it exists, do nothing else if (file.exists(file <- this.path::path.join("~", ofile))) { } ## you could add other directories to look in, ## but this is good enough for an example else stop(gettextf("'%s' is not an existing file", ofile)) file <- this.path::set.sys.path(file, ofile = ofile) exprs <- parse(n = -1, file = file) for (i in seq_along(exprs)) eval(exprs[i], envir) invisible() }
FILE.R <- tempfile(fileext = ".R") this.path:::.writeCode({ this.path::sys.path(verbose = TRUE) try(this.path::env.path(verbose = TRUE)) this.path::src.path(verbose = TRUE) this.path::this.path(verbose = TRUE) }, FILE.R) ## here we have a source-like function, suppose this ## function is in a package for which you have write permission sourcelike <- function (file, envir = parent.frame()) { ofile <- file file <- set.sys.path(file, Function = "sourcelike") lines <- readLines(file, warn = FALSE) filename <- sys.path(local = TRUE, for.msg = TRUE) isFile <- !is.na(filename) if (isFile) { timestamp <- file.mtime(filename)[1] ## in case 'ofile' is a URL pathname / / 'unz' connection if (is.na(timestamp)) timestamp <- Sys.time() } else { filename <- if (is.character(ofile)) ofile else "<connection>" timestamp <- Sys.time() } srcfile <- srcfilecopy(filename, lines, timestamp, isFile) set.src.path(srcfile) exprs <- parse(text = lines, srcfile = srcfile, keep.source = FALSE) invisible(source.exprs(exprs, evaluated = TRUE, envir = envir)) } sourcelike(FILE.R) sourcelike(conn <- file(FILE.R)); close(conn) ## here we have another source-like function, suppose this function ## is in a foreign package for which you do not have write permission sourcelike2 <- function (pathname, envir = globalenv()) { if (!(is.character(pathname) && file.exists(pathname))) stop(gettextf("'%s' is not an existing file", pathname, domain = "R-base")) envir <- as.environment(envir) lines <- readLines(pathname, warn = FALSE) srcfile <- srcfilecopy(pathname, lines, isFile = TRUE) exprs <- parse(text = lines, srcfile = srcfile, keep.source = FALSE) invisible(source.exprs(exprs, evaluated = TRUE, envir = envir)) } ## the above function is similar to sys.source(), and it ## expects a character string referring to an existing file ## ## with the following, you should be able ## to use 'sys.path()' within 'FILE.R': wrap.source(sourcelike2(FILE.R), path.only = TRUE) # ## with R >= 4.1.0, use the forward pipe operator '|>' to # ## make calls to 'wrap.source' more intuitive: # sourcelike2(FILE.R) |> wrap.source(path.only = TRUE) ## 'wrap.source' can recognize arguments by name, so they ## do not need to appear in the same order as the formals wrap.source(sourcelike2(envir = new.env(), pathname = FILE.R), path.only = TRUE) ## it it much easier to define a new function to do this sourcelike3 <- function (...) wrap.source(sourcelike2(...), path.only = TRUE) ## the same as before sourcelike3(FILE.R) ## however, this is preferable: sourcelike4 <- function (pathname, ...) { ## pathname is now normalized pathname <- set.sys.path(pathname, path.only = TRUE) sourcelike2(pathname = pathname, ...) } sourcelike4(FILE.R) ## perhaps you wish to run several scripts in the same function fun <- function (paths, ...) { for (pathname in paths) { pathname <- set.sys.path(pathname, path.only = TRUE) sourcelike2(pathname = pathname, ...) unset.sys.path(pathname) } } ## here we have a source-like function which modularizes its code sourcelike5 <- function (file) { ofile <- file file <- set.sys.path(file, Function = "sourcelike5") lines <- readLines(file, warn = FALSE) filename <- sys.path(local = TRUE, for.msg = TRUE) isFile <- !is.na(filename) if (isFile) { timestamp <- file.mtime(filename)[1] ## in case 'ofile' is a URL pathname / / 'unz' connection if (is.na(timestamp)) timestamp <- Sys.time() } else { filename <- if (is.character(ofile)) ofile else "<connection>" timestamp <- Sys.time() } srcfile <- srcfilecopy(filename, lines, timestamp, isFile) set.src.path(srcfile) envir <- new.env(hash = TRUE, parent = .BaseNamespaceEnv) envir$.packageName <- filename oopt <- options(topLevelEnvironment = envir) on.exit(options(oopt)) set.env.path(envir) exprs <- parse(text = lines, srcfile = srcfile, keep.source = FALSE) source.exprs(exprs, evaluated = TRUE, envir = envir) envir } sourcelike5(FILE.R) ## the code can be made much simpler in some cases sourcelike6 <- function (file) { ## we expect a character string refering to a file ofile <- file filename <- set.sys.path(file, path.only = TRUE, ignore.all = TRUE, Function = "sourcelike6") lines <- readLines(filename, warn = FALSE) timestamp <- file.mtime(filename)[1] srcfile <- srcfilecopy(filename, lines, timestamp, isFile = TRUE) set.src.path(srcfile) envir <- new.env(hash = TRUE, parent = .BaseNamespaceEnv) envir$.packageName <- filename oopt <- options(topLevelEnvironment = envir) on.exit(options(oopt)) set.env.path(envir) exprs <- parse(text = lines, srcfile = srcfile, keep.source = FALSE) source.exprs(exprs, evaluated = TRUE, envir = envir) envir } sourcelike6(FILE.R) unlink(FILE.R)
FILE.R <- tempfile(fileext = ".R") this.path:::.writeCode({ this.path::sys.path(verbose = TRUE) try(this.path::env.path(verbose = TRUE)) this.path::src.path(verbose = TRUE) this.path::this.path(verbose = TRUE) }, FILE.R) ## here we have a source-like function, suppose this ## function is in a package for which you have write permission sourcelike <- function (file, envir = parent.frame()) { ofile <- file file <- set.sys.path(file, Function = "sourcelike") lines <- readLines(file, warn = FALSE) filename <- sys.path(local = TRUE, for.msg = TRUE) isFile <- !is.na(filename) if (isFile) { timestamp <- file.mtime(filename)[1] ## in case 'ofile' is a URL pathname / / 'unz' connection if (is.na(timestamp)) timestamp <- Sys.time() } else { filename <- if (is.character(ofile)) ofile else "<connection>" timestamp <- Sys.time() } srcfile <- srcfilecopy(filename, lines, timestamp, isFile) set.src.path(srcfile) exprs <- parse(text = lines, srcfile = srcfile, keep.source = FALSE) invisible(source.exprs(exprs, evaluated = TRUE, envir = envir)) } sourcelike(FILE.R) sourcelike(conn <- file(FILE.R)); close(conn) ## here we have another source-like function, suppose this function ## is in a foreign package for which you do not have write permission sourcelike2 <- function (pathname, envir = globalenv()) { if (!(is.character(pathname) && file.exists(pathname))) stop(gettextf("'%s' is not an existing file", pathname, domain = "R-base")) envir <- as.environment(envir) lines <- readLines(pathname, warn = FALSE) srcfile <- srcfilecopy(pathname, lines, isFile = TRUE) exprs <- parse(text = lines, srcfile = srcfile, keep.source = FALSE) invisible(source.exprs(exprs, evaluated = TRUE, envir = envir)) } ## the above function is similar to sys.source(), and it ## expects a character string referring to an existing file ## ## with the following, you should be able ## to use 'sys.path()' within 'FILE.R': wrap.source(sourcelike2(FILE.R), path.only = TRUE) # ## with R >= 4.1.0, use the forward pipe operator '|>' to # ## make calls to 'wrap.source' more intuitive: # sourcelike2(FILE.R) |> wrap.source(path.only = TRUE) ## 'wrap.source' can recognize arguments by name, so they ## do not need to appear in the same order as the formals wrap.source(sourcelike2(envir = new.env(), pathname = FILE.R), path.only = TRUE) ## it it much easier to define a new function to do this sourcelike3 <- function (...) wrap.source(sourcelike2(...), path.only = TRUE) ## the same as before sourcelike3(FILE.R) ## however, this is preferable: sourcelike4 <- function (pathname, ...) { ## pathname is now normalized pathname <- set.sys.path(pathname, path.only = TRUE) sourcelike2(pathname = pathname, ...) } sourcelike4(FILE.R) ## perhaps you wish to run several scripts in the same function fun <- function (paths, ...) { for (pathname in paths) { pathname <- set.sys.path(pathname, path.only = TRUE) sourcelike2(pathname = pathname, ...) unset.sys.path(pathname) } } ## here we have a source-like function which modularizes its code sourcelike5 <- function (file) { ofile <- file file <- set.sys.path(file, Function = "sourcelike5") lines <- readLines(file, warn = FALSE) filename <- sys.path(local = TRUE, for.msg = TRUE) isFile <- !is.na(filename) if (isFile) { timestamp <- file.mtime(filename)[1] ## in case 'ofile' is a URL pathname / / 'unz' connection if (is.na(timestamp)) timestamp <- Sys.time() } else { filename <- if (is.character(ofile)) ofile else "<connection>" timestamp <- Sys.time() } srcfile <- srcfilecopy(filename, lines, timestamp, isFile) set.src.path(srcfile) envir <- new.env(hash = TRUE, parent = .BaseNamespaceEnv) envir$.packageName <- filename oopt <- options(topLevelEnvironment = envir) on.exit(options(oopt)) set.env.path(envir) exprs <- parse(text = lines, srcfile = srcfile, keep.source = FALSE) source.exprs(exprs, evaluated = TRUE, envir = envir) envir } sourcelike5(FILE.R) ## the code can be made much simpler in some cases sourcelike6 <- function (file) { ## we expect a character string refering to a file ofile <- file filename <- set.sys.path(file, path.only = TRUE, ignore.all = TRUE, Function = "sourcelike6") lines <- readLines(filename, warn = FALSE) timestamp <- file.mtime(filename)[1] srcfile <- srcfilecopy(filename, lines, timestamp, isFile = TRUE) set.src.path(srcfile) envir <- new.env(hash = TRUE, parent = .BaseNamespaceEnv) envir$.packageName <- filename oopt <- options(topLevelEnvironment = envir) on.exit(options(oopt)) set.env.path(envir) exprs <- parse(text = lines, srcfile = srcfile, keep.source = FALSE) source.exprs(exprs, evaluated = TRUE, envir = envir) envir } sourcelike6(FILE.R) unlink(FILE.R)
Look through the command line arguments, extracting FILE from either of the following: -f FILE or --file=FILE
shFILE(original = FALSE, for.msg = FALSE, default, else.)
shFILE(original = FALSE, for.msg = FALSE, default, else.)
original |
|
for.msg |
|
default |
if FILE is not found, this value is returned. |
else. |
missing or a function to apply if FILE is found. See
|
character string, or default
if FILE was not found.
The original and the normalized path are saved; this makes them faster when called subsequent times.
On Windows, the normalized path will use /
as the
file separator.
FILE.R <- tempfile(fileext = ".R") this.path:::.writeCode({ this.path:::.withAutoprint({ shFILE(original = TRUE) shFILE() shFILE(default = { stop("since 'FILE.R' will be found,\n", "this error will not be thrown") }) }, spaced = TRUE, verbose = FALSE, width.cutoff = 60L) }, FILE.R) this.path:::.Rscript( c("--default-packages=this.path", "--vanilla", FILE.R) ) unlink(FILE.R) for (expr in c("shFILE(original = TRUE)", "shFILE(original = TRUE, default = NULL)", "shFILE()", "shFILE(default = NULL)")) { cat("\n\n") this.path:::.Rscript( c("--default-packages=this.path", "--vanilla", "-e", expr) ) }
FILE.R <- tempfile(fileext = ".R") this.path:::.writeCode({ this.path:::.withAutoprint({ shFILE(original = TRUE) shFILE() shFILE(default = { stop("since 'FILE.R' will be found,\n", "this error will not be thrown") }) }, spaced = TRUE, verbose = FALSE, width.cutoff = 60L) }, FILE.R) this.path:::.Rscript( c("--default-packages=this.path", "--vanilla", FILE.R) ) unlink(FILE.R) for (expr in c("shFILE(original = TRUE)", "shFILE(original = TRUE, default = NULL)", "shFILE()", "shFILE(default = NULL)")) { cat("\n\n") this.path:::.Rscript( c("--default-packages=this.path", "--vanilla", "-e", expr) ) }
site.file()
and init.file()
return the
normalized
paths
of the site-wide startup profile file and the user profile that were run at
startup
.
with_init.file()
declares that the current script is the user profile
then evaluates and auto-prints the sub-expressions of its argument.
site.file(original = FALSE, for.msg = FALSE, default, else.) init.file(original = FALSE, for.msg = FALSE, default, else.) with_site.file(expr) with_init.file(expr)
site.file(original = FALSE, for.msg = FALSE, default, else.) init.file(original = FALSE, for.msg = FALSE, default, else.) with_site.file(expr) with_init.file(expr)
original , for.msg , default , else.
|
Same as |
expr |
a braced expression, the sub-expressions of which to evaluate and auto-print. |
for site.file()
and init.file()
, a character string, or
default
if it was not found.
for with_site.file()
and with_init.file()
, NULL
invisibly.
with_site.file()
is unneeded now that the site-wide startup profile
file can be automatically detected.
## if you wish to use this.path() in a user profile, ## instead of writing: ## ## <expr 1> ## <expr 2> ## <...> ## ## write this: ## ## this.path::with_init.file({ ## <expr 1> ## <expr 2> ## <...> ## })
## if you wish to use this.path() in a user profile, ## instead of writing: ## ## <expr 1> ## <expr 2> ## <...> ## ## write this: ## ## this.path::with_init.file({ ## <expr 1> ## <expr 2> ## <...> ## })
this.path()
returns the
normalized
path of
the script in which it was written.
this.dir()
returns the directory of this.path()
.
this.path(verbose = getOption("verbose"), original = FALSE, for.msg = FALSE, contents = FALSE, local = FALSE, n = 0, envir = parent.frame(n + 1), matchThisEnv = getOption("topLevelEnvironment"), srcfile = if (n) sys.parent(n) else 0, default, else.) this.dir(verbose = getOption("verbose"), local = FALSE, n = 0, envir = parent.frame(n + 1), matchThisEnv = getOption("topLevelEnvironment"), srcfile = if (n) sys.parent(n) else 0, default, else.)
this.path(verbose = getOption("verbose"), original = FALSE, for.msg = FALSE, contents = FALSE, local = FALSE, n = 0, envir = parent.frame(n + 1), matchThisEnv = getOption("topLevelEnvironment"), srcfile = if (n) sys.parent(n) else 0, default, else.) this.dir(verbose = getOption("verbose"), local = FALSE, n = 0, envir = parent.frame(n + 1), matchThisEnv = getOption("topLevelEnvironment"), srcfile = if (n) sys.parent(n) else 0, default, else.)
verbose |
|
original |
|
for.msg |
|
contents |
In ‘Jupyter’, a list of character vectors will be returned, the
contents separated into cells. Otherwise, a character vector will be
returned. If the executing script cannot be determined and You could use
This is intended for logging purposes. This is useful in ‘Rgui’, ‘RStudio’, ‘VSCode’, and ‘Emacs’ when the source document has contents but no path. |
local |
|
n |
the number of additional generations to go back. By default,
|
envir , matchThisEnv
|
arguments passed to
|
srcfile |
source file in which to search for a pathname, or an object containing a source file. This includes a source reference, a call, an expression object, or a closure. |
default |
this value is returned if there is no executing script. |
else. |
function to apply if there is an executing script. See
|
this.path()
starts by examining argument srcfile
. It looks at
the bindings filename
and wd
to determine the associated file
path. A source file of class "srcfilecopy"
in which binding
isFile
is FALSE
will be ignored. A source file of class
"srcfilealias"
will use the aliased filename
in determining the
associated path. Filenames such as ""
, "clipboard"
, and
"stdin"
will be ignored since they do not refer to files.
If it does not find a path associated with srcfile
, it will next
examine arguments envir
and matchThisEnv
. Specifically, it
calculates topenv(envir, matchThisEnv)
then
looks for an associated path. It will find a path associated with the top
level environment in two ways:
from a package:box module's namespace
from an attribute "path"
If it does not find an associated path with envir
and
matchThisEnv
, it will next examine the call stack looking for a source
call; a call to one of these functions:
source()
debugSource
()
in ‘RStudio’
box::use()
targets::tar_callr_inner_try()
targets::tar_load_globals()
targets::tar_source()
targets::tar_workspace()
If a source call is
found, the file argument is returned from the function's evaluation
environment. If you have your own source()
-like function that you would
like to be recognized by this.path()
, please use
set.sys.path()
or contact the package maintainer so that it can
be implemented.
If no source call is found up the calling stack, it will next examine the GUI in use. If R is running from:
then the shell arguments are searched for -f FILE or --file=FILE (the two methods of taking input from FILE) (-f - and --file=- are ignored). The last FILE is extracted and returned. If no arguments of either type are supplied, an error is thrown.
If R is running from a shell under a Unix-alike with -g Tk or --gui=Tk, an error is thrown. ‘Tk’ does not make use of its -f FILE, --file=FILE arguments.
then the source document's filename (the document most recently
interacted with) is returned (at the time of evaluation). Please note
that minimized documents WILL be included when looking for the
most recently used document. It is important to not leave the current
document (either by closing the document or interacting with another
document) while any calls to this.path()
have yet to be evaluated
in the run selection. If no documents are open or the source document
does not exist (not saved anywhere), an error is thrown.
then the active document's filename (the document in which the cursor is
active) is returned (at the time of evaluation). If the active document
is the R console, the source document's filename (the document open in
the current tab) is returned (at the time of evaluation). Please note
that the source document will NEVER be a document open in another
window (with the Show in new window button). Please also note
that an active document open in another window can sometimes lose focus
and become inactive, thus returning the incorrect path. It is best
NOT to not run R code from a document open in another window.
It is important to not leave the current tab (either by closing or
switching tabs) while any calls to this.path()
have yet to be
evaluated in the run selection. If no documents are open or the source
document does not exist (not saved anywhere), an error is thrown.
then the source document's filename is returned (at the time of
evaluation). It is important to not leave the current tab (either by
closing or switching tabs) while any calls to this.path()
have yet
to be evaluated in the run selection. If no documents are open or the
source document does not exist (not saved anywhere), an error is thrown.
then the source document's filename is guessed by looking for R
notebooks in the initial working directory, then searching the contents
of those files for an expression matching the top-level expression.
Please be sure to save your notebook before using this.path()
, or
explicitly use set.jupyter.path()
.
then the source document's filename is returned (at the time of
evaluation). ‘Emacs’ must be running as a server, either by
running (server-start)
(consider adding to your ‘~/.emacs’
file) or typing M-x server-start
. It is important to not leave the
current window (either by closing or switching buffers) while any calls
to this.path()
have yet to be evaluated in the run selection. If
multiple frames are active, this.path()
will pick the first frame
containing the corresponding R session.
If multiple ‘Emacs’ sessions are active, this.path()
will
only work in the primary session due to limitations in
‘emacsclient’.
If you want to run multiple R sessions, it is better to run one
‘Emacs’ session with multiple frames, one R session per frame.
Use M-x make-frame
to make a new frame, or C-x 5 f
to visit
a file in a new frame.
Additionally, never use C-c C-b
to send the current buffer to the
R process. This copies the buffer contents to a new file which is then
source()
-ed. The source references now point to the wrong file.
Instead, use C-x h
to select the entire buffer then C-c C-r
to evaluate the selection.
then the executing script's path cannot be determined. Unlike ‘Rgui’, ‘RStudio’, ‘VSCode’, ‘Jupyter’, and ‘Emacs’, there is currently no way to request the path of an open document. Until such a time that there is a method for requesting the path of an open document, consider using another GUI.
If R is running in another manner, an error is thrown.
If your GUI of choice is not implemented with this.path()
, please
contact the package maintainer so that it can be implemented.
character string.
By default, this.path()
will look for a path based on the
srcref
of the call to this.path()
and the environment in which
this.path()
was called. For example:
{ #line 1 "file1.R" fun <- function() this.path::this.path(original = TRUE) fun() } { #line 1 "file2.R" fun() }
Both of these will return "file1.R"
because that is where the call to
this.path()
is written.
But suppose we do not care to know where this.path()
is called, but
instead want to know where fun()
is called. Pass argument n = 1
;
this.path()
will inspect the call and the calling environment one
generation up the stack:
{ #line 1 "file1.R" fun <- function() this.path::this.path(original = TRUE, n = 1) fun() } { #line 1 "file2.R" fun() }
These will return "file1.R"
and "file2.R"
, respectively,
because those are where the calls to fun()
are written.
But now suppose we wish to make a second function that uses fun()
. We
do not care to know where fun()
is called, but instead want to know
where fun2()
is called. Add a formal argument n = 0
to each
function and pass n = n + 1
to each sub-function:
{ #line 1 "file1.R" fun <- function(n = 0) { this.path::this.path(original = TRUE, n = n + 1) } fun() } { #line 1 "file2.R" fun2 <- function(n = 0) fun(n = n + 1) list(fun = fun(), fun2 = fun2()) } { #line 1 "file3.R" fun3 <- function(n = 0) fun2(n = n + 1) list(fun = fun(), fun2 = fun2(), fun3 = fun3()) }
Within each file, all these functions will return the path in which they are
called, regardless of how deep this.path()
is called.
If you need to use this.path()
inside a user profile, please use
with_init.file()
. i.e. instead of writing:
<expr 1> <expr 2> <...>
write this:
this.path::with_init.file({ <expr 1> <expr 2> <...> })
shFILE()
FILE1.R <- tempfile(fileext = ".R") writeLines("writeLines(sQuote(this.path::this.path()))", FILE1.R) ## 'this.path()' works with 'source()' source(FILE1.R) ## 'this.path()' works with 'sys.source()' sys.source(FILE1.R, envir = environment()) ## 'this.path()' works with 'debugSource()' in 'RStudio' if (.Platform$GUI == "RStudio") get("debugSource", "tools:rstudio", inherits = FALSE)(FILE1.R) ## 'this.path()' works with 'testthat::source_file()' if (requireNamespace("testthat")) testthat::source_file(FILE1.R, chdir = FALSE, wrap = FALSE) ## 'this.path()' works with 'compiler::loadcmp()' if (requireNamespace("compiler")) { FILE2.Rc <- tempfile(fileext = ".Rc") compiler::cmpfile(FILE1.R, FILE2.Rc) compiler::loadcmp(FILE2.Rc) unlink(FILE2.Rc) } ## 'this.path()' works with 'Rscript' this.path:::.Rscript(c("--default-packages=NULL", "--vanilla", FILE1.R)) ## 'this.path()' also works when 'source()'-ing a URL ## (included tryCatch in case an internet connection is not available) tryCatch({ source(paste0("https://raw.githubusercontent.com/ArcadeAntics/", "this.path/main/tests/sys-path-with-urls.R")) }, condition = this.path:::.cat_condition) unlink(FILE1.R)
FILE1.R <- tempfile(fileext = ".R") writeLines("writeLines(sQuote(this.path::this.path()))", FILE1.R) ## 'this.path()' works with 'source()' source(FILE1.R) ## 'this.path()' works with 'sys.source()' sys.source(FILE1.R, envir = environment()) ## 'this.path()' works with 'debugSource()' in 'RStudio' if (.Platform$GUI == "RStudio") get("debugSource", "tools:rstudio", inherits = FALSE)(FILE1.R) ## 'this.path()' works with 'testthat::source_file()' if (requireNamespace("testthat")) testthat::source_file(FILE1.R, chdir = FALSE, wrap = FALSE) ## 'this.path()' works with 'compiler::loadcmp()' if (requireNamespace("compiler")) { FILE2.Rc <- tempfile(fileext = ".Rc") compiler::cmpfile(FILE1.R, FILE2.Rc) compiler::loadcmp(FILE2.Rc) unlink(FILE2.Rc) } ## 'this.path()' works with 'Rscript' this.path:::.Rscript(c("--default-packages=NULL", "--vanilla", FILE1.R)) ## 'this.path()' also works when 'source()'-ing a URL ## (included tryCatch in case an internet connection is not available) tryCatch({ source(paste0("https://raw.githubusercontent.com/ArcadeAntics/", "this.path/main/tests/sys-path-with-urls.R")) }, condition = this.path:::.cat_condition) unlink(FILE1.R)
try.this.path()
attempts to return this.path()
,
returning this.path(original = TRUE)
if that fails, returning
NA_character_
if that fails as well.
try.this.path(contents = FALSE, local = FALSE, n = 0, envir = parent.frame(n + 1), matchThisEnv = getOption("topLevelEnvironment"), srcfile = if (n) sys.parent(n) else 0) try.shFILE()
try.this.path(contents = FALSE, local = FALSE, n = 0, envir = parent.frame(n + 1), matchThisEnv = getOption("topLevelEnvironment"), srcfile = if (n) sys.parent(n) else 0) try.shFILE()
contents , local , n , envir , matchThisEnv , srcfile
|
See
|
This should NOT be used to construct file paths against the script's directory. This should exclusively be used for diagnostic messages / / warnings / / errors / / logging. The returned path may not exist, may be relative instead of absolute, or may be undefined.
character string.
try.shFILE() try.this.path() try.this.path(contents = TRUE)
try.shFILE() try.this.path() try.this.path(contents = TRUE)