How to mutate a list-column that holds functions by converting strings to functions with the same name that are available in the environment?

I'm building a tibble in which I organize names (as chr) of data objects and the relevant wrangling function for each one.

For example, I have one function for wrangling mtcars and one function for wrangling iris:

library(dplyr)

wrangle_mtcars <- function() {
  mtcars %>%
    group_by(am) %>%
    summarise(mean_mpg = mean(mpg))
}

wrangle_iris <- function() {
  iris %>%
    group_by(Species) %>%
    summarise(across(starts_with("Sepal"), mean))
}

And I want to organize them in a table that looks like that:

library(tibble)

my_trb <-
  tribble(~data_name, ~.fn_wrangling,
          "mtcars", wrangle_mtcars,
          "iris", wrangle_iris)

my_trb
#> # A tibble: 2 x 2
#>   data_name .fn_wrangling
#>   <chr>     <list>       
#> 1 mtcars    <fn>         
#> 2 iris      <fn>

But instead of building my_trb manually as I did above, I want to do it programmatically. That is, if I'm already given a 1-column table with the name of the data object, I want to simply paste a "wrangle_" prefix and have the tibble "understand" that I'm referring to the function with the same name that is in the global environment.

In other words I want to get from:

given_table <- tibble(data_name = c("mtcars", "iris"))

to

## # A tibble: 2 x 2
##   data_name .fn_wrangling
##   <chr>     <list>       
## 1 mtcars    <fn>         
## 2 iris      <fn>  

By doing something like:

given_table %>%
  mutate(.fn_wrangling = list(paste0("wrangle_", data_name) %>% as.name))

## # A tibble: 2 x 2
##   data_name .fn_wrangling
##   <chr>     <list>       
## 1 mtcars    <sym>  # <----| but I want it to be <fn> as in `my_trb`, not <sym>       
## 2 iris      <sym>  # <----|

But if I use as.function() instead of as.name() it throws an error:

given_table %>%
  mutate(.fn_wrangling = list(paste0("wrangle_", data_name) %>% as.function))

Error: Problem with mutate() column .fn_wrangling.
i .fn_wrangling = list(paste0("wrangle_", data_name) %>% as.function).
x list argument expected


Solution 1:

We could use match.fun

library(dplyr)
given_table %>% 
  rowwise %>%
   mutate(.fn_wrangling = list(match.fun(paste0("wrangle_", data_name)))) %>% 
  ungroup
# A tibble: 2 × 2
  data_name .fn_wrangling
  <chr>     <list>       
1 mtcars    <fn>         
2 iris      <fn>