Type: | Package |
Title: | Supporting Functions for Packages Maintained by 'Yihui Xie' |
Version: | 0.51 |
Description: | Miscellaneous functions commonly used in other packages maintained by 'Yihui Xie'. |
Depends: | R (≥ 3.2.0) |
Imports: | grDevices, stats, tools |
Suggests: | testit, parallel, codetools, methods, rstudioapi, tinytex (≥ 0.30), mime, litedown (≥ 0.4), commonmark, knitr (≥ 1.47), remotes, pak, rhub, renv, curl, xml2, jsonlite, magick, yaml, qs, rmarkdown |
License: | MIT + file LICENSE |
URL: | https://github.com/yihui/xfun |
BugReports: | https://github.com/yihui/xfun/issues |
Encoding: | UTF-8 |
RoxygenNote: | 7.3.2 |
VignetteBuilder: | litedown |
NeedsCompilation: | yes |
Packaged: | 2025-02-19 15:23:21 UTC; runner |
Author: | Yihui Xie |
Maintainer: | Yihui Xie <xie@yihui.name> |
Repository: | CRAN |
Date/Publication: | 2025-02-19 16:00:02 UTC |
Generate ID strings
Description
Substitute certain (by default, non-alphanumeric) characters with dashes and remove extra dashes at both ends to generate ID strings. This function is intended for generating IDs for HTML elements, so HTML tags in the input text will be removed first.
Usage
alnum_id(x, exclude = "[^[:alnum:]]+")
Arguments
x |
A character vector. |
exclude |
A (Perl) regular expression to detect characters to be replaced by dashes. By default, non-alphanumeric characters are replaced. |
Value
A character vector of IDs.
Examples
x = c("Hello world 123!", "a &b*^##c 456")
xfun::alnum_id(x)
xfun::alnum_id(x, "[^[:alpha:]]+") # only keep alphabetical chars
# when text contains HTML tags
xfun::alnum_id("<h1>Hello <strong>world</strong>!")
Obtain an attribute of an object without partial matching
Description
An abbreviation of base::attr
(exact = TRUE)
.
Usage
attr(...)
Arguments
... |
Passed to |
Examples
z = structure(list(a = 1), foo = 2)
base::attr(z, "f") # 2
xfun::attr(z, "f") # NULL
xfun::attr(z, "foo") # 2
Get base R package names
Description
Return base R package names.
Usage
base_pkgs()
Value
A character vector of base R package names.
Examples
xfun::base_pkgs()
Encode/decode data into/from base64 encoding.
Description
The function base64_encode()
encodes a file or a raw vector into the
base64 encoding. The function base64_decode()
decodes data from the
base64 encoding.
Usage
base64_encode(x)
base64_decode(x, from = NA)
Arguments
x |
For |
from |
If provided (and |
Value
base64_encode()
returns a character string.
base64_decode()
returns a raw vector.
Examples
xfun::base64_encode(as.raw(1:10))
logo = xfun:::R_logo()
xfun::base64_encode(logo)
xfun::base64_decode("AQIDBAUGBwgJCg==")
Generate the Data URI for a file
Description
Encode the file in the base64 encoding, and add the media type. The data URI
can be used to embed data in HTML documents, e.g., in the src
attribute of
the <img />
tag.
Usage
base64_uri(x, type = mime_type(x))
Arguments
x |
A file path. |
type |
The MIME type of the file, e.g., |
Value
A string of the form data:<media type>;base64,<data>
.
Examples
logo = xfun:::R_logo()
img = xfun::html_tag("img", src = xfun::base64_uri(logo), alt = "R logo")
if (interactive()) xfun::html_view(img)
Start a background process
Description
Start a background process using the PowerShell cmdlet
Start-Process-PassThru
on Windows or the ampersand &
on
Unix, and return the process ID.
Usage
bg_process(
command,
args = character(),
verbose = getOption("xfun.bg_process.verbose", FALSE)
)
Arguments
command , args |
The system command and its arguments. They do not need to
be quoted, since they will be quoted via |
verbose |
If |
Value
The process ID as a character string.
Note
On Windows, if PowerShell is not available, try to use
system2
(wait = FALSE)
to start the background process instead. The
process ID will be identified from the output of the command
tasklist
. This method of looking for the process ID may not be
reliable. If the search is not successful in 30 seconds, it will throw an
error (timeout). If a longer time is needed, you may set
options(xfun.bg_process.timeout)
to a larger value, but it should be very
rare that a process cannot be started in 30 seconds. When you reach the
timeout, it is more likely that the command actually failed.
See Also
proc_kill()
to kill a process.
Find out broken packages and reinstall them
Description
If a package is broken (i.e., not loadable()
), reinstall it.
Usage
broken_packages(reinstall = TRUE)
Arguments
reinstall |
Whether to reinstall the broken packages, or only list their names. |
Details
Installed R packages could be broken for several reasons. One common reason
is that you have upgraded R to a newer x.y
version, e.g., from 4.0.5
to
4.1.0
, in which case you need to reinstall previously installed packages.
Value
A character vector of names of broken package.
Bump version numbers
Description
Increase the last digit of version numbers, e.g., from 0.1
to
0.2
, or 7.23.9
to 7.23.10
.
Usage
bump_version(x)
Arguments
x |
A vector of version numbers (of the class |
Value
A vector of new version numbers.
Examples
xfun::bump_version(c("0.1", "91.2.14"))
Cache the execution of an expression in memory or on disk
Description
Caching is based on the assumption that if the input does not change, the output will not change. After an expression is executed for the first time, its result will be saved (either in memory or on disk). The next run will be skipped and the previously saved result will be loaded directly if all external inputs of the expression remain the same, otherwise the cache will be invalidated and the expression will be re-executed.
Usage
cache_exec(expr, path = "cache/", id = NULL, ...)
Arguments
expr |
An R expression to be cached. |
path |
The path to save the cache. The special value |
id |
A stable and unique string identifier for the expression to be used
to identify a unique copy of cache for the current expression from all
cache files (or in-memory elements). If not provided, an MD5 digest of the
deparsed expression will be used, which means if the expression does not
change (changes in comments or white spaces do not matter), the |
... |
More arguments to control the behavior of caching (see ‘Details’). |
Details
Arguments supported in ...
include:
-
vars
: Names of local variables (which are created inside the expression). By default, local variables are automatically detected from the expression viafind_locals()
. Locally created variables are cached along with the value of the expression. -
hash
andextra
: R objects to be used to determine if cache should be loaded or invalidated. If (the MD5 hash of) the objects is not changed, the cache is loaded, otherwise the cache is invalidated and rebuilt. By default,hash
is a list of values of global variables in the expression (i.e., variables created outside the expression). Global variables are automatically detected byfind_globals()
. You can provide a vector of names to override the automatic detection if you want some specific global variables to affect caching, or the automatic detection is not reliable. You can also provide additional information via theextra
argument. For example, if the expression reads an external filefoo.csv
, and you want the cache to be invalidated after the file is modified, you may useextra = file.mtime("foo.csv")
. -
keep
: By default, only one copy of the cache corresponding to anid
underpath
is kept, and all other copies for thisid
is automatically purged. IfTRUE
, all copies of the cache are kept. IfFALSE
, all copies are removed, which means the cache is always invalidated, and can be useful to force re-executing the expression. -
rw
: A list of functions to read/write the cache files. The list is of the formlist(name = 'xxx', load = function(file) {}, save = function(x, file) {})
. By default,readRDS()
andsaveRDS()
are used. This argument can also take a character string to use some built-in read/write methods. Currently available methods includerds
(the default),raw
(usingserialize()
andunserialize()
), andqs
(usingqs::qread()
andqs::qsave()
). Therds
andraw
methods only use base R functions (therds
method generates smaller files because it uses compression, but is often slower than theraw
method, which does not use compression). Theqs
method requires the qs package, which can be much faster than base R methods and also supports compression.
Value
If the cache is found, the cached value of the expression will be loaded and returned (other local variables will also be lazy-loaded into the current environment as a side-effect). If cache does not exist, the expression is executed and its value is returned.
Examples
# the first run takes about 1 second
y1 = xfun::cache_exec({
x = rnorm(1e+05)
Sys.sleep(1)
x
}, path = ":memory:", id = "sim-norm")
# the second run takes almost no time
y2 = xfun::cache_exec({
# comments won't affect caching
x = rnorm(1e+05)
Sys.sleep(1)
x
}, path = ":memory:", id = "sim-norm")
# y1, y2, and x should be identical
stopifnot(identical(y1, y2), identical(y1, x))
Cache the value of an R expression to an RDS file
Description
Save the value of an expression to a cache file (of the RDS format). Next time the value is loaded from the file if it exists.
Usage
cache_rds(
expr = {
},
rerun = FALSE,
file = "cache.rds",
dir = "cache/",
hash = NULL,
clean = getOption("xfun.cache_rds.clean", TRUE),
...
)
Arguments
expr |
An R expression. |
rerun |
Whether to delete the RDS file, rerun the expression, and save the result again (i.e., invalidate the cache if it exists). |
file |
The base (see Details) cache filename under the directory
specified by the |
dir |
The path of the RDS file is partially determined by |
hash |
A |
clean |
Whether to clean up the old cache files automatically when
|
... |
Other arguments to be passed to |
Details
Note that the file
argument does not provide the full cache filename. The
actual name of the cache file is of the form ‘BASENAME_HASH.rds’, where
‘BASENAME’ is the base name provided via the ‘file’ argument (e.g.,
if file = 'foo.rds'
, BASENAME
would be ‘foo’), and ‘HASH’ is
the MD5 hash (also called the ‘checksum’) calculated from the R code
provided to the expr
argument and the value of the hash
argument, which
means when the code or the hash
argument changes, the ‘HASH’ string
may also change, and the old cache will be invalidated (if it exists). If you
want to find the cache file, look for ‘.rds’ files that contain 32
hexadecimal digits (consisting of 0-9 and a-z) at the end of the filename.
The possible ways to invalidate the cache are: 1) change the code in expr
argument; 2) delete the cache file manually or automatically through the
argument rerun = TRUE
; and 3) change the value of the hash
argument. The
first two ways should be obvious. For the third way, it makes it possible to
automatically invalidate the cache based on changes in certain R objects. For
example, when you run cache_rds({ x + y })
, you may want to invalidate the
cache to rerun { x + y }
when the value of x
or y
has been changed, and
you can tell cache_rds()
to do so by cache_rds({ x + y }, hash = list(x, y))
. The value of the argument hash
is expected to be a list, but it can
also take a special value, "auto"
, which means cache_rds(expr)
will try
to automatically figure out the global variables in expr
, return a list of
their values, and use this list as the actual value of hash
. This behavior
is most likely to be what you really want: if the code in expr
uses an
external global variable, you may want to invalidate the cache if the value
of the global variable has changed. Here a “global variable” means a
variable not created locally in expr
, e.g., for cache_rds({ x <- 1; x + y })
, x
is a local variable, and y
is (most likely to be) a global
variable, so changes in y
should invalidate the cache. However, you know
your own code the best. If you want to be completely sure when to invalidate
the cache, you can always provide a list of objects explicitly rather than
relying on hash = "auto"
.
By default (the argument clean = TRUE
), old cache files will be
automatically cleaned up. Sometimes you may want to use clean = FALSE
(set
the R global option options(xfun.cache_rds.clean = FALSE)
if you want
FALSE
to be the default). For example, you may not have decided which
version of code to use, and you can keep the cache of both versions with
clean = FALSE
, so when you switch between the two versions of code, it will
still be fast to run the code.
Value
If the cache file does not exist, run the expression and save the result to the file, otherwise read the cache file and return the value.
Note
Changes in the code in the expr
argument do not necessarily always
invalidate the cache, if the changed code is parse
d
to the same
expression as the previous version of the code. For example, if you have
run cache_rds({Sys.sleep(5);1+1})
before, running cache_rds({ Sys.sleep( 5 ) ; 1 + 1 })
will use the cache, because the two expressions are
essentially the same (they only differ in white spaces). Usually you can
add/delete white spaces or comments to your code in expr
without
invalidating the cache. See the package vignette vignette('xfun', package = 'xfun')
for more examples.
When this function is called in a code chunk of a knitr document, you may not want to provide the filename or directory of the cache file, because they have reasonable defaults.
Side-effects (such as plots or printed output) will not be cached. The
cache only stores the last value of the expression in expr
.
See Also
cache_exec()
, which is more flexible (e.g., it supports in-memory
caching and different read/write methods for cache files).
Examples
f = tempfile() # the cache file
compute = function(...) {
res = xfun::cache_rds({
Sys.sleep(1)
1:10
}, file = f, dir = "", ...)
res
}
compute() # takes one second
compute() # returns 1:10 immediately
compute() # fast again
compute(rerun = TRUE) # one second to rerun
compute()
unlink(paste0(f, "_*.rds"))
Submit check jobs to crandalf
Description
Check the reverse dependencies of a package using the crandalf service: https://github.com/yihui/crandalf. If the number of reverse dependencies is large, they will be split into batches and pushed to crandalf one by one.
Usage
crandalf_check(pkg, size = 400, jobs = Inf, which = "all")
crandalf_results(pkg, repo = NA, limit = 200, wait = 5 * 60)
Arguments
pkg |
The package name of which the reverse dependencies are to be checked. |
size |
The number of reverse dependencies to be checked in each job. |
jobs |
The number of jobs to run in GitHub Actions (by default, all jobs are submitted, but you can choose to submit the first few jobs). |
which |
The type of dependencies (see |
repo |
The crandalf repo on GitHub (of the form |
limit |
The maximum of records for |
wait |
Number of seconds to wait if not all jobs have been completed on
GitHub. By default, this function checks the status every 5 minutes until
all jobs are completed. Set |
Details
Due to the time limit of a single job on GitHub Actions (6 hours), you will
have to split the large number of reverse dependencies into batches and check
them sequentially on GitHub (at most 5 jobs in parallel). The function
crandalf_check()
does this automatically when necessary. It requires
the git
command to be available.
The function crandalf_results()
fetches check results from GitHub
after all checks are completed, merge the results, and show a full summary of
check results. It requires gh
(GitHub CLI:
https://cli.github.com/manual/) to be installed and you also need to
authenticate with your GitHub account beforehand.
Parse comma-separated chunk options
Description
For knitr and R Markdown documents, code chunk options can be written
using the comma-separated syntax (e.g., opt1=value1, opt2=value2
). This
function parses these options and returns a list. If an option is not named,
it will be treated as the chunk label.
Usage
csv_options(x)
Arguments
x |
The chunk options as a string. |
Value
A list of chunk options.
Examples
xfun::csv_options("foo, eval=TRUE, fig.width=5, echo=if (TRUE) FALSE")
Evaluate an expression after forcing the decimal point to be a dot
Description
Sometimes it is necessary to use the dot character as the decimal separator.
In R, this could be affected by two settings: the global option
options(OutDec)
and the LC_NUMERIC
locale. This function sets the former
to .
and the latter to C
before evaluating an expression, such as
coercing a number to character.
Usage
decimal_dot(x)
Arguments
x |
An expression. |
Value
The value of x
.
Examples
opts = options(OutDec = ",")
as.character(1.234) # using ',' as the decimal separator
print(1.234) # same
xfun::decimal_dot(as.character(1.234)) # using dot
xfun::decimal_dot(print(1.234)) # using dot
options(opts)
Delete an empty directory
Description
Use list.file()
to check if there are any files or subdirectories
under a directory. If not, delete this empty directory.
Usage
del_empty_dir(dir)
Arguments
dir |
Path to a directory. If |
Create a directory recursively by default
Description
First check if a directory exists. If it does, return TRUE
, otherwise
create it with dir.create
(recursive = TRUE)
by default.
Usage
dir_create(x, recursive = TRUE, ...)
Arguments
x |
A path name. |
recursive |
Whether to create all directory components in the path. |
... |
Other arguments to be passed to |
Value
A logical value indicating if the directory either exists or is successfully created.
Test the existence of files and directories
Description
These are wrapper functions of [utils::file_test()]
to test the
existence of directories and files. Note that file_exists()
only tests
files but not directories, which is the main difference between
file.exists()
in base R. If you use are using the R version
3.2.0 or above, dir_exists()
is the same as dir.exists()
in base R.
Usage
dir_exists(x)
file_exists(x)
Arguments
x |
A vector of paths. |
Value
A logical vector.
Divide chunk options from the code chunk body
Description
Chunk options can be written in special comments (e.g., after #|
for R code
chunks) inside a code chunk. This function partitions these options from the
chunk body.
Usage
divide_chunk(engine, code)
Arguments
engine |
The name of the language engine (to determine the appropriate comment character). |
code |
A character vector (lines of code). |
Value
A list with the following items:
-
options
: The parsed options (if there are any) as a list. -
src
: The part of the input that contains the options. -
code
: The part of the input that contains the code.
Note
Chunk options must be written on continuous lines (i.e., all lines
must start with the special comment prefix such as #|
) at the beginning
of the chunk body.
Examples
# parse yaml-like items
yaml_like = c("#| label: mine", "#| echo: true", "#| fig.width: 8", "#| foo: bar",
"1 + 1")
writeLines(yaml_like)
xfun::divide_chunk("r", yaml_like)
# parse CSV syntax
csv_like = c("#| mine, echo = TRUE, fig.width = 8, foo = 'bar'", "1 + 1")
writeLines(csv_like)
xfun::divide_chunk("r", csv_like)
Perform a task once in an R session
Description
Perform a task once in an R session, e.g., emit a message or warning. Then give users an optional hint on how not to perform this task at all.
Usage
do_once(
task,
option,
hint = c("You will not see this message again in this R session.",
"If you never want to see this message,",
sprintf("you may set options(%s = FALSE) in your .Rprofile.", option))
)
Arguments
task |
Any R code expression to be evaluated once to perform a task,
e.g., |
option |
An R option name. This name should be as unique as possible in
|
hint |
A character vector to provide a hint to users on how not to
perform the task or see the message again in the current R session. Set
|
Value
The value returned by the task
, invisibly.
Examples
do_once(message("Today's date is ", Sys.Date()), "xfun.date.reminder")
# if you run it again, it will not emit the message again
do_once(message("Today's date is ", Sys.Date()), "xfun.date.reminder")
do_once({
Sys.sleep(2)
1 + 1
}, "xfun.task.1plus1")
do_once({
Sys.sleep(2)
1 + 1
}, "xfun.task.1plus1")
Download a file from a URL and cache it on disk
Description
This object provides methods to download files and cache them on disk.
Usage
download_cache
Format
A list of methods:
-
$get(url, type, handler)
downloads a URL, caches it, and returns the file content according to the value oftype
(possible values:"text"
means the text content;"base64"
means the base64 encoded data;"raw"
means the raw binary content;"auto"
is the default and means the type is determined by the content type in the URL headers). Optionally ahandler
function can be applied to the content. -
$list()
gives the list of cache files. -
$summary()
gives a summary of existing cache files. -
$remove(url, type)
removes a single cache file. -
$purge()
deletes all cache files.
Examples
# the first time it may take a few seconds
x1 = xfun::download_cache$get("https://www.r-project.org/")
head(x1)
# now you can get the cached content
x2 = xfun::download_cache$get("https://www.r-project.org/")
identical(x1, x2) # TRUE
# a binary file
x3 = xfun::download_cache$get("https://yihui.org/images/logo.png", "raw")
length(x3)
# show a summary
xfun::download_cache$summary()
# remove a specific cache file
xfun::download_cache$remove("https://yihui.org/images/logo.png", "raw")
# remove all cache files
xfun::download_cache$purge()
Try various methods to download a file
Description
Try all possible methods in download.file()
(e.g., libcurl
, curl
,
wget
, and wininet
) and see if any method can succeed. The reason to
enumerate all methods is that sometimes the default method does not work,
e.g., https://stat.ethz.ch/pipermail/r-devel/2016-June/072852.html.
Usage
download_file(
url,
output = url_filename(url),
...,
.error = "No download method works (auto/wininet/wget/curl/lynx)"
)
Arguments
url |
The URL of the file. |
output |
Path to the output file. By default, it is determined by
|
... |
Other arguments to be passed to |
.error |
An error message to signal when the download fails. |
Value
The output
file path if the download succeeded, or an error if none
of the download methods worked.
Note
To allow downloading large files, the timeout
option in options()
will be temporarily set to one hour (3600 seconds) inside this function
when this option has the default value of 60 seconds. If you want a
different timeout
value, you may set it via options(timeout = N)
, where
N
is the number of seconds (not 60).
Embed a file, multiple files, or directory on an HTML page
Description
For a file, first encode it into base64 data (a character string). Then
generate a hyperlink of the form ‘<a href="base64 data"
download="filename">Download filename</a>’. The file can be downloaded when
the link is clicked in modern web browsers. For a directory, it will be
compressed as a zip archive first, and the zip file is passed to
embed_file()
. For multiple files, they are also compressed to a zip file
first.
Usage
embed_file(path, name = basename(path), text = paste("Download", name), ...)
embed_dir(path, name = paste0(normalize_path(path), ".zip"), ...)
embed_files(path, name = with_ext(basename(path[1]), ".zip"), ...)
Arguments
path |
Path to the file(s) or directory. |
name |
The default filename to use when downloading the file. Note that
for |
text |
The text for the hyperlink. |
... |
For |
Details
These functions can be called in R code chunks in R Markdown documents with HTML output formats. You may embed an arbitrary file or directory in the HTML output file, so that readers of the HTML page can download it from the browser. A common use case is to embed data files for readers to download.
Value
An HTML tag ‘<a>’ with the appropriate attributes.
Note
Windows users may need to install Rtools to obtain the zip
command to use embed_dir()
and embed_files()
.
Internet Explorer does not support downloading embedded files. Chrome has a 2MB limit on the file size.
Examples
logo = xfun:::R_logo()
link = xfun::embed_file(logo, text = "Download R logo")
link
if (interactive()) xfun::html_view(link)
Retrieve a global option from both options()
and environment variables
Description
If the option exists in options()
, use its value. If not, query the
environment variable with the name R_NAME
where NAME
is the capitalized
option name with dots substituted by underscores. For example, for an option
xfun.foo
, first we try getOption('xfun.foo')
; if it does not exist, we
check the environment variable R_XFUN_FOO
.
Usage
env_option(name, default = NULL)
Arguments
name |
The option name. |
default |
The default value if the option is not found in |
Details
This provides two possible ways, whichever is more convenient, for users to set an option. For example, global options can be set in the .Rprofile file, and environment variables can be set in the .Renviron file.
Value
The option value.
Examples
xfun::env_option("xfun.test.option") # NULL
Sys.setenv(R_XFUN_TEST_OPTION = "1234")
xfun::env_option("xfun.test.option") # 1234
options(xfun.test.option = TRUE)
xfun::env_option("xfun.test.option") # TRUE (from options())
options(xfun.test.option = NULL) # reset the option
xfun::env_option("xfun.test.option") # 1234 (from env var)
Sys.unsetenv("R_XFUN_TEST_OPTION")
xfun::env_option("xfun.test.option") # NULL again
xfun::env_option("xfun.test.option", FALSE) # use default
Find file paths that exist
Description
This is a shorthand of x[file.exists(x)]
, and optionally returns the
first existing file path.
Usage
existing_files(x, first = FALSE, error = TRUE)
Arguments
x |
A vector of file paths. |
first |
Whether to return the first existing path. If |
error |
Whether to throw an error when |
Value
A vector of existing file paths.
Examples
xfun::existing_files(c("foo.txt", system.file("DESCRIPTION", package = "xfun")))
Call on.exit()
in a parent function
Description
The function on.exit()
is often used to perform tasks when the
current function exits. This exit_call()
function allows calling a
function when a parent function exits (thinking of it as inserting an
on.exit()
call into the parent function).
Usage
exit_call(fun, n = 2, ...)
Arguments
fun |
A function to be called when the parent function exits. |
n |
The parent frame number. For |
... |
Other arguments to be passed to |
References
This function was inspired by Kevin Ushey: https://yihui.org/en/2017/12/on-exit-parent/
Examples
f = function(x) {
print(x)
xfun::exit_call(function() print("The parent function is exiting!"))
}
g = function(y) {
f(y)
print("f() has been called!")
}
g("An argument of g()!")
Create a fenced block in Markdown
Description
Wrap content with fence delimiters such as backticks (code blocks) or colons
(fenced Div). Optionally the fenced block can have attributes. The function
fenced_div()
is a shorthand of fenced_block(char = ':')
.
Usage
fenced_block(x, attrs = NULL, fence = make_fence(x, char), char = "`")
fenced_div(...)
make_fence(x, char = "`", start = 3)
Arguments
x |
A character vector of the block content. |
attrs |
A vector of block attributes. |
fence |
The fence string, e.g., |
char |
The fence character to be used to generate the fence string by default. |
... |
Arguments to be passed to |
start |
The number of characters to start searching |
Value
fenced_block()
returns a character vector that contains both the
fences and content.
make_fence()
returns a character string. If the block content
contains N
fence characters (e.g., backticks), use N + 1
characters as
the fence.
Examples
# code block with class 'r' and ID 'foo'
xfun::fenced_block("1+1", c(".r", "#foo"))
# fenced Div
xfun::fenced_block("This is a **Div**.", char = ":")
# three backticks by default
xfun::make_fence("1+1")
# needs five backticks for the fences because content has four
xfun::make_fence(c("````r", "1+1", "````"))
Manipulate filename extensions
Description
Functions to obtain (file_ext()
), remove (sans_ext()
), and
change (with_ext()
) extensions in filenames.
Usage
file_ext(x, extra = "")
sans_ext(x, extra = "")
with_ext(x, ext, extra = "")
Arguments
x |
A character of file paths. |
extra |
Extra characters to be allowed in the extensions. By default,
only alphanumeric characters are allowed (and also some special cases in
‘Details’). If other characters should be allowed, they can be
specified in a character string, e.g., |
ext |
A vector of new extensions. It must be either of length 1, or the
same length as |
Details
file_ext()
is similar to tools::file_ext()
, and
sans_ext()
is similar to tools::file_path_sans_ext()
.
The main differences are that they treat tar.(gz|bz2|xz)
and
nb.html
as extensions (but functions in the tools package
doesn't allow double extensions by default), and allow characters ~
and #
to be present at the end of a filename.
Value
A character vector of the same length as x
.
Examples
library(xfun)
p = c("abc.doc", "def123.tex", "path/to/foo.Rmd", "backup.ppt~", "pkg.tar.xz")
file_ext(p)
sans_ext(p)
with_ext(p, ".txt")
with_ext(p, c(".ppt", ".sty", ".Rnw", "doc", "zip"))
with_ext(p, "html")
# allow for more characters in extensions
p = c("a.c++", "b.c--", "c.e##")
file_ext(p) # -/+/# not recognized by default
file_ext(p, extra = "-+#")
Rename files and directories
Description
First try file.rename()
. If it fails (e.g., renaming a file from one volume
to another on disk is likely to fail), try file.copy()
instead, and clean
up the original files if the copy succeeds.
Usage
file_rename(from, to)
Arguments
from , to |
Original and target paths, respectively. |
Value
A logical vector (TRUE
for success and FALSE
for failure).
Read a text file and concatenate the lines by '\n'
Description
The source code of this function should be self-explanatory.
Usage
file_string(file)
Arguments
file |
Path to a text file (should be encoded in UTF-8). |
Value
A character string of text lines concatenated by '\n'
.
Examples
xfun::file_string(system.file("DESCRIPTION", package = "xfun"))
Find global/local variables in R code
Description
Use codetools::findGlobals()
and codetools::findLocalsList()
to find
global and local variables in a piece of code. Global variables are defined
outside the code, and local variables are created inside the code.
Usage
find_globals(code, envir = parent.frame())
find_locals(code)
Arguments
code |
Either a character vector of R source code, or an R expression. |
envir |
The global environment in which global variables are to be found. |
Value
A character vector of the variable names. If the source code contains syntax errors, an empty character vector will be returned.
Note
Due to the flexibility of creating and getting variables in R, these
functions are not guaranteed to find all possible variables in the code
(e.g., when the code is hidden behind eval()
).
Examples
x = 2
xfun::find_globals("y = x + 1")
xfun::find_globals("y = get('x') + 1") # x is not recognized
xfun::find_globals("y = zzz + 1") # zzz doesn't exist
xfun::find_locals("y = x + 1")
xfun::find_locals("assign('y', x + 1)") # it works
xfun::find_locals("assign('y', x + 1, new.env())") # still smart
xfun::find_locals("eval(parse(text = 'y = x + 1'))") # no way
Format numbers of bytes using a specified unit
Description
Call the S3 method format.object_size()
to format numbers of bytes.
Usage
format_bytes(x, units = "auto", ...)
Arguments
x |
A numeric vector (each element represents a number of bytes). |
units , ... |
Passed to |
Value
A character vector.
Examples
xfun::format_bytes(c(1, 1024, 2000, 1e+06, 2e+08))
xfun::format_bytes(c(1, 1024, 2000, 1e+06, 2e+08), units = "KB")
Get the relative path of a path in a project relative to the current working directory
Description
First compose an absolute path using the project root directory and the
relative path components, i.e., file.path
(root, ...)
. Then
convert it to a relative path with relative_path()
, which is
relative to the current working directory.
Usage
from_root(..., root = proj_root(), error = TRUE)
Arguments
... |
A character vector of path components relative to the root directory of the project. |
root |
The root directory of the project. |
error |
Whether to signal an error if the path cannot be converted to a relative path. |
Details
This function was inspired by here::here()
, and the major difference
is that it returns a relative path by default, which is more portable.
Value
A relative path, or an error when the project root directory cannot
be determined or the conversion failed and error = TRUE
.
Examples
## Not run:
xfun::from_root("data", "mtcars.csv")
## End(Not run)
Get the tags of GitHub releases of a repository
Description
Use the GitHub API (github_api()
) to obtain the tags of the
releases.
Usage
github_releases(
repo,
tag = "",
pattern = "v[0-9.]+",
use_jsonlite = loadable("jsonlite")
)
Arguments
repo |
The repository name of the form |
tag |
A tag as a character string. If provided, it will be returned if
the tag exists. If |
pattern |
A regular expression to match the tags. |
use_jsonlite |
Whether to use jsonlite to parse the releases info. |
Value
A character vector of (GIT) tags.
Examples
xfun::github_releases("yihui/xfun")
xfun::github_releases("gohugoio/hugo")
Perform replacement with gsub()
on elements matched from grep()
Description
This function is a shorthand of gsub(pattern, replacement, grep(pattern, x, value = TRUE))
.
Usage
grep_sub(pattern, replacement, x, ...)
Arguments
pattern , replacement , x , ... |
Passed to |
Value
A character vector.
Examples
# find elements that matches 'a[b]+c' and capitalize 'b' with perl regex
xfun::grep_sub("a([b]+)c", "a\\U\\1c", c("abc", "abbbc", "addc", "123"), perl = TRUE)
Search and replace strings in files
Description
These functions provide the "file" version of gsub()
, i.e.,
they perform searching and replacement in files via gsub()
.
Usage
gsub_file(file, ..., rw_error = TRUE)
gsub_files(files, ...)
gsub_dir(..., dir = ".", recursive = TRUE, ext = NULL, mimetype = ".*")
gsub_ext(ext, ..., dir = ".", recursive = TRUE)
Arguments
file |
Path of a single file. |
... |
For |
rw_error |
Whether to signal an error if the file cannot be read or
written. If |
files |
A vector of file paths. |
dir |
Path to a directory (all files under this directory will be replaced). |
recursive |
Whether to find files recursively under a directory. |
ext |
A vector of filename extensions (without the leading periods). |
mimetype |
A regular expression to filter files based on their MIME
types, e.g., |
Note
These functions perform in-place replacement, i.e., the files will be overwritten. Make sure you backup your files in advance, or use version control!
Examples
library(xfun)
f = tempfile()
writeLines(c("hello", "world"), f)
gsub_file(f, "world", "woRld", fixed = TRUE)
readLines(f)
Tools for HTML tags
Description
Given a tag name, generate an HTML tag with optional attributes and content.
html_tag()
can be viewed as a simplified version of htmltools::tags
,
html_value()
adds classes on the value so that it will be treated as raw
HTML (not escaped by html_tag()
), html_escape()
escapes special
characters in HTML, and html_view()
launches a browser or viewer to view
the HTML content.
Usage
html_tag(.name, .content = NULL, .attrs = NULL, ...)
html_value(x)
html_escape(x, attr = FALSE)
html_view(x, ...)
Arguments
.name |
The tag name. |
.content |
The content between opening and closing tags. Ignored for
void tags such as |
.attrs |
A named list of attributes. |
... |
For |
x |
A character vector to be treated as raw HTML content for
|
attr |
Whether to escape |
Value
A character string.
Examples
xfun::html_tag("a", "<R Project>", href = "https://www.r-project.org", target = "_blank")
xfun::html_tag("br")
xfun::html_tag("a", xfun::html_tag("strong", "R Project"), href = "#")
xfun::html_tag("a", list("<text>", xfun::html_tag("b", "R Project")), href = "#")
xfun::html_escape("\" quotes \" & brackets < >")
xfun::html_escape("\" & < > \r \n", attr = TRUE)
Evaluate an expression under a specified working directory
Description
Change the working directory, evaluate the expression, and restore the working directory.
Usage
in_dir(dir, expr)
Arguments
dir |
Path to a directory. |
expr |
An R expression. |
Examples
library(xfun)
in_dir(tempdir(), {
print(getwd())
list.files()
})
Install a source package from a directory
Description
Run R CMD build
to build a tarball from a source directory, and run
R CMD INSTALL
to install it.
Usage
install_dir(pkg = ".", build = TRUE, build_opts = NULL, install_opts = NULL)
Arguments
pkg |
The package source directory. |
build |
Whether to build a tarball from the source directory. If
|
build_opts |
The options for |
install_opts |
The options for |
Value
Invisible status from R CMD INSTALL
.
An alias of remotes::install_github()
Description
This alias is to make autocomplete faster via xfun::install_github
, because
most remotes::install_*
functions are never what I want. I only use
install_github
and it is inconvenient to autocomplete it, e.g.
install_git
always comes before install_github
, but I never use it. In
RStudio, I only need to type xfun::ig
to get xfun::install_github
.
Usage
install_github(...)
Arguments
... |
Arguments to be passed to |
Test if paths are relative or absolute
Description
On Unix, check if the paths start with ‘/’ or ‘~’ (if they do, they
are absolute paths). On Windows, check if a path remains the same (via
same_path()
) if it is prepended with ‘./’ (if it does, it is a
relative path).
Usage
is_abs_path(x)
is_rel_path(x)
Arguments
x |
A vector of paths. |
Value
A logical vector.
Examples
xfun::is_abs_path(c("C:/foo", "foo.txt", "/Users/john/", tempdir()))
xfun::is_rel_path(c("C:/foo", "foo.txt", "/Users/john/", tempdir()))
Check if a character vector consists of entirely ASCII characters
Description
Converts the encoding of a character vector to 'ascii'
, and check if
the result is NA
.
Usage
is_ascii(x)
Arguments
x |
A character vector. |
Value
A logical vector indicating whether each element of the character vector is ASCII.
Examples
library(xfun)
is_ascii(letters) # yes
is_ascii(intToUtf8(8212)) # no
Test if a character vector consists of blank strings
Description
Return a logical vector indicating if elements of a character vector are blank (white spaces or empty strings).
Usage
is_blank(x)
Arguments
x |
A character vector. |
Value
TRUE
for blank elements, or FALSE
otherwise.
Examples
xfun::is_blank("")
xfun::is_blank("abc")
xfun::is_blank(c("", " ", "\n\t"))
xfun::is_blank(c("", " ", "abc"))
Some utility functions for checking packages
Description
Miscellaneous utility functions to obtain information about the package checking environment.
Usage
is_R_CMD_check()
is_CRAN_incoming()
check_package_name()
check_old_package(name, version)
Test if a path is a subpath of a dir
Description
Check if the path starts with the dir path.
Usage
is_sub_path(x, dir, n = nchar(dir))
Arguments
x |
A vector of paths. |
dir |
A vector of directory paths. |
n |
The length of |
Value
A logical vector.
Note
You may want to normalize the values of the x
and dir
arguments
first (with normalize_path()
), to make sure the path separators
are consistent.
Examples
xfun::is_sub_path("a/b/c.txt", "a/b") # TRUE
xfun::is_sub_path("a/b/c.txt", "d/b") # FALSE
xfun::is_sub_path("a/b/c.txt", "a\\b") # FALSE (even on Windows)
Test if a path is a web path
Description
Check if a path starts with ‘http://’ or ‘https://’ or ‘ftp://’ or ‘ftps://’.
Usage
is_web_path(x)
Arguments
x |
A vector of paths. |
Value
A logical vector.
Examples
xfun::is_web_path("https://www.r-project.org") # TRUE
xfun::is_web_path("www.r-project.org") # FALSE
Test for types of operating systems
Description
Functions based on .Platform$OS.type
and Sys.info()
to test if
the current operating system is Windows, macOS, Unix, or Linux.
Usage
is_windows()
is_unix()
is_macos()
is_linux()
is_arm64()
Examples
library(xfun)
# only one of the following statements should be true
is_windows()
is_unix() && is_macos()
is_linux()
# In newer Macs, CPU can be either Intel or Apple
is_arm64() # TRUE on Apple silicone machines
Join multiple words into a single string
Description
If words
is of length 2, the first word and second word are joined by the
and
string; if and
is blank, sep
is used. When the length is greater
than 2, sep
is used to separate all words, and the and
string is
prepended to the last word.
Usage
join_words(
words,
sep = ", ",
and = " and ",
before = "",
after = before,
oxford_comma = TRUE
)
Arguments
words |
A character vector. |
sep |
Separator to be inserted between words. |
and |
Character string to be prepended to the last word. |
before , after |
A character string to be added before/after each word. |
oxford_comma |
Whether to insert the separator between the last two elements in the list. |
Value
A character string marked by raw_string()
.
Examples
join_words("a")
join_words(c("a", "b"))
join_words(c("a", "b", "c"))
join_words(c("a", "b", "c"), sep = " / ", and = "")
join_words(c("a", "b", "c"), and = "")
join_words(c("a", "b", "c"), before = "\"", after = "\"")
join_words(c("a", "b", "c"), before = "\"", after = "\"", oxford_comma = FALSE)
Save objects to files and lazy-load them
Description
The function lazy_save()
saves objects to files with incremental integer
names (e.g., the first object is saved to 1.rds
, and the second object is
saved to 2.rds
, etc.). The function lazy_load()
lazy-load objects from
files saved via lazy_save()
, i.e., a file will not be read until the object
is used.
Usage
lazy_save(list = NULL, path = "./", method = "auto", envir = parent.frame())
lazy_load(path = "./", method = "auto", envir = parent.frame())
Arguments
list |
A character vector of object names. This list will be written to
an index file with |
path |
The path to write files to / read files from. |
method |
The file save/load method. It can be a string (e.g., |
envir |
Value
lazy_save()
returns invisible NULL
; lazy_load()
returns the
object names invisibly.
See Also
Find a file or directory under a root directory
Description
Given a path, try to find it recursively under a root directory. The input
path can be an incomplete path, e.g., it can be a base filename, and
magic_path()
will try to find this file under subdirectories.
Usage
magic_path(
...,
root = proj_root(),
relative = TRUE,
error = TRUE,
message = getOption("xfun.magic_path.message", TRUE),
n_dirs = getOption("xfun.magic_path.n_dirs", 10000)
)
Arguments
... |
A character vector of path components. |
root |
The root directory under which to search for the path. If
|
relative |
Whether to return a relative path. |
error |
Whether to signal an error if the path is not found, or multiple paths are found. |
message |
Whether to emit a message when multiple paths are found and
|
n_dirs |
The number of subdirectories to recursively search. The
recursive search may be time-consuming when there are a large number of
subdirectories under the root directory. If you really want to search for
all subdirectories, you may try |
Value
The path found under the root directory, or an error when error = TRUE
and the path is not found (or multiple paths are found).
Examples
## Not run:
xfun::magic_path("mtcars.csv") # find any file that has the base name mtcars.csv
## End(Not run)
Mark some paths as directories
Description
Add a trailing backlash to a file path if this is a directory. This is useful in messages to the console for example to quickly identify directories from files.
Usage
mark_dirs(x)
Arguments
x |
Character vector of paths to files and directories. |
Details
If x
is a vector of relative paths, directory test is done with path
relative to the current working dir. Use in_dir()
or use absolute
paths.
Examples
mark_dirs(list.files(find.package("xfun"), full.names = TRUE))
Generate a simple Markdown pipe table
Description
A minimal Markdown table generator using the pipe |
as column separators.
Usage
md_table(x, digits = NULL, na = NULL, newline = NULL, limit = NULL)
Arguments
x |
A 2-dimensional object (e.g., a matrix or data frame). |
digits |
The number of decimal places to be passed to |
na |
A character string to represent |
newline |
A character string to substitute |
limit |
The maximum number of rows to show in the table. If it is smaller than the number of rows, the data in the middle will be omitted. If it is of length 2, the second number will be used to limit the number of columns. Zero and negative values are ignored. |
Details
The default argument values can be set via global options with the prefix
xfun.md_table.
, e.g., options(xfun.md_table.digits 2, xfun.md_table.na = 'n/a')
.
Value
A character vector.
See Also
knitr::kable()
(which supports more features)
Examples
xfun::md_table(head(iris))
xfun::md_table(mtcars, limit = c(10, 6))
Calculate the MD5 checksums of R objects
Description
Serialize an object and calculate the checksum via
tools::md5sum()
. If tools::md5sum()
does not have the argument bytes
,
the object will be first serialized to a temporary file, which will be
deleted after the checksum is calculated, otherwise the raw bytes of the
object will be passed to the bytes
argument directly (which will be
faster than writing to a temporary file).
Usage
md5(...)
Arguments
... |
Any number of R objects. |
Value
A character vector of the checksums of objects passed to md5()
. If
the arguments are named, the results will also be named.
Examples
x1 = 1
x2 = 1:10
x3 = seq(1, 10)
x4 = iris
x5 = paste
(m = xfun::md5(x1, x2, x3, x4, x5))
stopifnot(m[2] == m[3]) # x2 and x3 should be identical
xfun::md5(x1 = x1, x2 = x2) # named arguments
Get the MIME types of files
Description
If the mime package is installed, call mime::guess_type()
, otherwise
use the system command file --mime-type
to obtain the MIME type of a file.
Typically, the file
command exists on *nix. On Windows, the command should
exist if Cygwin or Rtools is installed. If it is not found, .NET's
MimeMapping
class will be used instead (which requires the .NET framework).
Usage
mime_type(x, use_mime = loadable("mime"), empty = "text/plain")
Arguments
x |
A vector of file paths. |
use_mime |
Whether to use the mime package. |
empty |
The MIME type for files without extensions (e.g., |
Value
A character vector of MIME types.
Note
When querying the MIME type via the system command, the result will be
cached to xfun:::cache_dir()
. This will make future queries much faster,
since running the command in real time can be a little slow.
Examples
f = list.files(R.home("doc"), full.names = TRUE)
mime_type(f)
mime_type(f, FALSE) # don't use mime
mime_type(f, FALSE, NA) # run command for files without extension
Generate a message with cat()
Description
This function is similar to message()
, and the difference is
that msg_cat()
uses cat()
to write out the message,
which is sent to stdout()
instead of stderr()
. The
message can be suppressed by suppressMessages()
.
Usage
msg_cat(...)
Arguments
... |
Character strings of messages, which will be concatenated into one
string via |
Value
Invisible NULL
, with the side-effect of printing the message.
Note
By default, a newline will not be appended to the message. If you need a newline, you have to explicitly add it to the message (see ‘Examples’).
See Also
This function was inspired by rlang::inform()
.
Examples
{
# a message without a newline at the end
xfun::msg_cat("Hello world!")
# add a newline at the end
xfun::msg_cat(" This message appears right after the previous one.\n")
}
suppressMessages(xfun::msg_cat("Hello world!"))
Try to use the system native encoding to represent a character vector
Description
Apply enc2native()
to the character vector, and check if enc2utf8()
can
convert it back without a loss. If it does, return enc2native(x)
, otherwise
return the original vector with a warning.
Usage
native_encode(x)
Arguments
x |
A character vector. |
Note
On platforms that supports UTF-8 as the native encoding
(l10n_info()
[['UTF-8']]
returns TRUE
), the conversion will be
skipped.
Examples
library(xfun)
s = intToUtf8(c(20320, 22909))
Encoding(s)
s2 = native_encode(s)
Encoding(s2)
Create a local web application
Description
An experimental function to create a local web application based on R's
internal httpd
server (which is primarily for running R's dynamic help
system).
Usage
new_app(name, handler, open = interactive(), ports = 4321 + 1:10)
Arguments
name |
The app name (a character string, and each app should have a unique name). |
handler |
A function that takes the HTTP request information (the first argument is the requested path) and returns a response. |
open |
Whether to open the app, or a function to open the app URL. |
ports |
A vector of ports to try for starting the server. |
Value
The app URL of the form http://127.0.0.1:port/custom/name/
.
Note
This function is not based on base R's public API, and is possible to break in the future, which is also why the documentation here is terse. Please avoid creating public-facing web apps with it. You may consider packages like httpuv and Rserve for production web apps.
Convert package news to the Markdown format
Description
Read the package news with news()
, convert the result to
Markdown, and write to an output file (e.g., ‘NEWS.md’). Each package
version appears in a first-level header, each category (e.g., ‘NEW
FEATURES’ or ‘BUG FIXES’) is in a second-level header, and the news
items are written into bullet lists.
Usage
news2md(package, ..., output = "NEWS.md", category = TRUE)
Arguments
package , ... |
Arguments to be passed to |
output |
The output file path. |
category |
Whether to keep the category names. |
Value
If output = NA
, returns the Markdown content as a character
vector, otherwise the content is written to the output file.
Examples
# news for the current version of R
xfun::news2md("R", Version == getRversion(), output = NA)
Normalize paths
Description
A wrapper function of normalizePath()
with different defaults.
Usage
normalize_path(x, winslash = "/", must_work = FALSE, resolve_symlink = TRUE)
Arguments
x , winslash , must_work |
Arguments passed to
|
resolve_symlink |
Whether to resolve symbolic links. |
Examples
library(xfun)
normalize_path("~")
Convert numbers to English words
Description
This can be helpful when writing reports with knitr/rmarkdown if
we want to print numbers as English words in the output. The function n2w()
is an alias of numbers_to_words()
.
Usage
numbers_to_words(x, cap = FALSE, hyphen = TRUE, and = FALSE)
n2w(x, cap = FALSE, hyphen = TRUE, and = FALSE)
Arguments
x |
A numeric vector. The absolute values should be less than |
cap |
Whether to capitalize the first letter of the word. This can be
useful when the word is at the beginning of a sentence. Default is |
hyphen |
Whether to insert hyphen (-) when the number is between 21 and 99 (except 30, 40, etc.). |
and |
Whether to insert |
Value
A character vector.
Author(s)
Daijiang Li
Examples
library(xfun)
n2w(0, cap = TRUE)
n2w(0:121, and = TRUE)
n2w(1e+06)
n2w(1e+11 + 12345678)
n2w(-987654321)
n2w(1e+15 - 1)
n2w(123.456)
n2w(123.45678901)
n2w(123.456789098765)
Run OptiPNG on all PNG files under a directory
Description
Call the command optipng
via system2()
to optimize all PNG
files under a directory.
Usage
optipng(dir = ".", files = all_files("[.]png$", dir), ...)
Arguments
dir |
Path to a directory. |
files |
Alternatively, you can choose the specific files to optimize. |
... |
Arguments to be passed to |
References
OptiPNG: https://optipng.sourceforge.net.
Parse R code and do not keep the source
Description
An abbreviation of parse(keep.source = FALSE)
.
Usage
parse_only(code)
Arguments
code |
A character vector of the R source code. |
Value
R expression()
s.
Examples
library(xfun)
parse_only("1+1")
parse_only(c("y~x", "1:5 # a comment"))
parse_only(character(0))
Attach or load packages, and automatically install missing packages if requested
Description
pkg_attach()
is a vectorized version of library()
over
the package
argument to attach multiple packages in a single function
call. pkg_load()
is a vectorized version of
requireNamespace()
to load packages (without attaching them).
The functions pkg_attach2()
and pkg_load2()
are wrappers of
pkg_attach(install = TRUE)
and pkg_load(install = TRUE)
,
respectively. loadable()
is an abbreviation of
requireNamespace(quietly = TRUE)
. pkg_available()
tests if a
package with a minimal version is available.
Usage
pkg_attach(
...,
install = FALSE,
message = getOption("xfun.pkg_attach.message", TRUE)
)
pkg_load(..., error = TRUE, install = FALSE)
loadable(pkg, strict = TRUE, new_session = FALSE)
pkg_available(pkg, version = NULL)
pkg_attach2(...)
pkg_load2(...)
Arguments
... |
Package names (character vectors, and must always be quoted). |
install |
Whether to automatically install packages that are not
available using |
message |
Whether to show the package startup messages (if any startup messages are provided in a package). |
error |
Whether to signal an error when certain packages cannot be loaded. |
pkg |
A single package name. |
strict |
If |
new_session |
Whether to test if a package is loadable in a new R
session. Note that |
version |
A minimal version number. If |
Details
These are convenience functions that aim to solve these common problems: (1)
We often need to attach or load multiple packages, and it is tedious to type
several library()
calls; (2) We are likely to want to install the
packages when attaching/loading them but they have not been installed.
Value
pkg_attach()
returns NULL
invisibly. pkg_load()
returns a logical vector, indicating whether the packages can be loaded.
See Also
pkg_attach2()
is similar to pacman::p_load()
, but does
not allow non-standard evaluation (NSE) of the ...
argument, i.e.,
you must pass a real character vector of package names to it, and all names
must be quoted. Allowing NSE adds too much complexity with too little gain
(the only gain is that it saves your effort in typing two quotes).
Examples
library(xfun)
pkg_attach("stats", "graphics")
# pkg_attach2('servr') # automatically install servr if it is not installed
(pkg_load("stats", "graphics"))
Generate BibTeX bibliography databases for R packages
Description
Call utils::citation()
and utils::toBibtex()
to create bib entries for R
packages and write them in a file. It can facilitate the auto-generation of
bibliography databases for R packages, and it is easy to regenerate all the
citations after updating R packages.
Usage
pkg_bib(
x = .packages(),
file = "",
tweak = TRUE,
width = NULL,
prefix = getOption("xfun.bib.prefix", "R-"),
lib.loc = NULL,
packageURL = TRUE
)
Arguments
x |
Package names. Packages which are not installed are ignored. |
file |
The (‘.bib’) file to write. By default, or if |
tweak |
Whether to fix some known problems in the citations, especially non-standard format of author names. |
width |
Width of lines in bibliography entries. If |
prefix |
Prefix string for keys in BibTeX entries; by default, it is
|
lib.loc |
A vector of path names of R libraries. |
packageURL |
Use the |
Details
For a package, the keyword R-pkgname
is used for its bib item, where
pkgname
is the name of the package. Citation entries specified in the
‘CITATION’ file of the package are also included. The main purpose of
this function is to automate the generation of the package citation
information because it often changes (e.g., the author, year, package
version, and so on).
There are at least two different uses for the URL in a reference list. You
might want to tell users where to go for more information. In that case, use
the default packageURL = TRUE
, and the first URL listed in the
‘DESCRIPTION’ file will be used. Be careful: some authors don't put the
most relevant URL first. Alternatively, you might want to identify exactly
which version of the package was used in the document. If it was installed
from CRAN or some other repositories, the version number identifies it, and
packageURL = FALSE
will use the repository URL (as used by
utils::citation()
).
Value
A list containing the citations. Citations are also written to the
file
as a side effect.
Note
Some packages on CRAN do not have standard bib entries, which was once
reported by Michael Friendly at
https://stat.ethz.ch/pipermail/r-devel/2010-November/058977.html. I
find this a pain, and there are no easy solutions except contacting package
authors to modify their DESCRIPTION files. The argument tweak
has
provided hacks to deal with known packages with non-standard bib entries;
tweak = TRUE
is by no means intended to hide or modify the original
citation information. It is just due to the loose requirements on package
authors for the DESCRIPTION file. On one hand, I apologize if it really
mangles the information about certain packages; on the other, I strongly
recommend package authors to consider the Authors@R
field (see the
manual Writing R Extensions) to make it easier for other people to cite R
packages.
Author(s)
Yihui Xie and Michael Friendly
Examples
pkg_bib(c("base", "MASS", "xfun"))
pkg_bib("cluster", prefix = "R-pkg-") # a different prefix
Kill a process and (optionally) all its child processes
Description
Run the command taskkill /f /pid
on Windows and kill
on
Unix, respectively, to kill a process.
Usage
proc_kill(pid, recursive = TRUE, ...)
Arguments
pid |
The process ID. |
recursive |
Whether to kill the child processes of the process. |
... |
Arguments to be passed to |
Value
The status code returned from system2()
.
Read a text file, process the text with a function, and write the text back
Description
Read a text file with the UTF-8 encoding, apply a function to the text, and write back to the original file if the processed text is different with the original input.
Usage
process_file(file, fun = identity, x = read_utf8(file))
sort_file(..., fun = sort)
Arguments
file |
Path to a text file. |
fun |
A function to process the text. |
x |
The content of the file. |
... |
Arguments to be passed to |
Details
sort_file()
is an application of process_file()
, with the processing
function being sort()
, i.e., it sorts the text lines in a file and write
back the sorted text.
Value
If file
is provided, invisible NULL
(the file is updated as a
side effect), otherwise the processed content (as a character vector).
Examples
f = tempfile()
xfun::write_utf8("Hello World", f)
xfun::process_file(f, function(x) gsub("World", "woRld", x))
xfun::read_utf8(f) # see if it has been updated
file.remove(f)
Return the (possible) root directory of a project
Description
Given a path of a file (or dir) in a potential project (e.g., an R package or an RStudio project), return the path to the project root directory.
Usage
proj_root(path = "./", rules = root_rules)
root_rules
Arguments
path |
The initial path to start the search. If it is a file path, its parent directory will be used. |
rules |
A matrix of character strings of two columns: the first column contains regular expressions to look for filenames that match the patterns, and the second column contains regular expressions to match the content of the matched files. The regular expression can be an empty string, meaning that it will match anything. |
Format
An object of class matrix
(inherits from array
) with 2 rows and 2 columns.
Details
The search for the root directory is performed by a series of tests,
currently including looking for a ‘DESCRIPTION’ file that contains
Package: *
(which usually indicates an R package), and a
‘*.Rproj’ file that contains Version: *
(which usually indicates
an RStudio project). If files with the expected patterns are not found in the
initial directory, the search will be performed recursively in upper-level
directories.
Value
Path to the root directory if found, otherwise NULL
.
Note
This function was inspired by the rprojroot package, but is much less sophisticated. It is a rather simple function designed to be used in some of packages that I maintain, and may not meet the need of general users until this note is removed in the future (which should be unlikely). If you are sure that you are working on the types of projects mentioned in the ‘Details’ section, this function may be helpful to you, otherwise please consider using rprojroot instead.
Find the indices of lines in Markdown that are prose (not code blocks)
Description
Filter out the indices of lines between code block fences such as ```
(could be three or four or more backticks).
Usage
prose_index(x, warn = TRUE)
Arguments
x |
A character vector of text in Markdown. |
warn |
Whether to emit a warning when code fences are not balanced. |
Value
An integer vector of indices of lines that are prose in Markdown.
Note
If the code fences are not balanced (e.g., a starting fence without an ending fence), this function will treat all lines as prose.
Examples
library(xfun)
prose_index(c("a", "```", "b", "```", "c"))
prose_index(c("a", "````", "```r", "1+1", "```", "````", "c"))
Protect math expressions in pairs of backticks in Markdown
Description
For Markdown renderers that do not support LaTeX math, we need to protect math expressions as verbatim code (in a pair of backticks), because some characters in the math expressions may be interpreted as Markdown syntax (e.g., a pair of underscores may make text italic). This function detects math expressions in Markdown (by heuristics), and wrap them in backticks.
Usage
protect_math(x, token = "", use_block = FALSE)
Arguments
x |
A character vector of text in Markdown. |
token |
A character string to wrap math expressions at both ends. This can be a unique token so that math expressions can be reliably identified and restored after the Markdown text is converted. |
use_block |
Whether to use code blocks ( |
Details
Expressions in pairs of dollar signs or double dollar signs are treated as
math, if there are no spaces after the starting dollar sign, or before the
ending dollar sign. There should be a space or (
before the starting dollar
sign, unless the math expression starts from the very beginning of a line.
For a pair of single dollar signs, the ending dollar sign should not be
followed by a number, and the inner math expression should not be wrapped in
backticks. With these assumptions, there should not be too many false
positives when detecing math expressions.
Besides, LaTeX environments (\begin{*}
and \end{*}
) are also
protected in backticks.
Value
A character vector with math expressions in backticks.
Note
If you are using Pandoc or the rmarkdown package, there is no need to use this function, because Pandoc's Markdown can recognize math expressions.
Examples
library(xfun)
protect_math(c("hi $a+b$", "hello $$\\alpha$$", "no math here: $x is $10 dollars"))
protect_math(c("hi $$", "\\begin{equation}", "x + y = z", "\\end{equation}"))
protect_math("$a+b$", "===")
Print a character vector in its raw form
Description
The function raw_string()
assigns the class xfun_raw_string
to
the character vector, and the corresponding printing function
print.xfun_raw_string()
uses cat(x, sep = '\n')
to write the
character vector to the console, which will suppress the leading indices
(such as [1]
) and double quotes, and it may be easier to read the
characters in the raw form (especially when there are escape sequences).
Usage
raw_string(x, ...)
## S3 method for class 'xfun_raw_string'
print(x, ...)
Arguments
x |
For |
... |
Other arguments (currently ignored). |
Examples
library(xfun)
raw_string(head(LETTERS))
raw_string(c("a \"b\"", "hello\tworld!"))
Read all text files and concatenate their content
Description
Read files one by one, and optionally add text before/after the content. Then combine all content into one character vector.
Usage
read_all(files, before = function(f, x) NULL, after = function(f, x) NULL)
Arguments
files |
A vector of file paths. |
before , after |
A function that takes one file path and its content as the input and returns values to be added before or after the content of the file. Alternatively, they can be constant values to be added. |
Value
A character vector.
Examples
# two files in this package
fs = system.file("scripts", c("call-fun.R", "child-pids.sh"), package = "xfun")
xfun::read_all(fs)
# add file paths before file content and an empty line after content
xfun::read_all(fs, before = function(f) paste("#-----", f, "-----"), after = "")
# add constants
xfun::read_all(fs, before = "/*", after = c("*/", ""))
Read all records of a binary file as a raw vector by default
Description
This is a wrapper function of readBin()
with default arguments
what = "raw"
and n =
file.size
(file)
, which means it
will read the full content of a binary file as a raw vector by default.
Usage
read_bin(file, what = "raw", n = file.info(file)$size, ...)
Arguments
file , what , n , ... |
Arguments to be passed to |
Value
A vector returned from readBin()
.
Examples
f = tempfile()
cat("abc", file = f)
xfun::read_bin(f)
unlink(f)
Read / write files encoded in UTF-8
Description
Read or write files, assuming they are encoded in UTF-8. read_utf8()
is
roughly readLines(encoding = 'UTF-8')
(a warning will be issued if non-UTF8
lines are found), and write_utf8()
calls writeLines(enc2utf8(text), useBytes = TRUE)
.
Usage
read_utf8(con, error = FALSE)
write_utf8(text, con, ...)
append_utf8(text, con, sort = TRUE)
append_unique(text, con, sort = function(x) base::sort(unique(x)))
Arguments
con |
A connection or a file path. |
error |
Whether to signal an error when non-UTF8 characters are detected
(if |
text |
A character vector (will be converted to UTF-8 via |
... |
Other arguments passed to |
sort |
Logical ( |
Details
The function append_utf8()
appends UTF-8 content to a file or connection
based on read_utf8()
and write_utf8()
, and optionally sort the content.
The function append_unique()
appends unique lines to a file or connection.
Value
read_utf8()
returns a character vector of the file content;
write_utf8()
returns the con
argument (invisibly).
Run R code and record the results
Description
Run R code and capture various types of output, including text output, plots, messages, warnings, and errors.
Usage
record(
code = NULL,
dev = "png",
dev.path = "xfun-record",
dev.ext = dev_ext(dev),
dev.args = list(),
message = TRUE,
warning = TRUE,
error = NA,
cache = list(),
print = record_print,
print.args = list(),
verbose = getOption("xfun.record.verbose", 0),
envir = parent.frame()
)
## S3 method for class 'xfun_record_results'
format(
x,
to = c("text", "markdown", "html"),
encode = FALSE,
template = FALSE,
...
)
## S3 method for class 'xfun_record_results'
print(
x,
browse = interactive(),
to = if (browse) "html" else "text",
template = TRUE,
...
)
Arguments
code |
A character vector of R source code. |
dev |
A graphics device. It can be a function name, a function, or a character string that can be evaluated to a function to open a graphics device. |
dev.path |
A base file path for plots. Actual plot filenames will be
this base path plus incremental suffixes. For example, if |
dev.ext |
The file extension for plot files. By default, it will be inferred from the first argument of the device function if possible. |
dev.args |
Extra arguments to be passed to the device. The default
arguments are |
message , warning , error |
If |
cache |
A list of options for caching. See the |
print |
A (typically S3) function that takes the value of an expression
in the code as input and returns output. The default is |
print.args |
A list of arguments for the |
verbose |
|
envir |
An environment in which the code is evaluated. |
x |
An object returned by |
to |
The output format (text, markdown, or html). |
encode |
For HTML output, whether to base64 encode plots. |
template |
For HTML output, whether to embed the formatted results in an
HTML template. Alternatively, this argument can take a file path, i.e.,
path to an HTML template that contains the variable |
... |
Currently ignored. |
browse |
Whether to browse the results on an HTML page. |
Value
record()
returns a list of the class xfun_record_results
that
contains elements with these possible classes: record_source
(source
code), record_output
(text output), record_plot
(plot file paths),
record_message
(messages), record_warning
(warnings), and
record_error
(errors, only when the argument error = TRUE
).
The format()
method returns a character vector of plain-text output
or HTML code for displaying the results.
The print()
method prints the results as plain text or HTML to the
console or displays the HTML page.
Examples
code = c("# a warning test", "1:2 + 1:3", "par(mar = c(4, 4, 1, .2))",
"barplot(5:1, col = 2:6, horiz = TRUE)", "head(iris)",
"sunflowerplot(iris[, 3:4], seg.col = 'purple')",
"if (TRUE) {\n message('Hello, xfun::record()!')\n}",
"# throw an error", "1 + 'a'")
res = xfun::record(code, dev.args = list(width = 9, height = 6.75),
error = TRUE)
xfun::tree(res)
format(res)
# find and clean up plot files
plots = Filter(function(x) inherits(x, "record_plot"),
res)
file.remove(unlist(plots))
Print methods for record()
Description
An S3 generic function to be called to print visible values in code when the
code is recorded by record()
. It is similar to knitr::knit_print()
. By
default, it captures the normal print()
output and returns the result as a
character vector. The knitr_kable
method is for printing knitr::kable()
output. Users and package authors can define other S3 methods to extend this
function.
Usage
record_print(x, ...)
## Default S3 method:
record_print(x, ...)
## S3 method for class 'record_asis'
record_print(x, ...)
new_record(x, class)
Arguments
x |
For |
... |
Other arguments to be passed to |
class |
A class name. Possible values are |
Value
A record_print()
method should return a character vector or a list
of character vectors. The original classes of the vector will be discarded,
and the vector will be treated as console output by default (i.e.,
new_record(class = "output")
). If it should be another type of output,
wrap the vector in new_record()
and specify a class name.
Get the relative path of a path relative to a directory
Description
Given a directory, return the relative path that is relative to this directory. For example, the path ‘foo/bar.txt’ relative to the directory ‘foo/’ is ‘bar.txt’, and the path ‘/a/b/c.txt’ relative to ‘/d/e/’ is ‘../../a/b/c.txt’.
Usage
relative_path(x, dir = ".", use.. = TRUE, error = TRUE)
Arguments
x |
A vector of paths to be converted to relative paths. |
dir |
Path to a directory. |
use.. |
Whether to use double-dots (‘..’) in the relative path. A
double-dot indicates the parent directory (starting from the directory
provided by the |
error |
Whether to signal an error if a path cannot be converted to a relative path. |
Value
A vector of relative paths if the conversion succeeded; otherwise the
original paths when error = FALSE
, and an error when error = TRUE
.
Examples
xfun::relative_path("foo/bar.txt", "foo/")
xfun::relative_path("foo/bar/a.txt", "foo/haha/")
xfun::relative_path(getwd())
Rename files with a sequential numeric prefix
Description
Rename a series of files and add an incremental numeric prefix to the filenames. For example, files ‘a.txt’, ‘b.txt’, and ‘c.txt’ can be renamed to ‘1-a.txt’, ‘2-b.txt’, and ‘3-c.txt’.
Usage
rename_seq(
pattern = "^[0-9]+-.+[.]Rmd$",
format = "auto",
replace = TRUE,
start = 1,
dry_run = TRUE
)
Arguments
pattern |
A regular expression for |
format |
The format for the numeric prefix. This is passed to
|
replace |
Whether to remove existing numeric prefixes in filenames. |
start |
The starting number for the prefix (it can start from 0). |
dry_run |
Whether to not really rename files. To be safe, the default is
|
Value
A named character vector. The names are original filenames, and the vector itself is the new filenames.
Examples
xfun::rename_seq()
xfun::rename_seq("[.](jpeg|png)$", format = "%04d")
Get data from a REST API
Description
Read data from a REST API and optionally with an authorization token in the
request header. The function rest_api_raw()
returns the raw text of
the response, and rest_api()
will parse the response with
jsonlite::fromJSON()
(assuming that the response is in the JSON
format).
Usage
rest_api(...)
rest_api_raw(root, endpoint, token = "", params = list(), headers = NULL)
github_api(
endpoint,
token = "",
params = list(),
headers = NULL,
raw = !loadable("jsonlite")
)
Arguments
... |
Arguments to be passed to |
root |
The API root URL. |
endpoint |
The API endpoint. |
token |
A named character string (e.g., |
params |
A list of query parameters to be sent with the API call. |
headers |
A named character vector of HTTP headers, e.g., |
raw |
Whether to return the raw response or parse the response with jsonlite. |
Details
These functions are simple wrappers based on url()
and
read_utf8()
. Specifically, the headers
argument is
passed to url()
, and read_utf8()
will send a ‘GET’ request
to the API server. This means these functions only support the ‘GET’
method. If you need to use other HTTP methods (such as ‘POST’), you have
to use other packages such as curl and httr.
github_api()
is a wrapper function based on
rest_api_raw()
to obtain data from the GitHub API:
https://docs.github.com/en/rest. You can provide a personal access
token (PAT) via the token
argument, or via one of the environment
variables GITHUB_PAT, GITHUB_TOKEN, GH_TOKEN. A PAT
allows for a much higher rate limit in API calls. Without a token, you can
only make 60 calls in an hour.
Value
A character vector (the raw JSON response) or an R object parsed from the JSON text.
Examples
# a normal GET request
xfun::rest_api("https://httpbin.org", "/get")
xfun::rest_api_raw("https://httpbin.org", "/get")
# send the request with an auth header
xfun::rest_api("https://httpbin.org", "/headers", "OPEN SESAME!")
# with query parameters
xfun::rest_api("https://httpbin.org", "/response-headers", params = list(foo = "bar"))
# get the rate limit info from GitHub
xfun::github_api("/rate_limit")
Retry calling a function for a number of times
Description
If the function returns an error, retry it for the specified number of times, with a pause between attempts.
Usage
retry(fun, ..., .times = 3, .pause = 5)
Arguments
fun |
A function. |
... |
Arguments to be passed to the function. |
.times |
The number of times. |
.pause |
The number of seconds to wait before the next attempt. |
Details
One application of this function is to download a web resource. Since the download might fail sometimes, you may want to retry it for a few more times.
Examples
# read the GitHub releases info of the repo yihui/xfun
xfun::retry(xfun::github_releases, "yihui/xfun")
Run R CMD check
on the reverse dependencies of a package
Description
Install the source package, figure out the reverse dependencies on CRAN,
download all of their source packages, and run R CMD check
on them
in parallel.
Usage
rev_check(
pkg,
which = "all",
recheck = NULL,
ignore = NULL,
update = TRUE,
timeout = getOption("xfun.rev_check.timeout", 15 * 60),
src = file.path(src_dir, pkg),
src_dir = getOption("xfun.rev_check.src_dir")
)
compare_Rcheck(status_only = TRUE, output = "00check_diffs.md")
Arguments
pkg |
The package name. |
which |
Which types of reverse dependencies to check. See
|
recheck |
A vector of package names to be (re)checked. If not provided
and there are any ‘*.Rcheck’ directories left by certain packages
(this often means these packages failed the last time), |
ignore |
A vector of package names to be ignored in |
update |
Whether to update all packages before the check. |
timeout |
Timeout in seconds for |
src |
The path of the source package directory. |
src_dir |
The parent directory of the source package directory. This can be set in a global option if all your source packages are under a common parent directory. |
status_only |
If |
output |
The output Markdown file to which the diffs in check logs will be written. If the markdown package is available, the Markdown file will be converted to HTML, so you can see the diffs more clearly. |
Details
Everything occurs under the current working directory, and you are recommended to call this function under a designated directory, especially when the number of reverse dependencies is large, because all source packages will be downloaded to this directory, and all ‘*.Rcheck’ directories will be generated under this directory, too.
If a source tarball of the expected version has been downloaded before (under the ‘tarball’ directory), it will not be downloaded again (to save time and bandwidth).
After a package has been checked, the associated ‘*.Rcheck’ directory will be deleted if the check was successful (no warnings or errors or notes), which means if you see a ‘*.Rcheck’ directory, it means the check failed, and you need to take a look at the log files under that directory.
The time to finish the check is recorded for each package. As the check goes
on, the total remaining time will be roughly estimated via n * mean(times)
, where n
is the number of packages remaining to be
checked, and times
is a vector of elapsed time of packages that have
been checked.
If a check on a reverse dependency failed, its ‘*.Rcheck’ directory will
be renamed to ‘*.Rcheck2’, and another check will be run against the
CRAN version of the package unless options(xfun.rev_check.compare = FALSE)
is set. If the logs of the two checks are the same, it means no new
problems were introduced in the package, and you can probably ignore this
particular reverse dependency. The function compare_Rcheck()
can be
used to create a summary of all the differences in the check logs under
‘*.Rcheck’ and ‘*.Rcheck2’. This will be done automatically if
options(xfun.rev_check.summary = TRUE)
has been set.
A recommended workflow is to use a special directory to run
rev_check()
, set the global options()
xfun.rev_check.src_dir
and repos
in the R startup (see
?
Startup
) profile file .Rprofile
under this directory,
and (optionally) set R_LIBS_USER
in ‘.Renviron’ to use a special
library path (so that your usual library will not be cluttered). Then run
xfun::rev_check(pkg)
once, investigate and fix the problems or (if you
believe it was not your fault) ignore broken packages in the file
‘00ignore’, and run xfun::rev_check(pkg)
again to recheck the
failed packages. Repeat this process until all ‘*.Rcheck’ directories
are gone.
As an example, I set options(repos = c(CRAN = 'https://cran.rstudio.com'), xfun.rev_check.src_dir = '~/Dropbox/repo')
in
‘.Rprofile’, and R_LIBS_USER=~/R-tmp
in ‘.Renviron’. Then I
can run, for example, xfun::rev_check('knitr')
repeatedly under a
special directory ‘~/Downloads/revcheck’. Reverse dependencies and their
dependencies will be installed to ‘~/R-tmp’, and knitr will be
installed from ‘~/Dropbox/repo/kintr’.
Value
A named numeric vector with the names being package names of reverse
dependencies; 0
indicates check success, 1
indicates failure,
and 2
indicates that a package was not checked due to global
timeout.
See Also
devtools::revdep_check()
is more sophisticated, but currently
has a few major issues that affect me: (1) It always deletes the
‘*.Rcheck’ directories
(https://github.com/r-lib/devtools/issues/1395), which makes it
difficult to know more information about the failures; (2) It does not
fully install the source package before checking its reverse dependencies
(https://github.com/r-lib/devtools/pull/1397); (3) I feel it is
fairly difficult to iterate the check (ignore the successful packages and
only check the failed packages); by comparison, xfun::rev_check()
only requires you to run a short command repeatedly (failed packages are
indicated by the existing ‘*.Rcheck’ directories, and automatically
checked again the next time).
xfun::rev_check()
borrowed a very nice feature from
devtools::revdep_check()
: estimating and displaying the remaining
time. This is particularly useful for packages with huge numbers of reverse
dependencies.
Run the commands Rscript
and R CMD
Description
Wrapper functions to run the commands Rscript
and R CMD
.
Usage
Rscript(args, ...)
Rcmd(args, ...)
Arguments
args |
A character vector of command-line arguments. |
... |
Other arguments to be passed to |
Value
A value returned by system2()
.
Examples
library(xfun)
Rscript(c("-e", "1+1"))
Rcmd(c("build", "--help"))
Call a function in a new R session via Rscript()
Description
Save the argument values of a function in a temporary RDS file, open a new R
session via Rscript()
, read the argument values, call the function, and
read the returned value back to the current R session.
Usage
Rscript_call(
fun,
args = list(),
options = NULL,
...,
wait = TRUE,
fail = sprintf("Failed to run '%s' in a new R session", deparse(substitute(fun))[1])
)
Arguments
fun |
A function, or a character string that can be parsed and evaluated to a function. |
args |
A list of argument values. |
options |
A character vector of options to passed to |
... , wait |
Arguments to be passed to |
fail |
The desired error message when an error occurred in calling the function. If the actual error message during running the function is available, it will be appended to this message. |
Value
If wait = TRUE
, the returned value of the function in the new R
session. If wait = FALSE
, three file paths will be returned: the first
one stores fun
and args
(as a list), the second one is supposed to
store the returned value of the function, and the third one stores the
possible error message.
Examples
factorial(10)
# should return the same value
xfun::Rscript_call("factorial", list(10))
# the first argument can be either a character string or a function
xfun::Rscript_call(factorial, list(10))
# Run Rscript starting a vanilla R session
xfun::Rscript_call(factorial, list(10), options = c("--vanilla"))
Type a character vector into the RStudio source editor
Description
Use the rstudioapi package to insert characters one by one into the RStudio source editor, as if they were typed by a human.
Usage
rstudio_type(x, pause = function() 0.1, mistake = 0, save = 0)
Arguments
x |
A character vector. |
pause |
A function to return a number in seconds to pause after typing each character. |
mistake |
The probability of making random mistakes when typing the next character. A random mistake is a random string typed into the editor and deleted immediately. |
save |
The probability of saving the document after typing each character. Note that If a document is not opened from a file, it will never be saved. |
Examples
library(xfun)
if (loadable("rstudioapi") && rstudioapi::isAvailable()) {
rstudio_type("Hello, RStudio! xfun::rstudio_type() looks pretty cool!",
pause = function() runif(1, 0, 0.5), mistake = 0.1)
}
Test if two paths are the same after they are normalized
Description
Compare two paths after normalizing them with the same separator (/
).
Usage
same_path(p1, p2, ...)
Arguments
p1 , p2 |
Two vectors of paths. |
... |
Arguments to be passed to |
Examples
library(xfun)
same_path("~/foo", file.path(Sys.getenv("HOME"), "foo"))
An alternative to sessionInfo() to print session information
Description
This function tweaks the output of sessionInfo()
: (1) It adds
the RStudio version information if running in the RStudio IDE; (2) It removes
the information about matrix products, BLAS, and LAPACK; (3) It removes the
names of base R packages; (4) It prints out package versions in a single
group, and does not differentiate between loaded and attached packages.
Usage
session_info(packages = NULL, dependencies = TRUE)
Arguments
packages |
A character vector of package names, of which the versions will be printed. If not specified, it means all loaded and attached packages in the current R session. |
dependencies |
Whether to print out the versions of the recursive dependencies of packages. |
Details
It also allows you to only print out the versions of specified packages (via
the packages
argument) and optionally their recursive dependencies.
For these specified packages (if provided), if a function
xfun_session_info()
exists in a package, it will be called and
expected to return a character vector to be appended to the output of
session_info()
. This provides a mechanism for other packages to inject
more information into the session_info
output. For example,
rmarkdown (>= 1.20.2) has a function xfun_session_info()
that
returns the version of Pandoc, which can be very useful information for
diagnostics.
Value
A character vector of the session information marked as
raw_string()
.
Examples
xfun::session_info()
if (xfun::loadable("MASS")) xfun::session_info("MASS")
Set environment variables
Description
Set environment variables from a named character vector, and return the old values of the variables, so they could be restored later.
Usage
set_envvar(vars)
Arguments
vars |
A named character vector of the form |
Details
The motivation of this function is that Sys.setenv()
does not
return the old values of the environment variables, so it is not
straightforward to restore the variables later.
Value
Old values of the variables (if not set, NA
).
Examples
vars = xfun::set_envvar(c(FOO = "1234"))
Sys.getenv("FOO")
xfun::set_envvar(vars)
Sys.getenv("FOO")
Shrink images to a maximum width
Description
Use magick::image_resize()
to shrink an
image if its width is larger than the value specified by the argument
width
, and optionally call tinify()
to compress it.
Usage
shrink_images(
width = 800,
dir = ".",
files = all_files("[.](png|jpe?g|webp)$", dir),
tinify = FALSE
)
Arguments
width |
The desired maximum width of images. |
dir |
The directory of images. |
files |
A vector of image file paths. By default, this is all
‘.png’, ‘.jpeg’, and ‘.webp’ images under |
tinify |
Whether to compress images using |
Examples
f = xfun:::all_files("[.](png|jpe?g)$", R.home("doc"))
file.copy(f, tempdir())
f = file.path(tempdir(), basename(f))
magick::image_info(magick::image_read(f)) # some widths are larger than 300
xfun::shrink_images(300, files = f)
magick::image_info(magick::image_read(f)) # all widths <= 300 now
file.remove(f)
Split a character vector by line breaks
Description
Call unlist(strsplit(x, '\n'))
on the character vector x
and
make sure it works in a few edge cases: split_lines('')
returns
''
instead of character(0)
(which is the returned value of
strsplit('', '\n')
); split_lines('a\n')
returns c('a', '')
instead of c('a')
(which is the returned value of
strsplit('a\n', '\n')
.
Usage
split_lines(x)
Arguments
x |
A character vector. |
Value
All elements of the character vector are split by '\n'
into
lines.
Examples
xfun::split_lines(c("a", "b\nc"))
Split source lines into complete expressions
Description
Parse the lines of code one by one to find complete expressions in the code, and put them in a list.
Usage
split_source(x, merge_comments = FALSE, line_number = FALSE)
Arguments
x |
A character vector of R source code. |
merge_comments |
Whether to merge consecutive lines of comments as a single expression to be combined with the next non-comment expression (if any). |
line_number |
Whether to store the line numbers of each expression in the returned value. |
Value
A list of character vectors, and each vector contains a complete R
expression, with an attribute lines
indicating the starting and ending
line numbers of the expression if the argument line_number = TRUE
.
Examples
code = c("# comment 1", "# comment 2", "if (TRUE) {", "1 + 1", "}", "print(1:5)")
xfun::split_source(code)
xfun::split_source(code, merge_comments = TRUE)
Wrap character vectors
Description
A wrapper function to make strwrap()
return a character vector of the same
length as the input vector; each element of the output vector is a string
formed by concatenating wrapped strings by \n
.
Usage
str_wrap(...)
Arguments
... |
Arguments passed to |
Value
A character vector.
Examples
x = sample(c(letters, " "), 200, TRUE, c(rep(0.5/26, 26), 0.5))
x = rep(paste(x, collapse = ""), 2)
strwrap(x, width = 30)
xfun::str_wrap(x, width = 30) # same length as x
Strict lists
Description
A strict list is essentially a normal list()
but it does not
allow partial matching with $
.
Usage
strict_list(...)
as_strict_list(x)
## S3 method for class 'xfun_strict_list'
x$name
## S3 method for class 'xfun_strict_list'
print(x, ...)
Arguments
... |
Objects (list elements), possibly named. Ignored in the
|
x |
For For |
name |
The name (a character string) of the list element. |
Details
To me, partial matching is often more annoying and surprising than
convenient. It can lead to bugs that are very hard to discover, and I have
been bitten by it many times. When I write x$name
, I always mean
precisely name
. You should use a modern code editor to autocomplete
the name
if it is too long to type, instead of using partial names.
Value
Both strict_list()
and as_strict_list()
return a list
with the class xfun_strict_list
. Whereas as_strict_list()
attempts to coerce its argument x
to a list if necessary,
strict_list()
just wraps its argument ...
in a list, i.e., it
will add another list level regardless if ...
already is of type
list.
Examples
library(xfun)
(z = strict_list(aaa = "I am aaa", b = 1:5))
z$a # NULL!
z$aaa # I am aaa
z$b
z$c = "create a new element"
z2 = unclass(z) # a normal list
z2$a # partial matching
z3 = as_strict_list(z2) # a strict list again
z3$a # NULL again!
Strip HTML tags
Description
Remove HTML tags and comments from text.
Usage
strip_html(x)
Arguments
x |
A character vector. |
Value
A character vector with HTML tags and comments stripped off.
Examples
xfun::strip_html("<a href=\"#\">Hello <!-- comment -->world!</a>")
Submit a source package to CRAN
Description
Build a source package and submit it to CRAN with the curl package.
Usage
submit_cran(file = pkg_build(), comment = "")
Arguments
file |
The path to the source package tarball. By default, the current
working directory is treated as the package root directory, and
automatically built into a tarball, which is deleted after submission. This
means you should run |
comment |
Submission comments for CRAN. By default, if a file ‘cran-comments.md’ exists, its content will be read and used as the comment. |
See Also
devtools::submit_cran()
does the same job, with a few more
dependencies in addition to curl (such as cli);
xfun::submit_cran()
only depends on curl.
Run system2()
and mark its character output as UTF-8 if appropriate
Description
This is a wrapper function based on system2()
. If system2()
returns character output (e.g., with the argument stdout = TRUE
),
check if the output is encoded in UTF-8. If it is, mark it with UTF-8
explicitly.
Usage
system3(...)
Arguments
... |
Passed to |
Value
The value returned by system2()
.
Examples
a = shQuote(c("-e", "print(intToUtf8(c(20320, 22909)))"))
x2 = system2("Rscript", a, stdout = TRUE)
Encoding(x2) # unknown
x3 = xfun::system3("Rscript", a, stdout = TRUE)
# encoding of x3 should be UTF-8 if the current locale is UTF-8
!l10n_info()[["UTF-8"]] || Encoding(x3) == "UTF-8" # should be TRUE
Represent a (recursive) list with (nested) tabsets
Description
The tab titles are names of list members, and the tab content contains the values of list members. If a list member is also a list, it will be represented recursively with a child tabset.
Usage
tabset(x, value = str)
Arguments
x |
A list. |
value |
A function to print the value of a list member. By default,
|
Value
A character vector of Markdown that can be rendered to HTML with
litedown::mark()
.
Examples
xfun::tabset(iris)
xfun::tabset(iris, dput)
xfun::tabset(iris, print)
# a deeply nested list
plot(1:10)
p = recordPlot()
xfun::tabset(p)
A simple YAML reader and writer
Description
TAML is a tiny subset of YAML. See https://yihui.org/litedown/#sec:yaml-syntax for its specifications.
Usage
taml_load(x, envir = parent.frame())
taml_file(path)
taml_save(x, path = NULL, indent = " ")
Arguments
x |
For |
envir |
The environment in which R expressions in YAML are evaluated. To
disable the evaluation, use |
path |
A file path to read from or write to. |
indent |
A character string to indent sub-lists by one level. |
Value
taml_load()
and taml_file()
return a list; if path = NULL
,
taml_save()
returns a character vector, otherwise the vector is written
to the file specified by the path
.
Examples
(res = taml_load("a: 1"))
taml_save(res)
(res = taml_load("a: 1\nb: \"foo\"\nc: null"))
taml_save(res)
(res = taml_load("a:\n b: false\n c: true\n d: 1.234\ne: bar"))
taml_save(res)
taml_save(res, indent = "\t")
taml_load("a: !expr paste(1:10, collapse = \", \")")
taml_load("a: [1, 3, 4, 2]")
taml_load("a: [1, \"abc\", 4, 2]")
taml_load("a: [\"foo\", \"bar\"]")
taml_load("a: [true, false, true]")
# the other form of array is not supported
taml_load("a:\n - b\n - c")
# and you must use the yaml package
if (loadable("yaml")) yaml_load("a:\n - b\n - c")
Use the Tinify API to compress PNG and JPEG images
Description
Compress PNG/JPEG images with ‘api.tinify.com’, and download the
compressed images. These functions require R packages curl and
jsonlite. tinify_dir()
is a wrapper function of tinify()
to
compress images under a directory.
Usage
tinify(
input,
output,
quiet = FALSE,
force = FALSE,
key = env_option("xfun.tinify.key"),
history = env_option("xfun.tinify.history")
)
tinify_dir(dir = ".", ...)
Arguments
input |
A vector of input paths of images. |
output |
A vector of output paths or a function that takes |
quiet |
Whether to suppress detailed information about the compression,
which is of the form ‘input.png (10 Kb) ==> output.png (5 Kb, 50%);
compression count: 42’. The percentage after |
force |
Whether to compress an image again when it appears to have been
compressed before. This argument only makes sense when the |
key |
The Tinify API key. It can be set via either the global option
|
history |
Path to a history file to record the MD5 checksum of
compressed images. If the checksum of an expected output image exists in
this file and |
dir |
A directory under which all ‘.png’, ‘.jpeg’, and ‘.webp’ files are to be compressed. |
... |
Arguments passed to |
Details
You are recommended to set the API key in ‘.Rprofile’ or
‘.Renviron’. After that, the only required argument of this function is
input
. If the original images can be overwritten by the compressed images,
you may either use output = identity
, or set the value of the history
argument in ‘.Rprofile’ or ‘.Renviron’.
Value
The output file paths.
References
Tinify API: https://tinypng.com/developers.
See Also
The tinieR package (https://github.com/jmablog/tinieR/) is a
more comprehensive implementation of the Tinify API, whereas
xfun::tinify()
has only implemented the feature of shrinking images.
Examples
## Not run:
f = xfun:::R_logo("jpg$")
xfun::tinify(f) # remember to set the API key before trying this
## End(Not run)
A simple JSON serializer
Description
A JSON serializer that only works on a limited types of R data (NULL
,
lists, arrays, logical/character/numeric/date/time vectors). Other types of
data will be coerced to character. A character string of the class
JS_LITERAL
is treated as raw JavaScript, so will not be quoted. The
function json_vector()
converts an atomic R vector to JSON.
Usage
tojson(x)
json_vector(x, to_array = FALSE, quote = TRUE)
Arguments
x |
An R object. |
to_array |
Whether to convert a vector to a JSON array (use |
quote |
Whether to double quote the elements. |
Details
Both NULL
and NA
are converted to null
. Named lists are converted to
objects of the form {key1: value1, key2: value2, ...}
. Unnamed lists are
converted to arrays of the form [[value1], [value2], ...]
. The same rules
apply to data frames since technically they are also lists. However, please
note that unnamed data frames (i.e., without column names) will be converted
to an array with each row as an array element, whereas named data frames
will have each column as an individual element. For matrices, the JSON
array will have each row as an individual element, and names are discarded.
Dates and times are coerced to character using UTC as the timezone, and
represented via the JavaScript expression new Date(value)
(which is not
standard JSON but practically more useful).
Value
A character string.
See Also
The jsonlite package provides a full JSON serializer.
Examples
library(xfun)
tojson(NULL)
tojson(1:10)
tojson(TRUE)
tojson(FALSE)
tojson(list(a = 1, b = list(c = 1:3, d = "abc")))
tojson(list(c("a", "b"), 1:5, TRUE, Sys.Date() + 1:3))
tojson(head(iris)) # each column is in an element
tojson(unname(head(iris))) # each row is in an element
tojson(matrix(1:12, 3))
# literal JS code
JS = function(x) structure(x, class = "JS_LITERAL")
tojson(list(a = 1:5, b = JS("function() {return true;}")))
Turn the output of str()
into a tree diagram
Description
The super useful function str()
uses ..
to indicate the level
of sub-elements of an object, which may be difficult to read. This function
uses vertical pipes to connect all sub-elements on the same level, so it is
clearer which elements belong to the same parent element in an object with a
nested structure (such as a nested list).
Usage
tree(...)
Arguments
... |
Arguments to be passed to |
Value
A character string as a raw_string()
.
Examples
fit = lsfit(1:9, 1:9)
str(fit)
xfun::tree(fit)
fit = lm(dist ~ speed, data = cars)
str(fit)
xfun::tree(fit)
# some trivial examples
xfun::tree(1:10)
xfun::tree(iris)
Try an expression and see if it throws an error
Description
Use tryCatch()
to check if an expression throws an error.
Usage
try_error(expr)
Arguments
expr |
An R expression. |
Value
TRUE
(error) or FALSE
(success).
Examples
xfun::try_error(stop("foo")) # TRUE
xfun::try_error(1:10) # FALSE
Try to evaluate an expression silently
Description
An abbreviation of try(silent = TRUE)
.
Usage
try_silent(expr)
Arguments
expr |
An R expression. |
Examples
library(xfun)
z = try_silent(stop("Wrong!"))
inherits(z, "try-error")
Upload to an FTP server via curl
Description
The function upload_ftp()
runs the command curl -T file
server
to upload a file to an FTP server if the system command
curl
is available, otherwise it uses the R package curl. The
function upload_win_builder()
uses upload_ftp()
to upload
packages to the win-builder server.
Usage
upload_ftp(file, server, dir = "")
upload_win_builder(
file = pkg_build(),
version = c("R-devel", "R-release", "R-oldrelease"),
server = c("ftp", "https"),
solaris = pkg_available("rhub")
)
Arguments
file |
Path to a local file. |
server |
The address of the FTP server. For |
dir |
The remote directory to which the file should be uploaded. |
version |
The R version(s) on win-builder. |
solaris |
Whether to also upload the package to the Rhub server to check it on Solaris. |
Details
These functions were written mainly to save package developers the trouble of going to the win-builder web page and uploading packages there manually.
Value
Status code returned from system2()
or
curl::curl_fetch_memory()
.
Upload an image to imgur.com
Description
This function uses the curl package or the system command curl
(whichever is available) to upload a image to https://imgur.com.
Usage
upload_imgur(
file,
key = env_option("xfun.upload_imgur.key"),
use_curl = loadable("curl"),
include_xml = FALSE
)
Arguments
file |
Path to the image file to be uploaded. |
key |
Client ID for Imgur. It can be set via either the global option
|
use_curl |
Whether to use the R package curl to upload the image.
If |
include_xml |
Whether to include the XML response in the returned value. |
Details
One application is to upload local image files to Imgur when knitting a
document with knitr: you can set the knitr::opts_knit$set(upload.fun = xfun::upload_imgur
, so the output document does not need local image files
any more, and it is ready to be published online.
Value
A character string of the link to the image. If include_xml = TRUE
,
this string carries an attribute named XML
, which is the XML response
from Imgur (it will be parsed by xml2 if available). See Imgur API in
the references.
Note
Please register your own Imgur application to get your client ID. You can certainly use mine, but this ID is in the public domain and it might reach Imgur's rate limit if too many people are using it in the same time period or someone is trying to upload too many images at once.
Author(s)
Yihui Xie, adapted from the imguR package by Aaron Statham
References
A demo: https://yihui.org/knitr/demo/upload/
Examples
## Not run:
f = tempfile(fileext = ".png")
png(f)
plot(rnorm(100), main = R.version.string)
dev.off()
res = imgur_upload(f, include_xml = TRUE)
res # link to original URL of the image
attr(res, "XML") # all information
if (interactive())
browseURL(res)
# to use your own key
options(xfun.upload_imgur.key = "your imgur key")
## End(Not run)
Test if a URL is accessible
Description
Try to send a HEAD
request to a URL using
curlGetHeaders()
or the curl package, and see if it
returns a successful status code.
Usage
url_accessible(x, use_curl = !capabilities("libcurl"), ...)
Arguments
x |
A URL as a character string. |
use_curl |
Whether to use the curl package or the
|
... |
Arguments to be passed to |
Value
TRUE
or FALSE
.
Examples
xfun::url_accessible("https://yihui.org")
Extract filenames from a URLs
Description
Get the base names of URLs via basename()
, and remove the
possible query parameters or hash from the names.
Usage
url_filename(x, default = "index.html")
Arguments
x |
A character vector of URLs. |
default |
The default filename when it cannot be determined from the URL, e.g., when the URL ends with a slash. |
Value
A character vector of filenames at the end of URLs.
Examples
xfun::url_filename("https://yihui.org/images/logo.png")
xfun::url_filename("https://yihui.org/index.html")
xfun::url_filename("https://yihui.org/index.html?foo=bar")
xfun::url_filename("https://yihui.org/index.html#about")
xfun::url_filename("https://yihui.org")
xfun::url_filename("https://yihui.org/")
Check if the syntax of the code is valid
Description
Try to parse()
the code and see if an error occurs.
Usage
valid_syntax(code, silent = TRUE)
Arguments
code |
A character vector of R source code. |
silent |
Whether to suppress the error message when the code is not valid. |
Value
TRUE
if the code could be parsed, otherwise FALSE
.
Examples
xfun::valid_syntax("1+1")
xfun::valid_syntax("1+")
xfun::valid_syntax(c("if(T){1+1}", "else {2+2}"), silent = FALSE)
Partition the YAML metadata and the body in a document
Description
Split a document into the YAML metadata (which starts with ---
in the
beginning of the document) and the body.
Usage
yaml_body(x, ..., parse = TRUE)
Arguments
x |
A character vector of the document content. |
... |
Arguments to be passed to |
parse |
Whether to parse the YAML data. |
Value
A list of components yaml
(the YAML data), lines
(starting and
ending line numbers of YAML), and body
(a character vector of the body
text). If YAML metadata does not exist in the document, the components
yaml
and lines
will be missing.
Examples
xfun::yaml_body(c("---", "title: Hello", "output: litedown::html_format", "---",
"", "Content."))
Read YAML data
Description
If the yaml package is installed, use yaml::yaml.load()
to read the
data. If not, use the simple parser taml_load()
instead.
Usage
yaml_load(
x,
...,
handlers = NULL,
envir = parent.frame(),
use_yaml = loadable("yaml")
)
Arguments
x |
A character vector of YAML data. |
... , handlers |
Arguments to be passed to |
envir |
The environment in which R expressions in YAML are evaluated. To
disable the evaluation, use |
use_yaml |
Whether to use the yaml package. |
Value
An R object (typically a list).
Note
R expressions in YAML will be returned as expressions when they are
not evaluated. This is different with yaml::yaml.load()
, which returns
character strings for expressions.
Examples
yaml_load("a: 1")
yaml_load("a: 1", use_yaml = FALSE)