r-lib / rlang

Low-level API for programming with R
https://rlang.r-lib.org
Other
500 stars 137 forks source link

Add example for `last_messages()` #1581

Closed batpigandme closed 1 year ago

batpigandme commented 1 year ago

Currently the examples for Display last warnings which references both last_warnings() and last_messages() doesn't have any examples for last_messages().

I'm trying to figure out where I'm going wrong in my attempts to use last_messages(), and having an example of how it should work would probably help me (and others) get there.

I think I finally got it in the end (I was messing things up by leaving the immediate. = TRUE arg from the warnings example in the code for the messages), but it took me a hot second (and I'm, not sure if there's supposed to be a stack of messages as there were for warnings):

Faux reprex (since output changes when you use Rmarkdown:

library(rlang)
global_entrace()
#> Error in globalCallingHandlers(error = function (cnd) : should not be called with handlers on the stack
f <- function() g()
g <- function() message("Hi!")
f()
#> Hi!
rlang::last_messages()
#> [[1]]
#> <message/rlang_message>
#> Message in `message()`:
#> Hi!
#> ---
#> Backtrace:
#>  1. global f()
#>  2. global g()

f <- function() { warning("foo"); g() }
g <- function() { warning("bar", immediate. = TRUE); h() }
h <- function() warning("baz")

f()
#> Warning in f(): foo
#> Warning in g(): bar
#> Warning in h(): baz
rlang::last_warnings()
#> [[1]]
#> <warning/rlang_warning>
#> Warning in `f()`:
#> foo
#> ---
#> Backtrace:
#>  1. global f()
#> 
#> [[2]]
#> <warning/rlang_warning>
#> Warning in `g()`:
#> bar
#> ---
#> Backtrace:
#>  1. global f()
#>  2. global g()

#> [[3]]
#> <warning/rlang_warning>
#> Warning in `h()`:
#> baz
#> ---
#> Backtrace:
#>  1. global f()
#>  2. global g()
#>  3. global h()
rlang::last_messages()
#> [[1]]
#> <message/rlang_message>
#> Message in `message()`:
#> Hi!
#> ---
#> Backtrace:
#>  1. global f()
#>  2. global g()

f <- function() { message_cnd("foo"); g() }
g <- function() { message_cnd("bar"); h() }
h <- function() message_cnd("baz")
f()
#> <message/baz>

## n.b. even though the last message out was <message/baz> goes back to original "Hi" message
rlang::last_messages()
#> [[1]]
#> <message/rlang_message>
#> Message in `message()`:
#> Hi!
#> ---
#> Backtrace:
#>  1. global f()
#>  2. global g()

Created on 2023-02-27 with reprex v2.0.2

lionel- commented 1 year ago

message_cnd() creates a condition object that inherits from "message" but doesn't emit it. Were you looking for inform() or message()?

batpigandme commented 1 year ago

🤦 Duh! Sorry, @lionel-!

Your call re. message() vs inform(), since it seems to work pretty much the same with both as long as global_entrace() is enabled (I'm sure you understand the subtle differences infinitely better than I do).

Faux reprex to avoid the #> Error in globalCallingHandlers(error = function (cnd) : should not be called with handlers on the stack:

With message()

library(rlang)
global_entrace()
f <- function() { message("Hey!"); g() }
g <- function() { message("Hi!"); h() }
h <- function() message("Hello!")

f()
#> Hey!
#> Hi!
#> Hello!

rlang::last_messages()
#> [[1]]
#> <message/rlang_message>
#>   Message in `message()`:
#>   Hey!
#>   ---
#>   Backtrace:
#>   1. global f()
#> 
#> [[2]]
#> <message/rlang_message>
#>   Message in `message()`:
#>   Hi!
#>   ---
#>   Backtrace:
#>   1. global f()
#>   2. global g()
#> 
#> [[3]]
#> <message/rlang_message>
#>   Message in `message()`:
#>   Hello!
#>   ---
#>   Backtrace:
#>   1. global f()
#>   2. global g()
#>   3. global h()

With inform()

library(rlang)
global_entrace()
f <- function() { inform("Hey!"); g() }
g <- function() { inform("Hi!"); h() }
h <- function() inform("Hello!")

f()
#> Hey!
#> Hi!
#> Hello!

rlang::last_messages()
#> [[1]]
#> <message/rlang_message>
#>   Message:
#>   Hey!
#>   ---
#>   Backtrace:
#>   1. global f()
#> 
#> [[2]]
#> <message/rlang_message>
#>   Message:
#>   Hi!
#>   ---
#>   Backtrace:
#>   1. global f()
#>   2. global g()
#> 
#> [[3]]
#> <message/rlang_message>
#>   Message:
#>   Hello!
#>   ---
#>   Backtrace:
#>   1. global f()
#>   2. global g()
#>   3. global h()