Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
231 views
in Technique[技术] by (71.8m points)

r - How to assign a quosure to another object?

I want to change the name of some argument.

Following the guidelines, I should use lifecycle::deprecate_warn and then attribute the old name to the new name.

However, in my function, the argument is normally used with quosures, so the attribution fails with an error:

library(tidyverse)
library(lifecycle)
library(rlang)
my_fun = function(df, cols, .vars = deprecated()){
  if (quo_is_missing(enquo(cols)) && !quo_is_missing(enquo(.vars))) {
    deprecate_warn("0.1.6", "my_fun(.vars=)", "my_fun(cols=)")
    cols <- .vars #error is thrown here
  }
  select(df, {{cols}})
}

my_fun(iris, cols=Sepal.Length) %>% head()
#>   Sepal.Length
#> 1          5.1
#> 2          4.9
#> 3          4.7
#> 4          4.6
#> 5          5.0
#> 6          5.4
my_fun(iris, .vars=Sepal.Length) %>% head()
#> Warning: The `.vars` argument of `my_fun()` is deprecated as of <NA> 0.1.6.
#> Please use the `cols` argument instead.
#> This warning is displayed once every 8 hours.
#> Call `lifecycle::last_warnings()` to see where this warning was generated.
#> Error in my_fun(iris, .vars = Sepal.Length): objet 'Sepal.Length' introuvable

Created on 2021-01-28 by the reprex package (v0.3.0)

I blindly tried various things with enquo and others but nothing worked.

How can I attribute the old name to the new name?

question from:https://stackoverflow.com/questions/65937178/how-to-assign-a-quosure-to-another-object

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Recall that {{ is shorthand for !!enquo(). Since you want to quote either cols or .vars, depending on which one is missing, I suggest doing !! and enquo() separately:

my_fun = function(df, cols, .vars = deprecated()){
  if (quo_is_missing(enquo(cols)) && !quo_is_missing(enquo(.vars))) {
    deprecate_warn("0.1.6", "my_fun(.vars=)", "my_fun(cols=)")
    cols <- enquo(.vars)    # Quote .vars, if cols is missing
  }
  else cols <- enquo(cols)  # Quote cols, if cols is not missing

  select(df, !!cols)        # Unquote with !!, instead of {{, which is !!enquo()
}

my_fun(iris, cols=Sepal.Length) %>% head()    # Works
my_fun(iris, .vars=Sepal.Length) %>% head()   # Also works

If you absolutely must use {{, the only way to modify the expression that gets captured is to change how the function is called. This can be done with a little bit of recursion (i.e., having my_fun call itself):

my_fun = function(df, cols, .vars = deprecated()){
  if (quo_is_missing(enquo(cols)) && !quo_is_missing(enquo(.vars))) {
    deprecate_warn("0.1.6", "my_fun(.vars=)", "my_fun(cols=)")
    return( my_fun(df, {{.vars}}) )   # .vars will be captured as cols
  }

  select(df, {{cols}})
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...