diff --git a/DESCRIPTION b/DESCRIPTION index 3ab1f70..c92feb2 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -23,8 +23,11 @@ BugReports: https://github.com/lewinfox/icecream/issues Imports: cli, glue, + pillar (>= 1.6.1), + purrr (>= 0.3.4), rlang Suggests: + checkmate (>= 2.0.0), testthat (>= 3.0.0), withr Config/testthat/edition: 3 diff --git a/NAMESPACE b/NAMESPACE index dda605b..660a42c 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,10 +1,23 @@ # Generated by roxygen2: do not edit by hand +S3method(ic_autopeek,data.frame) +S3method(ic_autopeek,default) +S3method(ic_autopeek,list) +S3method(ic_autopeek_header,data.frame) +S3method(ic_autopeek_header,default) +S3method(ic_autopeek_header,list) export(ic) export(ic_disable) export(ic_enable) importFrom(cli,cli_alert_info) importFrom(glue,glue) +importFrom(glue,glue_collapse) +importFrom(glue,single_quote) +importFrom(pillar,obj_sum) +importFrom(purrr,detect_index) +importFrom(purrr,map2_chr) +importFrom(purrr,map_chr) +importFrom(purrr,map_int) importFrom(rlang,caller_env) importFrom(rlang,caller_fn) importFrom(rlang,enquo) diff --git a/R/autopeek.R b/R/autopeek.R new file mode 100644 index 0000000..a4fd2eb --- /dev/null +++ b/R/autopeek.R @@ -0,0 +1,95 @@ +#' Get descriptive one-line summary of an object +#' +#' This function is created as a modification of [utils::str()] function. It is supposed to +#' create more compacted yet informative summary about an object. It's default value of +#' "icecream.peeking.function" +#' +#' @param object The object to be summarized. +#' @param ... Other arguments passed to methods. +#' +#' @details This is a generic function. Default method simply calls `utils::str` function. +#' +#' @return The function is mainly used for its side effects -- outputting to the terminal. +#' However, it also returns an invisible string of the printed summary. +#' +#' @seealso [utils::str()] [ic_peek()] +ic_autopeek <- function(object, ...) UseMethod("ic_autopeek") + +#' @export +ic_autopeek.default <- function(object, ...) { + str(object, ...) +} + +#' @param max_summary_length Integer. Maximum length of string summarizing the object. +#' +#' @describeIn ic_autopeek Method for list +#' +#' @importFrom glue glue glue_collapse single_quote +#' @importFrom purrr map2_chr map_chr map_int detect_index +#' @importFrom pillar obj_sum +#' @export +ic_autopeek.list <- function(object, + max_summary_length = 70, + ...) { + # names of columns or their index if it does not exist + col_name <- if (is.null(names(object))) { + seq_along(object) + } else { + ifelse( + is.na(names(object)), + seq_along(object), + single_quote(names(object)) + ) + } + + # short type summary as in pillar package + type_summary <- map_chr(object, obj_sum) + + # combine name of column and type summary + col_summary <- glue("${col_name}: {type_summary}") + + # get header of the summary + header <- ic_autopeek_header(object) + + # calculate how many columns summaries can fit into the console + index <- detect_index( + cumsum(map_int(col_summary, nchar) + 2), + ~ . > max_summary_length - nchar(header) - 3 + ) + + # paste summary of all columns + summary <- glue_collapse( + if (index == 0) col_summary else c(col_summary[seq_len(index - 1)], "..."), + sep = ", " + ) + + ret <- paste0(header, summary) + cat(ret) + invisible(ret) +} + +#' @describeIn ic_autopeek Method for data.frame +#' @export +ic_autopeek.data.frame <- ic_autopeek.list + +#' Get a header of the object peeked at +#' +#' @param object The object peeked at. +#' @param ... Other arguments passed to methods. +#' +#' @details This function is used by `ic_autopeek` to get a header of the summary of a object. +#' It should return object's top-level class name and its dimension. +#' +ic_autopeek_header <- function(object, ...) UseMethod("ic_autopeek_header") + +#' @importFrom glue glue +#' @export +ic_autopeek_header.default <- function(object, ...) glue("{class(object)[[1]]}: ") + +#' @importFrom glue glue +#' @export +ic_autopeek_header.list <- function(object, ...) glue("{class(object)[[1]]} [{length(object)}]: ") + +#' @importFrom glue glue +#' @export +ic_autopeek_header.data.frame <- function(object, ...) glue("{class(object)[[1]]} [{nrow(object)} x {ncol(object)}]: ") diff --git a/R/ic.R b/R/ic.R index 54addea..4d3bdf0 100644 --- a/R/ic.R +++ b/R/ic.R @@ -11,7 +11,6 @@ #' ic(f(1)) #' #' ic(f(-1)) -#' #' @importFrom rlang enquo quo_is_missing trace_back quo_get_expr caller_fn caller_env expr_deparse eval_tidy fn_env env_label maybe_missing #' @importFrom glue glue #' @export @@ -27,7 +26,7 @@ ic <- function(x) { trace <- trace_back() num_calls <- length(trace$calls) - parent_ref <- if (num_calls > 1) trace$calls[[num_calls - 1]][[1]] else NULL + parent_ref <- if (num_calls > 1) trace$calls[[num_calls - 1]][[1]] else NULL ref <- attr(trace$calls[[num_calls]], "srcref") loc <- src_loc(ref) diff --git a/R/icecream-package.R b/R/icecream-package.R index 6a9ffb5..08cd96d 100644 --- a/R/icecream-package.R +++ b/R/icecream-package.R @@ -14,6 +14,11 @@ #' complicated debugging but produces a lot of output so is disabled by default. When `ic()` is #' called with no arguments, the context is always printed because showing the location of the #' call is the only reason to call `ic()` on its own. +#' * `icecream.peeking.function`: indicates the function that summarizes the object. Default value +#' is `ic_autopeek`, which works like `utils::str` for most of the time, but gives more +#' informative output for `lists`, `data.frames` and their subclasses in a more compact way. +#' * `icecream.max.lines` Integer. Determines maximum number of lines that the peek of an object +#' occupies; defaults to 1. #' * `icecream.output.function`: Not implemented yet. See the #' [configuration](https://github.com/gruns/icecream#configuration) section of the original #' project docs for details of what it will do. diff --git a/R/peek.R b/R/peek.R new file mode 100644 index 0000000..342e965 --- /dev/null +++ b/R/peek.R @@ -0,0 +1,37 @@ +#' Peek at value of expression +#' +#' This function is a proxy for calling peeking function. +#' +#' @param value The result of evaluating an expression inside the `ic()` function. +#' @param peeking_function The function used to peek at the value. Default value is set by the +#' "icecream.peeking.function" option. +#' @param max_lines Maximum number of lines printed. Default value is set by the +#' "icecream.max.lines" option. +#' +#' @details Default value of `icecream.peeking.function` is `ic_autopeek`. Suggested possible +#' alternatives are: +#' +#' * `utils::str` +#' * `print` +#' * `head` +#' * `summary` +#' * `tibble::glimpse` +#' +#' @return A string to be printed. +#' +#' @seealso [ic_autopeek()] [utils::str()] [base::print()] [utils::head()] [base::summary()] +#' [tibble::glimpse()] +#' @keywords internal +#' @importFrom utils capture.output +ic_peek <- function(value, + peeking_function = getOption("icecream.peeking.function"), + max_lines = getOption("icecream.max.lines")) { + output <- capture.output(peeking_function(value)) + real_lines <- min(length(output), max_lines) + if (real_lines == 1) { + trimws(output[[1]]) + } else { + output <- trimws(output[1:real_lines]) + paste0(c("", output), collapse = "\n") + } +} diff --git a/R/print.R b/R/print.R index eec71fd..30fdcf4 100644 --- a/R/print.R +++ b/R/print.R @@ -35,26 +35,22 @@ ic_print <- function(loc, parent_ref, deparsed_expression = missing_arg(), value # Formatting result if (!is_missing(deparsed_expression)) { # We want to print a one-line summary for complex objects like lists and data frames. - # - # TODO: Taking the first line of output from `str()` is a quick way of getting this but it - # doesn't produce great output (try passing in a `lm()` object - ugly). It would be nice - # to fix this at some point. - str_res <- trimws(capture.output(str(value)))[[1]] + str_res <- ic_peek(value) expression_string <- glue("{{.var {deparsed_expression}}}: {str_res}") } # We need to check what options are set to decide what to print - whether to include the context # or not. - # - # TODO: Shall icecream.include.context be reanamed to something like - # icecream.always.include.context? This may be misleading as context is printed when no - # expression is evaluated regardless of option value prefix <- getOption("icecream.prefix", "ic|") output <- if (!is.null(expression_string)) { if (getOption("icecream.always.include.context")) { glue("{context_string} | {expression_string}") - } else expression_string - } else context_string + } else { + expression_string + } + } else { + context_string + } output <- paste(prefix, output) cli_alert_info(output) diff --git a/R/zzz.R b/R/zzz.R index 4ef30b7..70ce58e 100644 --- a/R/zzz.R +++ b/R/zzz.R @@ -4,6 +4,8 @@ icecream.enabled = TRUE, icecream.prefix = "ic|", icecream.output.function = NULL, + icecream.peeking.function = ic_autopeek, + icecream.max.lines = 1, icecream.arg.to.string.function = NULL, icecream.always.include.context = FALSE ) @@ -15,6 +17,8 @@ icecream.enabled = NULL, icecream.prefix = NULL, icecream.output.function = NULL, + icecream.peeking.function = NULL, + icecream.max.lines = NULL, icecream.arg.to.string.function = NULL, icecream.always.include.context = NULL ) diff --git a/README.Rmd b/README.Rmd index b2efc9b..b3a6b93 100644 --- a/README.Rmd +++ b/README.Rmd @@ -220,6 +220,37 @@ of the call is the only reason to call `ic()` on its own. options(icecream.always.include.context = old.ctx) ``` +### `icecream.peeking.function` and `icecream.max.lines` +These two options control how the result of evaluation of an expression is printed. `icecream.peeking.function` indicates the function that summarizes the object. Default value is `ic_autopeek`, which works like `utils::str` for most of the time, but gives more informative output +for `lists`, `data.frames` and their subclasses in a more compact way. `icecream.max.lines` +determines maximum number of lines that the peek of an object occupies; defaults to 1. + +For more complex data you may want to use e.g. `head` function and 5 lines. + +```{r, include=FALSE} +old.fun <- getOption("icecream.peeking.function") +old.lines <- getOption("icecream.max.lines") +``` + +```{r, include=TRUE} +data(iris) + +ic(iris) # we would like to see header of the data + +options(icecream.peeking.function = head, + icecream.max.lines = 5) + +ic(iris) +``` + +```{r, include=FALSE} +options(icecream.peeking.function = old.fun, + icecream.max.lines = old.lines) +``` + +Note that if `icecream.max.lines` is greater than 1 and summary of an object is longer than 1, the +alert occupies one line more due to the header. + ### `icecream.output.function`, `icecream.arg.to.string.function` Not implemented yet. See the [configuration](https://github.com/gruns/icecream#configuration) section of the original project docs for details of what they will do. diff --git a/README.md b/README.md index fe679c2..f7fa099 100644 --- a/README.md +++ b/README.md @@ -44,10 +44,10 @@ library(icecream) is_negative <- function(x) x < 0 ic(is_negative(1)) -#> ℹ ic| `is_negative(1)`: logi FALSE +#> i ic| `is_negative(1)`: logi FALSE ic(is_negative(-1)) -#> ℹ ic| `is_negative(-1)`: logi TRUE +#> i ic| `is_negative(-1)`: logi TRUE ``` You’re more likely to want to do this within a function: @@ -60,11 +60,11 @@ some_function <- function(x) { } some_function(1) -#> ℹ ic| `intermediate_value / 2`: num 5 +#> i ic| `intermediate_value / 2`: num 5 #> [1] 5 some_function(10) -#> ℹ ic| `intermediate_value / 2`: num 50 +#> i ic| `intermediate_value / 2`: num 50 #> [1] 50 ``` @@ -73,10 +73,10 @@ cluttering the terminal. ``` r df <- ic(iris) -#> ℹ ic| `iris`: 'data.frame': 150 obs. of 5 variables: +#> i ic| `iris`: data.frame [150 x 5]: $'Sepal.Length': dbl [150], ... my_list <- ic(list(a = 1, b = 3, c = 1:100)) -#> ℹ ic| `list(a = 1, b = 3, c = 1:100)`: List of 3 +#> i ic| `list(a = 1, b = 3, c = 1:100)`: list [3]: $'a': dbl [1], $'b': dbl [1], $'c': int [100] ``` ## Inspect execution @@ -150,7 +150,7 @@ evaluating its input but will not print anything. ic_enable() # This is TRUE by default ic(mean(1:100)) -#> ℹ ic| `mean(1:100)`: num 50.5 +#> i ic| `mean(1:100)`: num 50.5 ic_disable() @@ -174,15 +174,15 @@ This is printed at the beginning of every line. Defaults to `"ic|"`. ``` r ic(mean(1:5)) -#> ℹ ic| `mean(1:5)`: num 3 +#> i ic| `mean(1:5)`: num 3 options(icecream.prefix = "DEBUG:") ic(mean(1:5)) -#> ℹ DEBUG: `mean(1:5)`: num 3 +#> i DEBUG: `mean(1:5)`: num 3 options(icecream.prefix = "\U1F366") ic(mean(1:5)) -#> ℹ 🍦 `mean(1:5)`: num 3 +#> i 🍦 `mean(1:5)`: num 3 ``` ### `icecream.always.include.context` @@ -207,6 +207,41 @@ When `ic()` is called with no arguments, the context is always printed because showing the location of the call is the only reason to call `ic()` on its own. +### `icecream.peeking.function` and `icecream.max.lines` + +These two options control how the result of evaluation of an expression +is printed. `icecream.peeking.function` indicates the function that +summarizes the object. Default value is `ic_autopeek`, which works like +`utils::str` for most of the time, but gives more informative output for +`lists`, `data.frames` and their subclasses in a more compact way. +`icecream.max.lines` determines maximum number of lines that the peek of +an object occupies; defaults to 1. + +For more complex data you may want to use e.g. `head` function and 5 +lines. + +``` r +data(iris) + +ic(iris) # we would like to see header of the data +#> i ic| `iris`: data.frame [150 x 5]: $'Sepal.Length': dbl [150], ... + +options(icecream.peeking.function = head, + icecream.max.lines = 5) + +ic(iris) +#> i ic| `iris`: +#> Sepal.Length Sepal.Width Petal.Length Petal.Width Species +#> 1 5.1 3.5 1.4 0.2 setosa +#> 2 4.9 3.0 1.4 0.2 setosa +#> 3 4.7 3.2 1.3 0.2 setosa +#> 4 4.6 3.1 1.5 0.2 setosa +``` + +Note that if `icecream.max.lines` is greater than 1 and summary of an +object is longer than 1, the alert occupies one line more due to the +header. + ### `icecream.output.function`, `icecream.arg.to.string.function` Not implemented yet. See the @@ -215,8 +250,8 @@ of the original project docs for details of what they will do. ## TODO: - - Implement `ic.format()` (see +- Implement `ic.format()` (see [here](https://github.com/gruns/icecream#miscellaneous)). - - Implement `ic.output.function`. At the moment it uses +- Implement `ic.output.function`. At the moment it uses `cli::cli_alert_info()` - - Implement `ic.arg.to.string.function` +- Implement `ic.arg.to.string.function` diff --git a/man/ic.Rd b/man/ic.Rd index 62f4874..ce3e597 100644 --- a/man/ic.Rd +++ b/man/ic.Rd @@ -22,5 +22,4 @@ f <- function(x) x < 0 ic(f(1)) ic(f(-1)) - } diff --git a/man/ic_autopeek.Rd b/man/ic_autopeek.Rd new file mode 100644 index 0000000..b663afe --- /dev/null +++ b/man/ic_autopeek.Rd @@ -0,0 +1,43 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/autopeek.R +\name{ic_autopeek} +\alias{ic_autopeek} +\alias{ic_autopeek.list} +\alias{ic_autopeek.data.frame} +\title{Get descriptive one-line summary of an object} +\usage{ +ic_autopeek(object, ...) + +\method{ic_autopeek}{list}(object, max_summary_length = 70, ...) + +\method{ic_autopeek}{data.frame}(object, max_summary_length = 70, ...) +} +\arguments{ +\item{object}{The object to be summarized.} + +\item{...}{Other arguments passed to methods.} + +\item{max_summary_length}{Integer. Maximum length of string summarizing the object.} +} +\value{ +The function is mainly used for its side effects -- outputting to the terminal. +However, it also returns an invisible string of the printed summary. +} +\description{ +This function is created as a modification of \code{\link[utils:str]{utils::str()}} function. It is supposed to +create more compacted yet informative summary about an object. It's default value of +"icecream.peeking.function" +} +\details{ +This is a generic function. Default method simply calls \code{utils::str} function. +} +\section{Methods (by class)}{ +\itemize{ +\item \code{list}: Method for list + +\item \code{data.frame}: Method for data.frame +}} + +\seealso{ +\code{\link[utils:str]{utils::str()}} \code{\link[=ic_peek]{ic_peek()}} +} diff --git a/man/ic_autopeek_header.Rd b/man/ic_autopeek_header.Rd new file mode 100644 index 0000000..a440d56 --- /dev/null +++ b/man/ic_autopeek_header.Rd @@ -0,0 +1,20 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/autopeek.R +\name{ic_autopeek_header} +\alias{ic_autopeek_header} +\title{Get a header of the object peeked at} +\usage{ +ic_autopeek_header(object, ...) +} +\arguments{ +\item{object}{The object peeked at.} + +\item{...}{Other arguments passed to methods.} +} +\description{ +Get a header of the object peeked at +} +\details{ +This function is used by \code{ic_autopeek} to get a header of the summary of a object. +It should return object's top-level class name and its dimension. +} diff --git a/man/ic_peek.Rd b/man/ic_peek.Rd new file mode 100644 index 0000000..050a3c4 --- /dev/null +++ b/man/ic_peek.Rd @@ -0,0 +1,43 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/peek.R +\name{ic_peek} +\alias{ic_peek} +\title{Peek at value of expression} +\usage{ +ic_peek( + value, + peeking_function = getOption("icecream.peeking.function"), + max_lines = getOption("icecream.max.lines") +) +} +\arguments{ +\item{value}{The result of evaluating an expression inside the \code{ic()} function.} + +\item{peeking_function}{The function used to peek at the value. Default value is set by the +"icecream.peeking.function" option.} + +\item{max_lines}{Maximum number of lines printed. Default value is set by the +"icecream.max.lines" option.} +} +\value{ +A string to be printed. +} +\description{ +This function is a proxy for calling peeking function. +} +\details{ +Default value of \code{icecream.peeking.function} is \code{ic_autopeek}. Suggested possible +alternatives are: +\itemize{ +\item \code{utils::str} +\item \code{print} +\item \code{head} +\item \code{summary} +\item \code{tibble::glimpse} +} +} +\seealso{ +\code{\link[=ic_autopeek]{ic_autopeek()}} \code{\link[utils:str]{utils::str()}} \code{\link[base:print]{base::print()}} \code{\link[utils:head]{utils::head()}} \code{\link[base:summary]{base::summary()}} +\code{\link[tibble:reexports]{tibble::glimpse()}} +} +\keyword{internal} diff --git a/man/icecream.Rd b/man/icecream.Rd index 5577b6c..4314f3b 100644 --- a/man/icecream.Rd +++ b/man/icecream.Rd @@ -20,6 +20,11 @@ or environment will be printed along with the expression and value. This can be complicated debugging but produces a lot of output so is disabled by default. When \code{ic()} is called with no arguments, the context is always printed because showing the location of the call is the only reason to call \code{ic()} on its own. +\item \code{icecream.peeking.function}: indicates the function that summarizes the object. Default value +is \code{ic_autopeek}, which works like \code{utils::str} for most of the time, but gives more +informative output for \code{lists}, \code{data.frames} and their subclasses in a more compact way. +\item \code{icecream.max.lines} Integer. Determines maximum number of lines that the peek of an object +occupies; defaults to 1. \item \code{icecream.output.function}: Not implemented yet. See the \href{https://github.com/gruns/icecream#configuration}{configuration} section of the original project docs for details of what it will do. diff --git a/tests/testthat/setup-lists.R b/tests/testthat/setup-lists.R new file mode 100644 index 0000000..f796677 --- /dev/null +++ b/tests/testthat/setup-lists.R @@ -0,0 +1,17 @@ +unnamed_list <- list( + sample.int(70, size = 8), + sample(letters, size = 4), + logical() +) +partially_named_list <- setNames(unnamed_list, c("first", NA, "last")) +named_list <- setNames(unnamed_list, c("first", "2.", "last")) + +long_list <- list( + c(TRUE, TRUE, FALSE), + sample.int(11, size = 3), + list(a = 1, b = 3:6), + seq_len(10), + LETTERS[19:11], + seq_len(4) +) +long_list_2 <- long_list[c(5, 2, 6, 1, 4, 3)] \ No newline at end of file diff --git a/tests/testthat/test-autopeek-lists.R b/tests/testthat/test-autopeek-lists.R new file mode 100644 index 0000000..e180619 --- /dev/null +++ b/tests/testthat/test-autopeek-lists.R @@ -0,0 +1,109 @@ +library(checkmate) +library(glue) + +test_that("`ic_autopeek()` has specific format for lists", { + purrr::walk( + list( + unnamed_list, partially_named_list, named_list, long_list, + long_list_2 + ), + ~ expect_output( + ic_autopeek(.x), + pattern = "^list \\[\\d+\\]: (?:\\$[^:]+: .+ \\[\\d+\\](?:, )?)+(?:\\.{3})?$" + ) + ) +}) + +# header tests ---- +test_that("`ic_autopeek()` prints correct list length", { + expect_output( + ic_autopeek(unnamed_list), + pattern = glue("^list \\[{length(unnamed_list)}\\]:") + ) +}) + +# element names tests ---- +test_that("`ic_autopeek()` prints indices for unnamed lists", { + #> list [3]: $1: int [8], $2: chr [4], $3: lgl [0] + expect_output( + ic_autopeek(unnamed_list), + pattern = glue_collapse(glue("\\${seq_along(unnamed_list)}:.*")) + ) +}) + +test_that("`ic_autopeek()` prints names for named lists", { + #> list [3]: $'first': int [8], $'2.': chr [4], $'last': lgl [0] + expect_output( + ic_autopeek(named_list), + pattern = glue_collapse(glue("\\$'{names(named_list)}':.*")) + ) +}) + +test_that("`ic_autopeek()` mixes names and indices for partially named lists", { + #> list [3]: $'first': int [8], $2: chr [4], $'last': lgl [0] + list_names <- ifelse( + is.na(names(partially_named_list)), + seq_along(partially_named_list), + glue("'{names(partially_named_list)}'") + ) + expect_output( + ic_autopeek(partially_named_list), + pattern = glue_collapse(glue("\\${list_names}:.*")) + ) +}) + +# element description tests ---- +test_that("`ic_autopeek()` contains vector abbreviations", { + purrr::walk( + list(unnamed_list, partially_named_list, named_list), + ~ expect_output( + ic_autopeek(.x), + pattern = glue_collapse(glue("{purrr::map_chr(.x, vctrs::vec_ptype_abbr)}.*")) + ) + ) +}) + +test_that("`ic_autopeek()` displays element lengths", { + purrr::walk( + list(unnamed_list, partially_named_list, named_list), + ~ expect_output( + ic_autopeek(.x), + pattern = glue_collapse(glue("\\[{lengths(.x)}\\].*")) + ) + ) +}) + +# max length tests ---- +test_that("`ic_autopeek()` truncates description with three dots", { + purrr::walk( + list(long_list, long_list_2), + ~ { + trunc_summary <- capture.output(ic_autopeek(.x, max_summary_length = 70)) + expect_string( + trunc_summary, + pattern = "\\.{3}$", + ) + expect_lte(nchar(trunc_summary), 70) + } + ) +}) + +test_that("`ic_autopeek()` doesn't truncate in the middle of a summary", { + purrr::walk( + list(long_list, long_list_2), + ~ expect_output( + ic_autopeek(.x, max_summary_length = 70), + pattern = "(?:\\$[^:]+: .+ \\[\\d+\\], )+\\.{3}$" + ) + ) +}) + +test_that("`ic_autopeek()` prints only header and '...' when the first element has too wide description already", { + purrr::walk( + list(long_list, long_list_2), + ~ expect_output( + ic_autopeek(.x, max_summary_length = 10), + fixed = glue("list [{length(.x)}]: ...") + ) + ) +}) diff --git a/tests/testthat/test-icecream.R b/tests/testthat/test-icecream.R index aa565f1..a781d10 100644 --- a/tests/testthat/test-icecream.R +++ b/tests/testthat/test-icecream.R @@ -52,7 +52,10 @@ test_that("setting prefixes works", { test_that("function environment is correctly identified", { - f <- function() {ic(); 1} + f <- function() { + ic() + 1 + } # Remove the srcref to ensure we fall back on the environment f <- utils::removeSource(f)