Search code examples
rargumentsrlang

Can rlang::fn_fmls() be nested?


The documentation shows that this is possible:

fn <- function(a = 1, b = 2) rlang::fn_fmls() 
fn()

$a
[1] 1

$b
[1] 2

I would like to have rlang::fn_fmls() within a function, and return the same structure for arguments within the current scope.

Expected behaviour:

x <- function(a, b){
  rlang::fn_fmls(fn = rlang::current_fn())
}

x(a = 1, b = 2)

$a
[1] 1

$b
[1] 2

Actual behaviour:

x <- function(a, b){
    rlang::fn_fmls(fn = rlang::current_fn())
}

x(a = 1, b = 2)

$a


$b

Another approach I've tried is:

x <- function(a, b){
    tmp <- base::match.call() %>% 
        base::as.list() 
  
  
    tmp %>% 
        stringr::str_detect('x') %>% 
        purrr::discard(tmp, .)
}

x(a = 1, b = 2)

$a
[1] 1

$b
[1] 2

Is there a way with rlang to get my intended results?


Solution

  • Are you looking for rlang::call_args?

    x <- function(a, b) rlang::call_args(sys.call())
    
    x(a = 1, b = 2)
    #> $a
    #> [1] 1
    #> 
    #> $b
    #> [1] 2
    

    If you are looking for the default arguments to be "filled in" then you could do something like:

    x <- function(a = 1, b = 2)
    {
      f  <- rlang::fn_fmls()
      mc <- as.list(match.call())[-1]
      append(mc, f[!names(f) %in% names(mc)])[names(f)]
    }
    

    Which produces the following behavior:

    x()
    #> $a
    #> [1] 1
    #> 
    #> $b
    #> [1] 2
    
    x(a = 5)
    #> $a
    #> [1] 5
    #> 
    #> $b
    #> [1] 2
    
    x(b = 7)
    #> $a
    #> [1] 1
    #> 
    #> $b
    #> [1] 7
    
    x(a = 5, b = 7)
    #> $a
    #> [1] 5
    #> 
    #> $b
    #> [1] 7
    

    Created on 2020-10-03 by the reprex package (v0.3.0)