knitr::opts_chunk$set( collapse = TRUE, comment = "#>", error = TRUE )
library(googledrive)
Things I do in a hidden chunk here, to aid exposition about internal tooling:
drive_bullets <- googledrive:::drive_bullets drive_abort <- googledrive:::drive_abort bulletize <- gargle::bulletize gargle_map_cli <- gargle::gargle_map_cli auth_success <- tryCatch( googledrive:::drive_auth_docs(), googledrive_auth_internal_error = function(e) e )
Everything should be emitted by helpers in utils-ui.R
: specifically, drive_bullets()
(and, for errors, drive_abort()
).
These helpers are all wrappers around cli functions, such as cli::cli_bullets()
.
These may not demo well via pkgdown, but the interactive experience is nice.
drive_bullets(c( "noindent", " " = "indent", "*" = "bullet", ">" = "arrow", "v" = "success", "x" = "danger", "!" = "warning", "i" = "info" ))
The helpers encourage consistent styling and make it possible to selectively silence messages coming from googledrive. The googledrive message helpers:
Use the cli package to get interpolation, inline markup, and pluralization.
Eventually route through rlang::inform()
, which is important because inform()
prints to standard output in interactive sessions.
This means that informational messages won't have the same "look" as errors and can generally be more stylish, at least in IDEs like RStudio.
Use some googledrive-wide style choices, such as:
.drivepath
style is like cli's inline .file
style, except cyan instead of blue..field
style is tweaked to be flanked by single quotes in a no-color situation.Are under the control of the googledrive_quiet
option.
If it's unset, the default is to show messages (unless we're testing, i.e. the environment variable TESTTHAT
is "true"
).
Doing options(googledrive_quiet = TRUE)
will suppress messages.
There are withr-style convenience helpers: local_drive_quiet()
and with_drive_quiet()
.
How we use the inline classes:
.drivepath
for the name or, occasionally, the (partial) path of a Drive file.field
for the value of an argument, e.g. a MIME type.code
for a column in a data frame and for reserved words, such as NULL
, TRUE
, and NA
.arg
, .fun
, .path
, .cls
, .url
for their usual purposedrive_bullets(c( "We need to talk about the {.arg foofy} argument to {.fun blarg}", "You provided {.field a_very_weird_value} and I suspect you're confused \\ about something" ))
Most relevant cli docs:
I use the different bullet points in drive_bullets()
to convey a mood.
Exclamation mark "!"
: I'm not throwing an error or warning, but I want to get the user's attention, because it seems likely (but not certain) that they misunderstand something about googledrive or Google Drive or their Drive files.
Examples:
drive_bullets(c( "!" = "Ignoring {.arg type}. Only consulted for native Google file types.", " " = "MIME type of {.arg file}: {.field mime_type}." )) drive_bullets(c( "!" = "Currently only fields for the {.field files} resource can be \\ checked for validity.", " " = "Nothing done." )) drive_bullets(c( "!" = "No updates specified." )) drive_bullets(c( "!" = "No such file to delete." ))
Information "i": I'm just keeping you informed of how my work is going.
drive_bullets(c( "i" = "No pre-existing file at this filepath. Calling \\ {.fun drive_upload}." )) drive_bullets(c( "i" = "Pre-existing file at this filepath. Calling \\ {.fun drive_update}." )) drive_bullets(c( "i" = "Not logged in as any specific Google user." ))
In cases where we determine there is nothing we can or should do, sometimes I use "!"
and sometimes I use "i"
.
It depends on whether it feels like the user could or should have known that no work would be possible or needed.
Often we need to create bullets from an R object, such as a character vector or a dribble. What needs to happen:
gargle_map_cli()
is a new generic in gargle that turns an object into a vector of strings with cli markup.
Currently gargle exports methods for character
(and NULL
and a default
) and googlesheets4 defines a method for dribble
.
This is likely to be replaced by something in cli itself in due course.
gargle_map_cli(letters[1:3])
By default gargle_map_cli.character()
just applies the .field
style, i.e. the template is "{.field <<x>>}"
.
But the template can be customized, if you need something else.
Note that we use non-standard glue delimiters (<<
and >>
, by default), because we are interpolating into a string with glue/cli markup, where {}
has the usual meaning.
gargle_map_cli(letters[4:6], template = "how about a path {.path <<x>>}?")
The gargle_map_cli.dribble()
method makes a cli-marked up string for each row of the dribble, i.e. for each Drive file.
dat <- drive_find(n_max = 5) gargle_map_cli(dat)
gargle_map_cli.dribble()
also allows a custom template, but it's a more complicated and less common situation than for character
.
We won't get into that here.
(I don't consider the dribble styling to be finalized yet.)
The result of gargle_map_cli()
then gets processed with gargle::bulletize()
, which adds the bullet-specifying names and does aesthetically pleasing truncation.
bulletize(gargle_map_cli(letters)) bulletize(gargle_map_cli(letters), bullet = "x", n_show = 2) drive_bullets(c( "These are surprising things:", bulletize(gargle_map_cli(letters), bullet = "!") )) dat <- drive_find(n_max = 10) drive_bullets(c( "Some Drive files:", bulletize(gargle_map_cli(dat)) ))
It's conceivable that cli will gain a better way of vectorization, but this works for now.
Known dysfunction: it's inefficient to gargle_map_cli()
over the whole object, then truncate with bulletize()
.
But it's easy.
There are contexts, like tibble printing, where formatting stuff that will never see the light of day is really punishing.
But I'm not sure I really have to worry about that.
I am currently using cli::cli_abort()
, which is present in the dev version of cli (as of late May 2021, cli version 2.5.0.9000).
It's wrapped as drive_abort()
, for the same reason as drive_bullets()
, namely to apply some package-wide style tweaks.
The mechanics of drive_abort()
usage are basically the same as drive_bullets()
.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.