#' Create gist to use as block
#'
#' These functions do the same thing: create a gist; they differ only in what
#' they return. `vw_create_block()` returns a copy of `spec` so that it can be
#' used in a pipe; `vw_create_block_gistid()` returns a list of information
#' about the newly-created gist.
#'
#' You will need a GitHub [Personal Access Token (PAT)](https://github.com/settings/tokens)
#' stored in an environment variable called `GITHUB_PAT`.
#' See [Happy Git with R](http://happygitwithr.com/github-pat.html)
#' for more information on how to acquire and store a PAT.
#'
#' If you are the default (`"https"`) method to upload your gist, you will need to
#' set another environment variable, `GITHUB_USERNAME`, according to your particular
#' account.
#'
#' The default versions of the Vega JavaScript libraries are this package's
#' supported versions. To use the major (current) versions instead, use
#' `version = vega_version(major = TRUE)`.
#'
#' If want to include preview and thumb images with the block, you will need
#' **[nodejs](https://nodejs.org/en/)** installed on your system,
#' and the **[processx](https://processx.r-lib.org/)** and
#' **[magick](https://github.com/ropensci/magick)** packages.
#'
#' @param spec object to be coerced to `vegaspec`, a Vega/Vega-Lite specification
#' @param embed `list` to specify
#' [vega-embed](https://github.com/vega/vega-embed#options) options,
#' see [vega_embed()] for more details.
#' @param .block `character`, YAML text for the `.block` file -
#' use the helper function [vw_block_config()] to specify block-configuration
#' @param version named `list` of `character`:
#' names refer to JavaScript libraries `vega`, `vega_lite`, `vega_embed`,
#' values are the tags for the versions to use in the block - use the
#' helper function [vega_version()] with `major = TRUE` to use the current
#' major versions rather than the versions supported in this package
#' @param description `character`, description for the gist - if `NULL`,
#' looks for a description field in `spec`.
#' @param readme `character`, single line, path to a markdown file;
#' multiple lines, markdown text
#' @param use_thumbnail `logical`, indicates to include a thumbnail image
#' @param use_preview `logical`, indicates to include a preview image
#' @param endpoint `character`, base endpoint for GitHub API, defaults to
#' `"https://api.github.com"`; useful to specify with GitHub Enterprise,
#' e.g. `"https://github.acme.com/api/v3"`
#' (not yet implemented)
#' @param git_method `character`, use `"https"` (default) or `"ssh"`
#' @param env_pat `character`, name of environment variable that contains
#' a GitHub PAT (Personal Access Token), defaults to `"GITHUB_PAT"`;
#' Useful to specify with GitHub Enterprise, e.g. `"GITHUB_ACME_PAT"`
#' (not yet implemented)
#' @param block_host `character`, hostname of blocks server,
#' defaults to `bl.ocks.org`
#' @param quiet `logical`, indicates to supress messages
#' @param browse `logical`, indicates to open browser to blocks web-page
#' when complete
#'
#' @return Called for side effects
#' \describe{
#' \item{`create_block()`}{returns an invisible copy of `spec`}
#' \item{`create_block_gistid()`}{returns a list with elements:
#' \describe{
#' \item{`endpoint`}{`character`, git API endpiont}
#' \item{`id`}{`character`, gist id}
#' }
#' }
#' }
#' @examples
#' \dontrun{
#' # use supported versions
#' vw_create_block(spec_mtcars)
#' # use major versions
#' vw_create_block(spec_mtcars, version = vega_version(major = TRUE))
#' # return gist information
#' vw_create_block_gistid(spec_mtcars)
#' }
#'
#' @seealso [Blocks documentation](https://bl.ocks.org/-/about),
#' [vw_retrieve_block()],
#' [gistr::gist_create_git()], [vega_version()], [vw_block_config()]
#'
#' @export
#'
vw_create_block <- function(spec, embed = vega_embed(),
.block = vw_block_config(),
version = vega_version(major = FALSE),
description = NULL, readme = NULL,
use_thumbnail = TRUE, use_preview = TRUE,
git_method = c("https", "ssh"),
endpoint = NULL, env_pat = NULL,
block_host = NULL, quiet = FALSE,
browse = TRUE) {
# pass along everything to .create_block()
result <- do.call(.vw_create_block, args = as.list(environment()))
invisible(result$spec)
}
#' @rdname vw_create_block
#' @export
#'
vw_create_block_gistid <- function(spec, embed = vega_embed(),
.block = vw_block_config(),
version = vega_version(major = FALSE),
description = NULL, readme = NULL,
use_thumbnail = TRUE, use_preview = TRUE,
git_method = c("https", "ssh"),
endpoint = NULL, env_pat = NULL,
block_host = NULL, quiet = FALSE,
browse = TRUE) {
# pass along everything to .create_block()
result <- do.call(.vw_create_block, args = as.list(environment()))
result[c("endpoint", "id")]
}
.vw_create_block <- function(spec, embed = vega_embed(),
.block = vw_block_config(),
version = vega_version(major = FALSE),
description = NULL, readme = NULL,
use_thumbnail = TRUE, use_preview = TRUE,
git_method = c("https", "ssh"),
endpoint = NULL, env_pat = NULL,
block_host = NULL, quiet = FALSE,
browse = TRUE) {
# validate
assert_packages("fs", "gistr")
git_method <- match.arg(git_method, c("https", "ssh"))
# check that we have a github_pat
if (!.has_envvar(env_pat %||% "GITHUB_PAT")) {
warning("GitHub PAT environment variable not set", call. = FALSE)
}
# if https, check that we have a GITHUB_USERNAME
if (!.has_envvar("GITHUB_USERNAME")) {
warning("GITHUB_USERNAME environment variable not set", call. = FALSE)
}
# create temporary directory
dir_temp <- fs::path(tempdir(), glue::glue("block-{as.numeric(Sys.time())}"))
fs::dir_create(dir_temp)
# doing this here so we can access the description
spec <- as_vegaspec(spec)
# compose a temp directory to contain the gist files
vw_block_build_directory(
dir_temp,
spec = spec,
embed = embed,
version = version,
.block = .block,
readme = readme,
use_thumbnail = use_thumbnail,
use_preview = use_preview
)
# create the gist based on the temp directory
files <- fs::dir_ls(dir_temp, all = TRUE) # ensures we include .block
description <- description %||% spec$description %||% ""
gst <- suppressMessages(
gistr::gist_create_git(
files,
description = description,
browse = FALSE,
git_method = git_method
)
)
# result
block_host <- block_host %||% "bl.ocks.org"
result <- list(
spec = spec,
endpoint = gsub("^(.*)(/gists/.*)$", "\\1", gst$url),
id = gst$id,
url_gist = gst$html_url,
url_block = glue::glue("https://{block_host}/{gst$id}")
)
# if indicated, message the gist URL and the blocks URL
if (!quiet) {
message(glue::glue("block url: {result$url_block}"))
message(glue::glue(" gist url: {result$url_gist}"))
}
# if indicated, open the browser
if (browse) {
utils::browseURL(result$url_block)
}
# delete temporary directory
unlink(dir_temp)
invisible(result)
}
#' Retrieve vegaspec from block
#'
#' You can use this function to retrieve a `vegaspec` from
#' blocks (gists) where the spec is in its own JSON file.
#'
#' You will need a GitHub [Personal Access Token](https://github.com/settings/tokens)
#' stored in an environment variable called `GITHUB_PAT`.
#' See [Happy Git with R](http://happygitwithr.com/github-pat.html)
#' for more information on how to acquire and store a PAT.
#'
#' The `file` argument accepts a regular expression for the name of the JSON file
#' within the gist. If you don't provide a `file`, it will return the first file
#' in the gist with a `.json` extension (not case sensitive). Don't worry about
#' escaping the dots in `file`, it will likely not make a difference.
#'
#' @param id `character` block id
#' @param file `character` filename within block,
#' `NULL` will retrieve first JSON file
#' @inheritParams vw_create_block
#'
#' @return S3 object of class `vegaspec`
#' @examples
#' \dontrun{
#' # https://bl.ocks.org/domoritz/455e1c7872c4b38a58b90df0c3d7b1b9
#' spec_bars <-
#' vw_retrieve_block("455e1c7872c4b38a58b90df0c3d7b1b9")
#' spec_bars <-
#' vw_retrieve_block("dmoritz/455e1c7872c4b38a58b90df0c3d7b1b9")
#' spec_bars <-
#' vw_retrieve_block(
#' "455e1c7872c4b38a58b90df0c3d7b1b9",
#' file = "bar.vl.json"
#' )
#' }
#' @seealso [Blocks documentation](https://bl.ocks.org/-/about),
#' [vw_create_block()], [gistr::gist()]
#' @export
#'
vw_retrieve_block <- function(id, file = NULL, endpoint = NULL, env_pat = NULL,
quiet = FALSE) {
assert_packages("gistr")
# check that we have a github_pat
if (!.has_envvar(env_pat %||% "GITHUB_PAT")) {
warning("GitHub PAT environment variable not set", call. = FALSE)
}
# defaults
endpoint <- endpoint %||% "https://api.github.com"
file <- file %||% "\\.json$"
# get gist
gist <- gistr::gist(id)
# get gist files - determine what matches the regex
gist_files <- names(gist$files)
match <- grepl(file, gist_files, ignore.case = TRUE)
gist_files_match <- gist_files[match]
# no matches
assertthat::assert_that(
length(gist_files_match) > 0,
msg = paste(
glue::glue("no matching files in gist {id}:"),
paste(" ", gist_files, collapse = "\n"),
sep = "\n"
)
)
# more than one match
if (length(gist_files_match) > 1) {
warning(
paste(
glue::glue("mutiple matching files in gist {id}:"),
paste(" ", gist_files, collapse = "\n"),
sep = "\n"
),
call. = FALSE
)
}
# take first match
gist_file <- gist_files_match[1]
if (!quiet) {
message(glue::glue("retrieving `{gist_file}` from gist {id}"))
}
# extract file information for the "chosen" file
file_info <- gist$files[[gist_file]]
# get result
result <- file_info$content
if (file_info$truncated) {
result <- file_info$raw_url
}
# coerce to vegaspec
spec <- as_vegaspec(result)
spec
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.