Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nesting glue function in custom function

Tags:

function

r

r-glue

I want to create a custom log function, that would get used in other functions. I am having issues with the custom function where arguments don't seem to flow through to the inner log function. My custom log function is inspired by the logger package but I am planning to expand this usage a bit further (so logger doesn't quite meet my needs)

log_fc <- function(type = c("INFO", "ERROR"), ...) {
  
  print(
    glue::glue("[{type} {Sys.time()}] ", ...)
  )
  
}

Next I am planning to use log_fc in various other custom functions, one example:

test_fc <- function(forecast) {

  log_fc(type = "INFO", "{forecast} is here")
  
  #print(forecast)
}

If I test this, I get the following error:

> test_fc(forecast = "d")
 Error in eval(parse(text = text, keep.source = FALSE), envir) : 
object 'forecast' not found

I am not sure why argument forecast is not being picked up by the inner test_fc function. TIA

like image 841
sactyr Avatar asked Nov 19 '25 17:11

sactyr


1 Answers

There are two things going on.

First, the name forecast is never passed to log_fc. The paste solution never needs the name, it just needs the value, so it still works. You'd need something like

log_fc(type = "INFO", "{forecast} is here", forecast = forecast)

to get the name into log_fc.

The second issue is more complicated. It's a design decision in many tidyverse functions. They want to be able to have code like f(x = 3, y = x + 1) where the x in the second argument gets the value that was bound to it in the first argument.

Standard R evaluation rules would not do that; they would look for x in the environment where f was called, so f(y = x + 1, x = 3) would bind the same values in the function as putting the arguments in the other order.

The tidyverse implementation of this non-standard evaluation messes up R's internal handling of .... The workaround (described here: https://github.com/tidyverse/glue/issues/231) is to tell glue() to evaluate the arguments in a particular location. You need to change your log function to fix this.

One possible change is shown below. I think @Waldi's change is actually better, but I'll leave this one to show a different approach.

log_fc <- function(type = c("INFO", "ERROR"), ...) {
  # Get all the arguments from ...
  args <- list(...)
  
  # The unnamed ones are messages, the named ones are substitutions
  named <- which(names(args) != "")
  
  # Put the named ones in their own environment
  e <- list2env(args[named])
  
  # Evaluate the substitutions in the new env
  print(
    glue::glue("[{type} {Sys.time()}] ", ..., .envir = e)
  )
}

test_fc <- function(forecast) {
  
  log_fc(type = "INFO", "{forecast} is here", forecast = forecast)

  }


test_fc(forecast = "d")
#> [INFO 2022-12-18 06:25:29] d is here

Created on 2022-12-18 with reprex v2.0.2

like image 187
user2554330 Avatar answered Nov 21 '25 06:11

user2554330