Repository navigation
Release Notes
This release adds 17 rules (RY112 to RY128) and checks calls to the
project's own functions. RY090 and RY091 check their arguments, RY092
checks simple argument types, and project S3 generics dispatch to their
methods. ry can now check an unsaved buffer from stdin and the R chunks
of R Markdown and Quarto files. It also reads box::use() imports and
typehint class comments, and ry.toml gains per-file rule
severities. Most of the fixes remove false positives
found by checking the top 500 CRAN packages.
The vendored typeshed moves to r-typeshed 0.6.4, which adds export
inventories for lubridate, knitr, and data.table.
Added
- Add RY112 for a
ry: ignore[...]comment with malformed brackets or an
unknown rule name. Such a comment no longer suppresses findings. Anoqa
list that names only other tools' rules no longer suppresses ry findings
either. A barery: ignorewithout a rule list still suppresses. - Add RY113, off by default, for a selective
ry: ignore[...]on RY034 or
RY102 that suppresses nothing. Turn it on with--warn RY113(#584). - Read
typehint0.1.0 class comments in the files that
[annotations.typehint]selects. RY114 reports a value that does not
match its declaration, RY115 an incomplete declaration, RY116
conflicting declarations, and RY117 an invalid declaration.
dump-facts --annotationsexports the declarations as fact schema 3
(#592, #593, #594). - Resolve static
box::use()imports of modules and packages in lexical
scope. ry follows selected names, aliases, wildcard exports, package
typeshed signatures, and the return types of local modules. RY118
reports a selected export or an exact$member that a complete local
module proves missing (#579). - Add RY119 for an
as.integer()call proven to lose range and return
NA. ry tells this newNAapart from anNAin the input and keeps
the fact for condition checks. Unknown inputs and casts that the code
repairs immediately stay silent (#569). - Check the R chunks of R Markdown and Quarto files when
[reports] enabled = true. RY120 marks report input that ry cannot
extract. RY121 marks chunk execution that ry cannot determine
statically (#587). - Add RY122 for a testthat equality assertion that compares a
deterministic expression with itself, such as
expect_equal(round(breaks$major, 3), round(breaks$major, 3)). The
assertion cannot fail (#572). - Add RY123 for
pkg::nameon the branch where
requireNamespace("pkg", quietly = TRUE)returnedFALSE. On that
branch the access errors instead of reaching the fallback (#571). - Add RY124 for a proven network or download call that runs while package
code loads. That means the top level of package ordata-rawcode, and
.onLoador.onAttach. Ordinary function bodies, lazily forced
defaults, connections that R has not opened, calls guarded by
interactive(),getOption(), orSys.getenv(), and masked or dynamic
callees stay silent (#829). - Add RY125 for
ncol(),nrow(), ordim()on a value proven to be a
function, such asncol(data)that resolves toutils::data. These
calls always returnNULL. ry also reports them inside literal
templates passed to proven cli message functions. cli markup, escaped
braces,.envir, masked callees, and dynamic strings stay silent
(#570). - Add RY126 for a sequence subscript proven to mix positive and negative
values, such asx[1:-1],x[seq(1, -1)], or
x[rlang::seq2(-1, 2)]. R rejects these on plain vectors and lists.
Descending sequences of one sign, such asx[3:1], and computed
endpoints stay silent (#355). - Add RY127 for
list(rep(v, n))inside a basec()orappend()whose
other elements are proven flat values of the same classless atomic
type. Thatlist()adds one element that holds the whole vector, not
nelements. Writerep(list(v), n)instead (#359). - Add RY128 for a
diag()call whose matrix dimension is proven invalid.
That is annroworncolthat isNAor negative after truncation to
an integer, or a length-one numericxwith the same property whenx
is the only argument.diag()reads such anxas the dimension, not
as a diagonal entry, so R errors.diag(-0.5)and
diag(-1, names = FALSE)are valid and stay silent. GPArotation
shipped this bug asdiag(d). A vectorx, a classedx, and computed
signs such asdiag(sign(...))stay silent (#320). - RY001 reports a
switch()selector that is still a formal whose default
is proven not length 1, as in
function(type = c("a", "b")) switch(type, ...)withoutmatch.arg().
A call that omitstypeforces the default, and R errors. Only defaults
built from literals count. A rebound formal and a default that reads
other bindings stay silent (#323). - RY001 reports an
iforwhilecondition proven to be a scalarNA.
The proven forms are anNAliteral or typedNA_*_constant, simple
literal expressions over one (such as!NA,NA > 1,c(NA),
any(NA), andas.logical(NA)), and an RY119 cast used directly as the
condition. A binding and a condition that is only possiblyNAstay
silent (#354). - Track lower bounds on length ("at least n") next to exact lengths. A
passinglength(x) > 1Lguard now reaches RY001 and RY002 onifand
whileconditions and onswitch()selectors. The>=, mirrored,
negated, and early-exit forms of the guard work too. Joining a length-2
and a length-3 vector gives "at least 2" instead of unknown. The bound
carries throughc(),rep(), recycling, and negative indexing. A
proven length other than one also rejects aswitch()selector of
unknown or non-vector mode, as R does for environments and functions.
Computed or fractional bounds, a reboundlength, and upper bounds
stay silent.dump-factsexports the bound as
{"kind":"at_least","value":N}(#649). - Dispatch calls to a project's own S3 generics to the project's methods.
Forlbl <- function(x, ...) UseMethod("lbl"), a method's return type
now reacheslbl(obj) + 1in the same file, and a call with no
applicable method reports RY050 (#654). - RY090 and RY091 point at the formal that a call names when the call
provably reaches a project function in the same file. JSON output adds
an optionalrelatedarray,fulloutput adds anote:line, and the
language server sendsrelatedInformationto clients that support it
(#581). - Set rule severities per file with ordered
[[rule-overrides]]tables
inry.toml. Matching files stay in project analysis (#583). - Check an unsaved buffer with
ry check - --stdin-filename PATH. The
buffer replaces the disk contents for analysis and gets the same project context and
diagnostics as a saved file (#582). - Document how to check against a uvr project library through
R_LIBS
(#615) and how to install the Arch Linux AUR packages (#590).
Changed
- RY090 and RY091 check calls to the project's own functions in the CLI
and the language server. In 0.11.0 they checked only stubbed functions,
sohelper <- function(x, scale) x * scale; helper(1, sclae = 2)stayed
silent. ry checks each call against the definition that the call
provably reaches (#659). - RY092 checks calls to simple project functions against what the body
does with each argument, sof <- function(x) x + 1L; f("oops")now
reports. ry reads these contracts only from a function bound once whose
body is a bare formal, a base arithmetic operation between a formal and
a literal, or$on a formal (#674). - RY033 reports only ordering comparisons (
<,>,<=, and>=).
==and!=between character and numeric values no longer report,
and the message names the actual mode (#699). - Lower the confidence of findings inside an error-assertion probe by one
tier. The probes are testthat'sexpect_error(),expect_warning(),
andexpect_snapshot(error = TRUE, ...), and basetry()and
tryCatch(..., error = ...). ry lowers findings only in the probed
argument, and only when the callee resolves to the real testthat or base
function.expect_warning()does not catch errors, so it lowers only
findings that are not errors. Severity stays the same, so
expect_error(1 + "")still reports RY040, at low confidence (#344). library(tidyverse)attaches every core package that has a stub:
purrr, stringr, tibble, readr, ggplot2, and lubridate, not only dplyr
and tidyr. ry reads the list from the stub's new top-levelattaches
field instead of special-casing tidyverse. forcats has no stub and still
leaves the search path open.- Type
a:bby R's:rules when one endpoint is unknown. If either
endpoint is a numeric or logical literal, optionally negated by base
-, the result is a nonempty integer or double vector, so
x <- 1:n; x + "a"now reports RY040. The result is integer only when
fromis a whole number and the end stays in integer range.1.5:nis
double, and ry no longer claims1:3e9is integer. Other endpoint pairs
may be a factor interaction and stay unknown. Character endpoints stay
unknown too, since1:"a"errors at the:. Under a user-defined
`:`,:stays unknown. A user-defined unary-or!now makes
its result unknown (#648). - Tell unknown values apart from known environments and language objects.
quote()of a symbol or call builds a classless language value, so
q <- quote(a + b); q * 2now reports RY040 unless an operand may
select anOpsmethod.new.env(),globalenv(),emptyenv(),
baseenv(), and two-sided formulas build values of unknown class and
stay silent in arithmetic. Calling a local environment or language
binding reports RY070 when no function of that name exists. Otherwise
ry resolves the call to that function.dump-types, hovers, and inlay
hints show the new modes where they used to showunknown(#648). dump-factsexports the newmodevaluesenvironmentandlanguage
without a schema bump. Its documentation now says that enum values and
object fields can grow within a schema version. Read an unrecognized
value as missing evidence.- Inlay hints stay short and mark hidden known fields and uncertainty.
The expanded inlay detail shows the type facts up to a size limit.
dump-typesoutput is unchanged (#591). --exit-zeroalso covers file read and discovery failures during a
check. Usage errors still exit nonzero (#604).- Report a malformed, unreadable, or parser-limited serialized data file
as a degraded scope instead of reading it as empty (#585). - The vendored typeshed moves to r-typeshed 0.6.4 (commit a0dac90).
lubridate, knitr, and data.table gain export inventories, so
library()andimport()of those packages resolve their names and
formals. Before, ry treated them as unstubbed packages that may supply
any name. A script that attaches them can now get RY010 for a name none
of them exports. The individual stub fixes are listed under Fixed. - Environment
pathsandinclude-build-ignoredpatterns match like
rule-override and typehint paths. On Unix,\is a filename
character, not a separator. A path matches by its physical location,
and a non-UTF-8 filename no longer matches through its lossy UTF-8
spelling (#641). - When a file attaches data.table, or its package imports from it,
x[val > 1]on a receiver of unknown type treatsvalas a possible
column instead of reporting RY010, becausexmay be a data.table.
This covers function parameters and the results offread(),
as.data.table(), andsetDT(). Alibrary(data.table)in another
file does not count. The data.table stub typesdata.table(),
rbindlist(),CJ(), andSJ()as data.tables, so their results get
the same treatment withoutlibrary(data.table). Atomic vectors, known
environments, and names outside[keep RY010. The stub also declares
which arguments data.table quotes.setkey(),setorder(), and
frank()quote their column names, sosetorder(dt, grp)stays
silent, while their table and options such asna.lastare still
checked.setindex(),measure(),rollup(),cube(), and
groupingsets()quote their whole.... That keeps
rollup(dt, j = sum(amount), by = "g")silent, but an unbound name
elsewhere in their..., such asby, is not reported. The same
arguments are quoted when data.table is attached only in another project
file. If no project file attaches data.table,setkey()and
setindex()are unknown calls, sosetkey(dt, grp)now reportsgrp.
setkeyv()andsetindexv()read theircolsargument, so an unbound
name there now reports RY010.
Fixed
x[i] <- v,x[[i]] <- v, andx$a <- vupdate the binding's
exported type. The mode widens as R coerces it, a named write adds the
name, and a positive literal subscript or the value extends the length.
dump-factsno longer reports the type from before the write (#839).x[["a"]] <- vandx$a <- von an atomic vector are valid R and no
longer report RY061.[[<-replaces in place, and$<-warns and turns
the vector into a list. RY061 still reports$reads (#840).rep()matches its arguments as R does. A third positional argument is
length.out, noteach. Partial names such aslen =andti =bind,
and a literallength.outsets the length on its own. This removes
false RY002 reports onrep(x, length.out = 1),rep(x, 2, 1), and
rep(x, len = 1).- A long left-associative operator chain, such as a 300-term
1 + 1 + ...or a long|>pipeline, no longer hits the 128-level
syntax nesting limit. Real nesting still does (#842). - Check files with long flat
else ifchains instead of skipping them at
the 128-level nesting limit. Up to 1024else ifarms may nest,
counting chains inside chains. lavaan'slav_object_inspect.Ris now
checked (#696). ry checkreports a file it cannot read or parse at all as one RY000 in
every output format, not only as a line on stderr. Before,
--output-format json --exit-zeroprinted a clean[]for such a file
(#743).- The RY000 for a file ry cannot parse gives a character column, like
every other finding, instead of a byte column after multibyte
characters (#789). - The language server publishes the same RY000 for an open buffer it
cannot parse, instead of keeping the findings from the last good parse.
It clears the RY000 once the buffer parses again (#785). - A NUL byte inside a
#comment is comment text. It no longer causes a
false RY000 that hid the file's other findings (#698). excludepatterns apply when the check root is relative, as in
ry check,ry check ., andry check ./R. Before, ry ignored them
(#642).ry serverexits on the LSPexitnotification, with code 0 after
shutdownand 1 otherwise. Before, it waited for stdin to close (#643).ry check --watchno longer misses an edit made just after the
"watching N file(s)" line (#660).- After the last workspace folder is removed, the language server no
longer re-indexes that folder or republishes diagnostics for its closed
files (#638). - End quietly instead of panicking when stdout closes early, as in
ry check | head(#626). - Check files with thousands of top-level functions in linear time.
torch's generatedRcppExports.Rtook 22 s and now takes under 2 s
(#697). - Skip diagnostics in an argument that the exact callee never evaluates.
ign <- function(x) 1L; ign("oops" + 1L)no longer reports RY040, since
R never evaluates"oops" + 1L(#656). - Return types no longer depend on function names in deep call chains,
and a recursive function keeps its base case, so
r <- function(n) if (n == 0L) "x" else r(n - 1L); r(1L) + 1Lnow
reports (#657). - A project function named like a base function, such as
identity(),
no longer types explicitbase::identity()calls. The same holds for
qualified callbacks such assapply(1:3, base::identity), for omitted
arguments, and for forwarded defaults. This removes false RY040 reports
(#668, #670). - Choose S4 methods by their full signature. The result no longer depends
on registration order, which removes false RY040 reports and finds
missed ones (#650). p + NULLwith a ggplot object, or any other literalNULLnext to an
operand that may dispatch, no longer reports RY040 (#707).- Skip diagnostics in the arm that a literal
ifnever runs, such as the
body ofif (FALSE)or theelseofif (TRUE)(#703). - A name assigned in an arm of an
ifused as a value is bound after the
if. This removes a false RY010 (#694). tryCatch(error = h, expr)takes its type fromexpr, not from the
handler. This removes a false RY001 (#720).- A passing type test such as
is.character(x)drops the zero length of
aNULLdefault, which removes a false RY001 onlogical<len=0>
(#695). - A closure defined in
local(),test_that(), or an R6 class body
shadows the base function of the same name. This removes a false RY091
(#718). - The inner target of
a <- b <- function(...)at top level is a package
binding. This removes a false RY010 in other files (#693). - Track literal dplyr column additions, removals, and renames through
common verbs. This removes two false RY060 reports for
group_by(big = ...)in the pinned dplyr corpus. Dynamic and custom S3
results stay conservative (#353). select()applies its selectors in order, as tidyselect does, so
select(d, -x, y)keepsyandginstead of onlyy. A join no
longer claims a shared non-key column such asv, which R returns as
v.xandv.y. Both remove false RY060 reports (#640).- Bind the target of a base
delayedAssign()without evaluating its
promise. This removes false RY010 reports for lazily bound values
(#349). - Treat a project's own
%<-%or%->%, such as rlang's
standalone-zeallot.Rcopy, as destructuring like zeallot's.
c(found, other) %<-% valuebinds both names instead of leavingfound
at itsNULLplaceholder (#706). - Apply the
data()andload()loaders only when no local, parameter,
or project binding of that name may be the callee. This removes false
RY061 reports on Shiny'sdata <- reactive(...)followed bydata()$x
(#717). - Accept a logical
NAcallback result in purrr's typed maps, which widen
it to the target type'sNA(#352). - Resolve base functions in package
R/code without whole-package
imports, since R finds base before attached packages. Theswitch()
check now reports aNULLselector inside such packages, as it already
did in scripts (#568). - RY070 no longer reports a call guarded by
is.function(x)when ry
inferred no function type forx(#741). - A mode guard such as
is.list(x)oris.numeric(x)no longer keeps a
stale type forxwhen ry inferred none of the tested mode. The guarded
arm sees an unknown value (#752). - A closure no longer gets RY010 for a free name that its enclosing block
binds later. This coverslocal({ ... }), including whenlocalmay be
masked, other braced call arguments such assuppressWarnings({ ... }),
andswitch()arms. It removes false positives in cli, pak, and rlang
(#690). - Enumerate every binding in a serialized workspace that holds an external
pointer, such as a readr tibble saved intoR/sysdata.rda. Before, ry
stopped at the pointer and reported the later bindings unbound (#714). - Function bodies see
<<-updates from writers defined after them or in
another package file, such as aNULLplaceholder that.onLoadfills.
This removes false RY001 and RY070 reports (#706). - RY070 no longer reports a call head bound to a join of
NULLor a value
with a function, such as an optional callback (#700). - Stop checking a closure's free variables against its defining frame once
environment(f) <- rhomoves it. This removes false RY070 reports on
lme4'smkTheta <- NULLR CMD check placeholders (#716). - A call head bound to an opaque or function-valued local or parameter
calls that value, not the base function of the same name.dt()on a
dtargument no longer takes the arity or return type ofstats::dt
(#722). $on a plain list follows R's partial matching. A unique prefix such as
res$nvreads thenvalidfield instead ofNULL, which removes a
false RY040 (#721).$on a base data frame follows the same partial matching, sodf$nv
reads a uniquenvalidcolumn instead of reporting RY060. Tibbles keep
RY060, since their$never partially matches (#753).- A column subset such as
tb[, "a"]keeps the tibble class, since a
tibble never drops to a vector withoutdrop = TRUE. A prefix$on it
now reports RY060, not nothing or a false RY061 (#771). - Stop reporting list arithmetic on
merge(),read.csv(), andgc()
results, such asmerge(a, b)[, 1] - 1. The vendored base stub returns
a data frame fromread.table(),read.csv(), andread.delim(), an
opaque value frommerge(), and a double matrix fromgc()(#709). - A literal positional
x[[1]] <- valuereplaces the element type a list
recorded. A computedx[[i]] <- valueor a positionalx[i] <- value
forgets the recorded element types. This removes false RY061 reports in
ade4 (#715). - RY070 no longer reports a call to a package S4 generic that shares its
name with a value formal, such asres()next tores = FALSE(#712). - A formal or local named
c,signature,setMethod,setGeneric, or
standardGenericmasks S4 registration only inside a function that
registers. Before,error = function(c)anywhere turned off every S4
method and scalar fact in the project (#780). - Bind
.Generic,.Class,.Method, and.Groupin S3 methods named
for a known or NAMESPACE-registered generic. The same holds for a helper
thatregisterS3method()or.S3method()registers in a top-level
evalqOnLoad()block. This removes false RY010 reports such as
lubridate'scomp_posix_date(#348). cut()on a dendrogram, such ascut(dend, h)$lower, no longer reports
RY061. The vendored base stub declarescutan S3 generic, so ry
dispatches tocut.dendrogram()(#711).- A name assigned inside a
[subscript stays bound when the receiver is
opaque or a matrix, as inx[iu <- upper.tri(x)]. This removes false
RY010 reports in lme4 and DescTools (#713). - A callee's formal no longer takes the type of the caller's forwarded
default when the caller tests that argument before the call, as in
if (!is.null(save_period)) cb_save(save_period)(#719). - A literal
x[[N]]on a partly named list reads by position.
list(a = "s", list(b = 2))[[1]]reads"s", so$bon it reports
RY061 (#758). - Stop applying an omitted
NULLdefault after guards that exclude it.
The guards areif (is.null(x)) return(...),!missing(x), every
!is.null()operand of&&,length(x) == 1,length(x) > 0, and a
forloop overx. These no longer give a false RY001 or RY070 (#692). - A local bound to a guard predicate narrows like the guard itself.
has_size <- !is.null(size); if (has_size) ...drops the omitted
NULLdefault likeif (!is.null(size))does, until either name is
rebound (#692). - After
if (is.null(x) || x == 1) return(...),xis notNULL,
whatever the other operand tests. After a return guard whose mode test a
local always passes, such asy <- "a"; if (is.character(y)) return(x),
the local is unknown, since R never gets there with that value (#692). - A passing
iftest such asx == "",!is.null(x) && x == "", or
!x %in% c("a", "b")proves thatxisNULLor scalar, as
stopifnot()already did. Ac()of literals keeps scalar facts. A
lateris.null(x) || pred(x)guard no longer reports a false RY032
(#702). - A successful
stopifnot()proves that a value is scalar orNULLfor
later RY032 checks, which removes the false positive on purrr's guarded
prepend(). Only a few base calls that do not dispatch keep the fact.
Any other call or replacement assignment drops it. A proven vector
alternative survives simple aliases and loop joins, so RY032 reports an
error on the first iteration or on an empty iterator. - An S3 generic inherits
{{ x }}defusing from its project methods, as
it already inheritsenquo()quoting.generic(df, col = mpg)no
longer reportsmpgas RY010 when the method forwards{{ col }}
(#687). - Recognize an S3 generic that runs statements before its final
UseMethod(), such ascheck_not_missing(data). The generic inherits
its methods'{{ x }}defusing unless those statements read the
argument (#774). - A
missing(col)check no longer counts as a use when ry decides whether
a function defusescol. After
if (missing(col)) stop(); dplyr::select(data, {{ col }}), callers'
bare column names no longer report RY010 (#688). - Passing
colto a project validator that only tests its formal with
missing()no longer counts as a use, so a later{{ col }}still
defuses it. An example is thecheck_not_missing()that cards copies
from insightsengineering'sstandalone-checks.R(#688). - The vendored rlang stub says
caller_arg()captures its argument, so a
validator default such asarg_name = rlang::caller_arg(x)no longer
counts as forcingx(#688). - RY010 reports a bare unbound name passed to a defused formal when the
call omits a sibling formal whose default reads it (label = col) and
the body uses that sibling before the embrace, since R then forces it
(#790). - RY010 no longer reports a bare name passed to a formal that only a used
sibling's default captures (q = rlang::enquo(col)), since R never
forces it (#793). - Plain assignments in a top-level rlang-style
on_load({...})block are
package bindings, so reads from other files no longer get RY010. Names
that both arms of a directif-elsein the block bind count too
(#691). - rlang's lazy
lhs %<~% rhsbindslhsand defersrhs, at top level
and insideon_load(). pkgload'sdesc_desc %<~% desc::desclazy
imports no longer report RY010 (#691, #706). Rcpp::loadModule()binds the objects it installs as package bindings.
A literalwhatbinds exactly those names.what = TRUEbinds exactly
theclass_<T>("Name")andfunction("name", ...)objects that the
package'ssrc/declares inRCPP_MODULE(mod), so typos still report
RY010 (#704).- Keep trusting a
length(x) == 1L &&guard when the project's only
length.*methods arefunction(x) length(unclass(x)). When RY032
distrusts a guard because of such a method, the message names the
method and adds a note at its definition (#701). - Apply the
captures_promisearguments of--typeshedstubs when
deciding whether a project function captures its formal. A wrapper
around a stubbed capture no longer reports its caller's name as RY010
(#776). - Stop applying an omitted default's type in the arm selected by a passing
test of that parameter that ry cannot decide, such asis_tensor(dims),
inherits(model, "ets") && is.null(lambda), or
"values" %in% names(sel)(#710). - Stop reporting a classless value inside the arm that a mode test
rejects when ry typed the value as the tested mode, such as theelse
ofis.numeric(shape)on an integershape. R never enters that arm
(#710). - A
$or[[name missing from a list whose names ry knows only in part
is unknown, notNULL. Such lists come fromlist(...),lapply(),
and fields written to an argument or environment. This removes false
RY001 reports in metafor, R.oo, terra, and gridGraphics (#689). - Keep every step of a nested replacement such as
x$f[[i]]$g <- v. An
index step that ry does not model makesx$fforget its element types
instead of recordingx$f$g. This removes false RY061 reports in
forecast and rgl (#708). Sys.Date()returns aDateandSys.time()aPOSIXctin the
vendored base stub. RY061 still reports$on them, and on any classed
atomic value, when no$.<class>method exists in the stubs, the
project, its registrations, its imports, or the enclosing scope. ry no
longer reports code that R never runs: code under a passing
is.numeric()on a Date, POSIXt, difftime, or factor value, and code
under a failinginherits()test of a class the value is known to
carry.sprintf()is empty whenfmtor any value is empty, like
file.path(). Before, the vendored stub claimed the length of the
longest argument.- knitr's
all_labels()andall_rcpp_labels()capture their filters, so
all_labels(engine == "R")no longer reports RY010. - Selection functions no longer claim their input's length.
return: "arg0"
with areturn_lengthrule keeps the first argument's mode and class
but counts its elements again, and drops facts about the whole value. A
data frame keeps its columns with unknown row counts. With the vendored
stubs,head(),tail(),unique(),setdiff(),union(),
na.omit(),subset(), andwindow()no longer give false RY002 and
RY041 reports such asif (head(x, 1) > 0)on a length-3x. Stubs can
declarezero_if_any_param_zerowith one parameter and the new
zero_if_all_params_zeroandsame_emptinessrules. A selection proven
nonempty from a known constant vector keeps its value, so
as.integer(unique(c(1e10, 1e10)))still reports RY119. - In a package, top-level assignments and
<<-writes in tests,inst/,
and other files outsideR/no longer bind names forR/code. This
restores RY010 reports in terra that tinytest variables hid (#804). - A function defined in a test or other file outside
R/no longer
resolves a bare call fromR/code, so its return type no longer types
package code (#806). - A built-in guard such as
is.null(x),length(x) == 1, ormissing(x)
no longer narrowsxwhen a project or local function redefines its
callee, also through`is.null` <-. RY032 no longer trusts a
length(x) == 1Lguard under a backtick`length`mask (#802).
Install ry-cli 0.12.0
Install prebuilt binaries via shell script
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/sims1253/ry/releases/download/v0.12.0/ry-cli-installer.sh | shInstall prebuilt binaries via powershell script
powershell -ExecutionPolicy Bypass -c "irm https://github.com/sims1253/ry/releases/download/v0.12.0/ry-cli-installer.ps1 | iex"Download ry-cli 0.12.0
| File | Platform | Checksum |
|---|---|---|
| ry-cli-aarch64-apple-darwin.tar.gz | Apple Silicon macOS | checksum |
| ry-cli-x86_64-apple-darwin.tar.gz | Intel macOS | checksum |
| ry-cli-aarch64-pc-windows-msvc.zip | ARM64 Windows | checksum |
| ry-cli-x86_64-pc-windows-msvc.zip | x64 Windows | checksum |
| ry-cli-aarch64-unknown-linux-gnu.tar.gz | ARM64 Linux | checksum |
| ry-cli-x86_64-unknown-linux-gnu.tar.gz | x64 Linux | checksum |
| ry-cli-armv7-unknown-linux-gnueabihf.tar.gz | ARMv7 Linux | checksum |
| ry-cli-aarch64-unknown-linux-musl.tar.gz | ARM64 MUSL Linux | checksum |
| ry-cli-x86_64-unknown-linux-musl.tar.gz | x64 MUSL Linux | checksum |