Skip to content

Releases: r-lib/rlang

rlang 0.4.4

31 Jan 21:43
Compare
Choose a tag to compare
  • Maintenance release for CRAN.

rlang 0.4.3

25 Jan 10:29
Compare
Choose a tag to compare
  • You can now use glue syntax to unquote on the LHS of :=. This
    syntax is automatically available in all functions taking dots with
    list2() and enquos(), and thus most of the tidyverse. Note that
    if you use the glue syntax in an R package, you need to import glue.

    A single pair of braces triggers normal glue interpolation:

    df <- data.frame(x = 1:3)
    
    suffix <- "foo"
    df %>% dplyr::mutate("var_{suffix}" := x * 2)
    #>   x var_foo
    #> 1 1       2
    #> 2 2       4
    #> 3 3       6

    Using a pair of double braces is for labelling a function argument.
    Technically, this is shortcut for "{as_label(enquo(arg))}". The
    syntax is similar to the curly-curly syntax for interpolating
    function arguments:

    my_wrapper <- function(data, var, suffix = "foo") {
      data %>% dplyr::mutate("{{ var }}_{suffix}" := {{ var }} * 2)
    }
    df %>% my_wrapper(x)
    #>   x x_foo
    #> 1 1     2
    #> 2 2     4
    #> 3 3     6
    
    df %>% my_wrapper(sqrt(x))
    #>   x sqrt(x)_foo
    #> 1 1    2.000000
    #> 2 2    2.828427
    #> 3 3    3.464102
  • Fixed a bug in magrittr backtraces that caused duplicate calls to
    appear in the trace.

  • Fixed a bug in magrittr backtraces that caused wrong call indices.

  • Empty backtraces are no longer shown when rlang_backtrace_on_error
    is set.

  • The tidy eval .env pronoun is now exported for documentation
    purposes.

  • warn() and abort() now check that either class or message
    was supplied. inform() allows sending empty message as it is
    occasionally useful for building user output incrementally.

  • flatten() fails with a proper error when input can't be flattened (#868, #885).

  • inform() now consistently appends a final newline to the message
    (#880).

  • cnd_body.default() is now properly registered.

  • cnd_signal() now uses the same approach as abort() to save
    unhandled errors to last_error().

  • Parsable constants like NaN and NA_integer_ are now deparsed by
    expr_deparse() in their parsable form (#890).

  • Infix operators now stick to their LHS when deparsed by
    expr_deparse() (#890).

rlang 0.4.2

25 Nov 13:47
Compare
Choose a tag to compare
  • New cnd_header(), cnd_body() and cnd_footer() generics. These
    are automatically called by conditionMessage.rlang_error(), the
    default method for all rlang errors.

    Concretely, this is a way of breaking up lazy generation of error
    messages with conditionMessage() into three independent
    parts. This provides a lot of flexibility for hierarchies of error
    classes, for instance you could inherit the body of an error message
    from a parent class while overriding the header and footer.

  • The reminder to call last_error() is now less confusing thanks to
    a suggestion by @markhwhiteii.

  • The functions prefixed in scoped_ have been renamed to use the
    more conventional local_ prefix. For instance, scoped_bindings()
    is now local_bindings(). The scoped_ functions will be
    deprecated in the next significant version of rlang (0.5.0).

  • The .subclass argument of abort(), warn() and inform() has
    been renamed to class. This is for consistency with our
    conventions for class constructors documented in
    https://adv-r.hadley.nz/s3.html#s3-subclassing.

  • inform() now prints messages to the standard output by default in
    interactive sessions. This makes them appear more like normal output
    in IDEs such as RStudio. In non-interactive sessions, messages are
    still printed to standard error to make it easy to redirect messages
    when running R scripts (#852).

  • Fixed an error in trace_back() when the call stack contains a
    quosured symbol.

  • Backtrace is now displayed in full when an error occurs in
    non-interactive sessions. Previously the backtraces of parent errors
    were left out.

rlang 0.4.1

24 Oct 15:03
Compare
Choose a tag to compare
  • New experimental framework for creating bulleted error messages. See
    ?cnd_message for the motivation and an overwiew of the tools we
    have created to support this approach. In particular, abort() now
    takes character vectors to assemble a bullet list. Elements named
    x are prefixed with a red cross, elements named i are prefixed
    with a blue info symbol, and unnamed elements are prefixed with a
    bullet.

  • Capture of backtrace in the context of rethrowing an error from an
    exiting handler has been improved. The tryCatch() context no
    longer leaks in the high-level backtrace.

  • Printing an error no longer recommends calling last_trace(),
    unless called from last_error().

  • env_clone() no longer recreates active bindings and is now just an
    alias for env2list(as.list(env)). Unlike as.list() which returns
    the active binding function on R < 4.0, the value of active bindings
    is consistently used in all versions.

  • The display of rlang errors derived from parent errors has been
    improved. The simplified backtrace (as printed by
    rlang::last_error()) no longer includes the parent errors. On the
    other hand, the full backtrace (as printed by rlang::last_trace())
    now includes the backtraces of the parent errors.

  • cnd_signal() has improved support for rlang errors created with
    error_cnd(). It now records a backtrace if there isn't one
    already, and saves the error so it can be inspected with
    rlang::last_error().

  • rlang errors are no longer formatted and saved through
    conditionMessage(). This makes it easier to use a
    conditionMessage() method in subclasses created with abort(),
    which is useful to delay expensive generation of error messages
    until display time.

  • abort() can now be called without error message. This is useful
    when conditionMessage() is used to generate the message at
    print-time.

  • Fixed an infinite loop in eval_tidy(). It occurred when evaluating
    a quosure that inherits from the mask itself.

  • env_bind()'s performance has been significantly improved by fixing a bug
    that caused values to be repeatedly looked up by name.

  • cnd_muffle() now checks that a restart exists before invoking
    it. The restart might not exist if the condition is signalled with a
    different function (such as stop(warning_cnd)).

  • trace_length() returns the number of frames in a backtrace.

  • Added internal utility cnd_entrace() to add a backtrace to a
    condition.

  • rlang::last_error() backtraces are no longer displayed in red.

  • x %|% y now also works when y is of same length as x (@rcannood, #806).

  • Empty named lists are now deparsed more explicitly as
    "<named list>".

  • Fixed chr() bug causing it to return invisibly.

rlang 0.4.0

25 Jun 13:12
76cd9cf
Compare
Choose a tag to compare

Tidy evaluation

Interpolate function inputs with the curly-curly operator

The main change of this release is the new tidy evaluation operator
{{. This operator abstracts the quote-and-unquote idiom into a
single interpolation step:

my_wrapper <- function(data, var, by) {
  data %>%
    group_by({{ by }}) %>%
    summarise(average = mean({{ var }}, na.rm = TRUE))
}

{{ var }} is a shortcut for !!enquo(var) that should be easier on
the eyes, and easier to learn and teach.

Note that for multiple inputs, the existing documentation doesn't
stress enough that you can just pass dots straight to other tidy eval
functions. There is no need for quote-and-unquote unless you need to
modify the inputs or their names in some way:

my_wrapper <- function(data, var, ...) {
  data %>%
    group_by(...) %>%
    summarise(average = mean({{ var }}, na.rm = TRUE))
}

More robust .env pronoun

Another improvement to tidy evaluation should make it easier to use
the .env pronoun. Starting from this release, subsetting an object
from the .env pronoun now evaluates the corresponding symbol. This
makes .env more robust, in particular in magrittr pipelines. The
following example would previously fail:

foo <- 10
mtcars %>% mutate(cyl = cyl * .env$foo)

This way, using the .env pronoun is now equivalent to unquoting a
constant objects, but with an easier syntax:

mtcars %>% mutate(cyl = cyl * !!foo)

Note that following this change, and despite its name, .env is no
longer referring to a bare environment. Instead, it is a special
shortcut with its own rules. Similarly, the .data pronoun is not
really a data frame.

New functions and features

  • New pairlist2() function with splicing support. It preserves
    missing arguments, which makes it useful for lists of formal
    parameters for functions.

  • is_bool() is a scalar type predicate that checks whether its input
    is a single TRUE or FALSE. Like is_string(), it returns
    FALSE when the input is missing. This is useful for type-checking
    function arguments (#695).

  • is_string() gains a string argument. is_string(x, "foo") is a
    shortcut for is_character(x) && length(x) == 1 && identical(x, "foo").

  • Lists of quosures now have pillar methods for display in tibbles.

  • set_names() now names unnamed input vectors before applying a
    function. The following expressions are now equivalent:

    letters %>% set_names() %>% set_names(toupper)
    
    letters %>% set_names(toupper)
    
  • You can now pass a character vector as message argument for
    abort(), warn(), inform(), and signal(). The vector is
    collapsed to a single string with a "\n" newline separating each
    element of the input vector (#744).

  • maybe_missing() gains a default argument.

  • New functions for weak references: new_weakref(), weakref_key(),
    weakref_value(), and is_weakref() (@wch, #787).

Performance

  • The performance of exec() has been improved. It is now on the same
    order of performance as do.call(), though slightly slower.

  • call2() now uses the new pairlist2() function internally. This
    considerably improves its performance. This also means it now
    preserves empty arguments:

    call2("fn", 1, , foo = )
    #> fn(1, , foo = )
    

Bugfixes and small improvements

  • with_handlers() now installs calling handlers first on the stack,
    no matter their location in the argument list. This way they always
    take precedence over exiting handlers, which ensures their side
    effects (such as logging) take place (#718).

  • In rlang backtraces, the global:: prefix is now only added when
    the function directly inherits from the global environment.
    Functions inheriting indirectly no longer have a namespace
    qualifier (#733).

  • options(error = rlang::entrace) now has better support for errors
    thrown from C (#779). It also saves structured errors in the error
    field of rlang::last_error().

  • ns_env() and ns_env_name() (experimental functions) now support
    functions and environments consisently. They also require an
    argument from now on.

  • is_interactive() is aware of the TESTTHAT environment variable and
    returns FALSE when it is "true" (@jennybc, #738).

  • fn_fmls() and variants no longer coerce their input to a
    closure. Instead, they throw an error.

  • Fixed an issue in knitr that caused backtraces to print even when error = TRUE.

  • The return object from as_function() now inherits from
    "function" (@richierocks, #735).

Lifecycle

We commit to support 5 versions of R. As R 3.6 is about to be
released, rlang now requires R 3.2 or greater. We're also continuing
our efforts to streamline and narrow the rlang API.

  • modify() and prepend() (two experimental functions marked as in
    the questioning stage since rlang 0.3.0) are now deprecated. Vector
    functions are now out of scope for rlang. They might be revived in
    the vctrs or funs packages.

  • exiting() is soft-deprecated because with_handlers() treats
    handlers as exiting by default.

  • The vector constructors like lgl() or new_logical() are now in
    the questioning stage. They are likely to be moved to the vctrs
    package at some point. Same for the missing values shortcuts like
    na_lgl.

  • as_logical(), as_integer(), etc have been soft-deprecated in
    favour of vctrs::vec_cast().

  • type_of(), switch_type(), coerce_type(), and friends are
    soft-deprecated.

  • The encoding and locale API was summarily archived. This API didn't
    bring any value and wasn't used on CRAN.

  • lang_type_of(), switch_lang(), and coerce_lang() were
    archived. These functions were not used on CRAN or internally.

  • Subsetting quosures with [ or [[ is soft-deprecated.

  • All functions that were soft-deprecated, deprecated, or defunct in
    previous releases have been bumped to the next lifecycle stage.

rlang 0.3.4

09 Apr 11:43
Compare
Choose a tag to compare
  • Fixed a unit test that failed on the Solaris CRAN machine.

  • Fixed a valgrind error (@BillDunlap).

rlang 0.3.3

09 Apr 11:42
Compare
Choose a tag to compare
  • Fixed an issue in knitr that caused backtraces to print even when error = TRUE.

  • maybe_missing() gains a default argument.

rlang 0.3.2

21 Mar 15:34
Compare
Choose a tag to compare
  • Fixed protection issue reported by rchk.

  • The experimental option rlang__backtrace_on_error is no longer
    experimental and has been renamed to rlang_backtrace_on_error.

  • New "none" option for rlang_backtrace_on_error.

  • Unary operators applied to quosures now give better error messages.

  • Fixed issue with backtraces of warnings promoted to error, and
    entraced via withCallingHandlers(). The issue didn't affect
    entracing via top level options(error = rlang::entrace) handling.

rlang 0.3.1

09 Jan 12:02
Compare
Choose a tag to compare

This patch release polishes the new backtrace feature introduced in
rlang 0.3.0 and solves bugs for the upcoming release of purrr
0.3.0. It also features as_label() and as_name() which are meant
to replace quo_name() in the future. Finally, a bunch of deparsing
issues have been fixed.

Backtrace fixes

  • New entrace() condition handler. Add this to your RProfile to
    enable rlang backtraces for all errors, including warnings promoted
    to errors:

    if (requireNamespace("rlang", quietly = TRUE)) {
      options(error = rlang::entrace)
    }

    This handler also works as a calling handler:

    with_handlers(
      error = calling(entrace),
      foo(bar)
    )

    However it's often more practical to use with_abort() in that case:

    with_abort(foo(bar))
  • with_abort() gains a classes argument to promote any kind of
    condition to an rlang error.

  • New last_trace() shortcut to print the backtrace stored in the
    last_error().

  • Backtrace objects now print in full by default.

  • Calls in backtraces are now numbered according to their position in
    the call tree. The numbering is non-contiguous for simplified
    backtraces because of omitted call frames.

  • catch_cnd() gains a classes argument to specify which classes of
    condition to catch. It returns NULL if the expected condition
    could not be caught (#696).

as_label() and as_name()

The new as_label() and as_name() functions should be used instead
of quo_name() to transform objects and quoted expressions to a
string. We have noticed that tidy eval users often use quo_name() to
extract names from quosured symbols. This is not a good use for that
function because the way quo_name() creates a string is not a well
defined operation.

For this reason, we are replacing quo_name() with two new functions
that have more clearly defined purposes, and hopefully better names
reflecting those purposes. Use as_label() to transform any object to
a short human-readable description, and as_name() to extract names
from (possibly quosured) symbols.

Create labels with as_label() to:

  • Display an object in a concise way, for example to labellise axes
    in a graphical plot.

  • Give default names to columns in a data frame. In this case,
    labelling is the first step before name repair.

We expect as_label() to gain additional parameters in the future,
for example to control the maximum width of a label. The way an object
is labelled is thus subject to change.

On the other hand, as_name() transforms symbols back to a string in
a well defined manner. Unlike as_label(), as_name() guarantees the
roundtrip symbol -> string -> symbol.

In general, if you don't know for sure what kind of object you're
dealing with (a call, a symbol, an unquoted constant), use
as_label() and make no assumption about the resulting string. If you
know you have a symbol and need the name of the object it refers to,
use as_name(). For instance, use as_label() with objects captured
with enquo() and as_name() with symbols captured with ensym().

Note that quo_name() will only be soft-deprecated at the next major
version of rlang (0.4.0). At this point, it will start issuing
once-per-session warnings in scripts, but not in packages. It will
then be deprecated in yet another major version, at which point it
will issue once-per-session warnings in packages as well. You thus
have plenty of time to change your code.

Minor fixes and features

  • New is_interactive() function. It serves the same purpose as
    base::interactive() but also checks if knitr is in progress and
    provides an escape hatch. Use with_interactive() and
    scoped_interactive() to override the return value of
    is_interactive(). This is useful in unit tests or to manually turn
    on interactive features in RMarkdown outputs

  • calling() now boxes its argument.

  • New done() function to box a value. Done boxes are sentinels to
    indicate early termination of a loop or computation. For instance,
    it will be used in the purrr package to allow users to shortcircuit
    a reduction or accumulation.

  • new_box() now accepts additional attributes passed to structure().

  • Fixed a quotation bug with binary operators of zero or one argument
    such as `/`(1) (#652). They are now deparsed and printed
    properly as well.

  • New call_ns() function to retrieve the namespace of a
    call. Returns NULL if the call is not namespaced.

  • Top-level S3 objects are now deparsed properly.

  • Empty { blocks are now deparsed on the same line.

  • Fixed a deparsing issue with symbols containing non-ASCII
    characters (#691).

  • expr_print() now handles [ and [[ operators correctly, and
    deparses non-syntactic symbols with backticks.

  • call_modify() now respects ordering of unnamed inputs. Before this
    fix, it would move all unnamed inputs after named ones.

  • as_closure() wrappers now call primitives with positional
    arguments to avoid edge case issues of argument matching.

  • as_closure() wrappers now dispatch properly on methods defined in
    the global environment (tidyverse/purrr#459).

  • as_closure() now supports both base-style (e1 and e2) and
    purrr-style (.x and .y) arguments with binary primitives.

  • exec() takes .fn as first argument instead of f, for
    consistency with other rlang functions.

  • Fixed infinite loop with quosures created inside a data mask.

  • Base errors set as parent of rlang errors are now printed
    correctly.

rlang 0.3.0

23 Oct 13:51
Compare
Choose a tag to compare

Breaking changes

The rlang API is still maturing. In this section, you'll find hard
breaking changes. See the life cycle section below for an exhaustive
list of API changes.

  • quo_text() now deparses non-syntactic symbols with backticks:

    quo_text(sym("foo+"))
    #> [1] "`foo+`"
    

    This caused a number of issues in reverse dependencies as
    quo_text() tends to be used for converting symbols to strings.
    quo_text() and quo_name() should not be used for this purpose
    because they are general purpose deparsers. These functions should
    generally only be used for printing outputs or creating default
    labels. If you need to convert symbols to strings, please use
    as_string() rather than quo_text().

    We have extended the documentation of ?quo_text and ?quo_name to
    make these points clearer.

  • exprs() no longer flattens quosures. exprs(!!!quos(x, y)) is now
    equivalent to quos(x, y).

  • The sentinel for removing arguments in call_modify() has been
    changed from NULL to zap(). This breaking change is motivated
    by the ambiguity of NULL with valid argument values.

    call_modify(call, arg = NULL)  # Add `arg = NULL` to the call
    call_modify(call, arg = zap()) # Remove the `arg` argument from the call
  • The %@% operator now quotes its input and supports S4 objects.
    This makes it directly equivalent to @ except that it extracts
    attributes for non-S4 objects (#207).

  • Taking the env_parent() of the empty environment is now an error.

Summary

The changes for this version are organised around three main themes:
error reporting, tidy eval, and tidy dots.

  • abort() now records backtraces automatically in the error object.
    Errors thrown with abort() invite users to call
    rlang::last_error() to see a backtrace and help identifying where
    and why the error occurred. The backtraces created by rlang (you can
    create one manually with trace_back()) are printed in a simplified
    form by default that removes implementation details from the
    backtrace. To see the full backtrace, call
    summary(rlang::last_error()).

    abort() also gains a parent argument. This is meant for
    situations where you're calling a low level API (to download a file,
    parse a JSON file, etc) and would like to intercept errors with
    base::tryCatch() or rlang::with_handlers() and rethrow them with
    a high-level message. Call abort() with the intercepted error as
    the parent argument. When the user prints rlang::last_error(),
    the backtrace will be shown in two sections corresponding to the
    high-level and low-level contexts.

    In order to get segmented backtraces, the low-level error has to be
    thrown with abort(). When that's not the case, you can call the
    low-level function within with_abort() to automatically promote
    all errors to rlang errors.

  • The tidy eval changes are mostly for developers of data masking
    APIs. The main user-facing change is that .data[[ is now an
    unquote operator so that var in .data[[var]] is never masked by
    data frame columns and always picked from the environment. This
    makes the pronoun safe for programming in functions.

  • The !!! operator now supports all classed objects like factors. It
    calls as.list() on S3 objects and as(x, "list") on S4 objects.

  • dots_list() gains several arguments to control how dots are
    collected. You can control the selection of arguments with the same
    name with .homonyms (keep first, last, all, or abort). You can
    also elect to preserve empty arguments with .preserve_empty.

Conditions and errors

  • New trace_back() captures a backtrace. Compared to the base R
    traceback, it contains additional structure about the relationship
    between frames. It comes with tools for automatically restricting to
    frames after a certain environment on the stack, and to simplify
    when printing. These backtraces are now recorded in errors thrown by
    abort() (see below).

  • abort() gains a parent argument to specify a parent error. This
    is meant for situations where a low-level error is expected
    (e.g. download or parsing failed) and you'd like to throw an error
    with higher level information. Specifying the low-level error as
    parent makes it possible to partition the backtraces based on
    ancestry.

  • Errors thrown with abort() now embed a backtrace in the condition
    object. It is no longer necessary to record a trace with a calling
    handler for such errors.

  • with_abort() runs expressions in a context where all errors are
    promoted to rlang errors and gain a backtrace.

  • Unhandled errors thrown by abort() are now automatically saved and
    can be retrieved with rlang::last_error(). The error prints with a
    simplified backtrace. Call summary(last_error()) to see the full
    backtrace.

  • New experimental option rlang__backtrace_on_error to display
    backtraces alongside error messages. See ?rlang::abort for
    supported options.

  • The new signal() function completes the abort(), warn() and
    inform() family. It creates and signals a bare condition.

  • New interrupt() function to simulate an user interrupt from R
    code.

  • cnd_signal() now dispatches messages, warnings, errors and
    interrupts to the relevant signalling functions (message(),
    warning(), stop() and the C function Rf_onintr()). This makes
    it a good choice to resignal a captured condition.

  • New cnd_type() helper to determine the type of a condition
    ("condition", "message", "warning", "error" or "interrupt").

  • abort(), warn() and inform() now accepts metadata with ....
    The data are stored in the condition and can be examined by user
    handlers.

    Consequently all arguments have been renamed and prefixed with a dot
    (to limit naming conflicts between arguments and metadata names).

  • with_handlers() treats bare functions as exiting handlers
    (equivalent to handlers supplied to tryCatch()). It also supports
    the formula shortcut for lambda functions (as in purrr).

  • with_handlers() now produces a cleaner stack trace.

Tidy dots

  • The input types of !!! have been standardised. !!! is generally
    defined on vectors: it takes a vector (typically, a list) and
    unquotes each element as a separate argument. The standardisation
    makes !!! behave the same in functions taking dots with list2()
    and in quoting functions. !!! accepts these types:

    • Lists, pairlists, and atomic vectors. If they have a class, they
      are converted with base::as.list() to allow S3 dispatch.
      Following this change, objects like factors can now be spliced
      without data loss.

    • S4 objects. These are converted with as(obj, "list") before
      splicing.

    • Quoted blocks of expressions, i.e. { } calls

    !!! disallows:

    • Any other objects like functions or environments, but also
      language objects like formula, symbols, or quosures.

    Quoting functions used to automatically wrap language objects in
    lists to make them spliceable. This behaviour is now soft-deprecated
    and it is no longer valid to write !!!enquo(x). Please unquote
    scalar objects with !! instead.

  • dots_list(), enexprs() and enquos() gain a .homonyms
    argument to control how to treat arguments with the same name.
    The default is to keep them. Set it to "first" or "last" to keep
    only the first or last occurrences. Set it to "error" to raise an
    informative error about the arguments with duplicated names.

  • enexprs() and enquos() now support .ignore_empty = "all"
    with named arguments as well (#414).

  • dots_list() gains a .preserve_empty argument. When TRUE, empty
    arguments are stored as missing arguments (see ?missing_arg).

  • dots_list(), enexprs() and enquos() gain a .check_assign
    argument. When TRUE, a warning is issued when a <- call is
    detected in .... No warning is issued if the assignment is wrapped
    in brackets like { a <- 1 }. The warning lets users know about a
    possible typo in their code (assigning instead of matching a
    function parameter) and requires them to be explicit that they
    really want to assign to a variable by wrapping in parentheses.

  • lapply(list(quote(foo)), list2) no longer evaluates foo (#580).

Tidy eval

  • You can now unquote quosured symbols as LHS of :=. The symbol is
    automatically unwrapped from the quosure.

  • Quosure methods have been defined for common operations like
    ==. These methods fail with an informative error message
    suggesting to unquote the quosure (#478, #tidyverse/dplyr#3476).

  • as_data_pronoun() now accepts data masks. If the mask has multiple
    environments, all of these are looked up when subsetting the pronoun.
    Function objects stored in the mask are bypassed.

  • It is now possible to unquote strings in function position. This is
    consistent with how the R parser coerces strings to symbols. These
    two expressions are now equivalent: expr("foo"()) and
    expr((!!"foo")()).

  • Quosures converted to functions with as_function() now support
    nested quosures.

  • expr_deparse() (used to print quosures at the console) now escapes
    special characters. For instance, newlines now print as "\n" (#484).
    This ensures that the roundtrip parse_expr(expr_deparse(x)) is not
    lossy.

  • new_data_mask() now throws an error when bottom is not a child
    of top (#551).

  • Formulas are now evaluated in the correct environment within
    eval_tidy(). This fixes issues in dplyr and other tidy-evaluation
    interfaces.

  • New functions new_quosures() and as_quosures() to create or
    coerce to a list of quosures. This is a small S3 class that ens...

Read more