├── .Rbuildignore
├── .gitignore
├── DESCRIPTION
├── LICENSE
├── LICENSE.md
├── NAMESPACE
├── R
├── boxview.R
├── boxview_rec.R
├── helpers.R
├── print.R
└── swap_calls.R
├── README.Rmd
├── README.md
├── boxview.Rproj
├── inst
├── ave.png
├── interaction1.png
└── interaction2.png
├── man
├── boxview.Rd
└── figures
│ └── logo.png
└── tests
├── testthat.R
└── testthat
├── _snaps
└── boxview.md
└── test-boxview.R
/.Rbuildignore:
--------------------------------------------------------------------------------
1 | ^boxview\.Rproj$
2 | ^\.Rproj\.user$
3 | ^README\.Rmd$
4 | ^LICENSE\.md$
5 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .Rproj.user
2 | .Rhistory
3 | .Rdata
4 | .httr-oauth
5 | .DS_Store
6 | .quarto
7 |
--------------------------------------------------------------------------------
/DESCRIPTION:
--------------------------------------------------------------------------------
1 | Package: boxview
2 | Title: Display the Code of a Function in Nested Boxes
3 | Version: 0.0.0.9000
4 | Authors@R:
5 | person("Antoine", "Fabri", , "antoine.fabri@gmail.com", role = c("aut", "cre"))
6 | Description: Functions containing a lot of control flow constructs can be hard
7 | to decipher. By displaying them into boxes and presenting the 'yes' and 'no'
8 | clauses of 'if' calls side by side we make their logic easier to grasp.
9 | License: MIT + file LICENSE
10 | Encoding: UTF-8
11 | Roxygen: list(markdown = TRUE)
12 | RoxygenNote: 7.3.2.9000
13 | Imports:
14 | cli,
15 | rlang,
16 | styler
17 | Suggests:
18 | testthat (>= 3.0.0)
19 | Config/testthat/edition: 3
20 | URL: https://github.com/cynkra/boxview
21 | BugReports: https://github.com/cynkra/boxview/issues
22 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | YEAR: 2025
2 | COPYRIGHT HOLDER: boxview authors
3 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | # MIT License
2 |
3 | Copyright (c) 2025 boxview authors
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/NAMESPACE:
--------------------------------------------------------------------------------
1 | # Generated by roxygen2: do not edit by hand
2 |
3 | S3method(print,boxview)
4 | export(boxview)
5 |
--------------------------------------------------------------------------------
/R/boxview.R:
--------------------------------------------------------------------------------
1 | #' Display code logic in nested boxes
2 | #'
3 | #' `boxview()` displays the code of a function in nested boxes, showing the
4 | #' 'yes' and 'no' clauses of `if` calls side by side. It often makes code easier to
5 | #' skim than the traditional way.
6 | #'
7 | #' @param fun A function
8 | #' @param width The desired width, the output will be wider if the we can't
9 | #' make it narrow enough by wrapping code, and will be narrower if we don't
10 | #' need the width when not wrapping at all
11 | #' @param optimization The level of space optimization, to wrap calls only
12 | #' when needed. `boxview()` is quite slow, and strong optimization can take
13 | #' a long time for big functions. You might not need higher levels most of
14 | #' the time, especially with sufficient width where the difference is often
15 | #' barely noticeable.
16 | #'
17 | #' @return a 'boxview' object that prints the boxed code to the console.
18 | #' @export
19 | #'
20 | #' @examples
21 | #' \dontrun{
22 | #' boxview(ave)
23 | #' boxview(ave, width = 10)
24 | #' boxview(ave, width = 10, optimization = "medium")
25 | #' boxview(interaction)
26 | #' boxview(data.frame)
27 | #' }
28 | boxview <- function(fun, width = 200, optimization = c("weak", "medium", "strong")) {
29 | optimization <- rlang::arg_match(optimization)
30 | header_chr <- cli::code_highlight(deparse(args(fun)))
31 | header_chr <- header_chr[-length(header_chr)]
32 | code <- boxview_rec(swap_calls(body(fun)), width = width, optimization = optimization)
33 | code <- c(header_chr, code)
34 | structure(code, class = c("boxview", "character"))
35 | }
36 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/R/boxview_rec.R:
--------------------------------------------------------------------------------
1 |
2 | boxview_rec <- function(call, col = identity, width = 200, optimization = "weak") {
3 |
4 | # A box of 40 # width
5 | # ┌──────────────────────────────────────┐
6 | # | 36 for a regular call | # width - 4
7 | # | ┌───────────────┐ ┌───────────────┐ |
8 | # | | 17 outside | | 13 inside | | # floor((width - 5) / 2)
9 | # | └───────────────┘ └───────────────┘ | # floor((width - 5) / 2) - 4
10 | # | ┌──────────────────────────────────┐ |
11 | # | | 36 outside, 32 inside | | # width - 4
12 | # | └──────────────────────────────────┘ | # width - 8
13 | # └──────────────────────────────────────┘
14 | #
15 | # * When a call doesn't fit the provided width, its box is extended
16 | # * As a consequence the parent box is extended too and we take advantage of
17 | # the new space there
18 | # * To take advantage of the extra space in this current box, we need
19 | # to rerun with the new width specs, and since it's recursive, that's a
20 | # lot of work and is very slow (though might be optimizationd with clever tricks).
21 | # So we make it optional.
22 |
23 | # `width` is the width of the box
24 | # The call content `with - 4` : regular calls, or nested boxes
25 | # if/else boxes are (width- 4) / 2, or width/2 - 2, rounded
26 |
27 | # if we don't run twice, some calls will stretch the boxes and calls above won't benefit from it
28 | # but it'll be much faster
29 |
30 | width_content <- width - 4
31 |
32 | if (rlang::is_call(call, "{")) {
33 | width_content <- optimal_content_width(call, width_content, optimization)
34 | code <- unlist(lapply(call[-1], boxview_rec, width = width_content, optimization = optimization))
35 | box <- code_to_box(code, col)
36 | return(box)
37 | }
38 |
39 |
40 | # if -------------------------------------------------------------------------
41 | if (rlang::is_call(call, "if")) {
42 | if_has_no <- length(call) == 4
43 |
44 | yes <- call[[3]]
45 | # wrap yes in {}
46 | if (!rlang::is_call(yes, "{")) yes <- bquote({.(yes)})
47 |
48 | if (if_has_no) {
49 | width_nested_box <- floor((width_content - 1) / 2)
50 |
51 | no <- call[[4]]
52 | # wrap no in {}
53 | if (!rlang::is_call(no, "{")) no <- bquote({.(no)})
54 |
55 | # boxes
56 | yes <- boxview_rec(yes, cli::col_green, width = width_nested_box, optimization = optimization)
57 | no <- boxview_rec(no, cli::col_red, width = width_nested_box, optimization = optimization)
58 |
59 | # add empty space at the bottom of the shortest box
60 | if (length(yes) > length(no)) {
61 | length(no) <- length(yes)
62 | } else {
63 | length(yes) <- length(no)
64 | }
65 | yes[is.na(yes)] <- strrep(" ", cli::ansi_nchar(yes[[1]]))
66 | no[is.na(no)] <- strrep(" ", cli::ansi_nchar(no[[1]]))
67 | box <- paste(yes, no)
68 | } else {
69 | yes <- boxview_rec(yes, cli::col_green, width = width_content, optimization = optimization)
70 | yes[is.na(yes)] <- strrep(" ", cli::ansi_nchar(yes[[1]]))
71 | box <- yes
72 | }
73 |
74 | header_chr <- header_if(call, width_content)
75 | box <- c(header_chr, box)
76 | return(box)
77 | }
78 |
79 | # for ------------------------------------------------------------------------
80 | if (rlang::is_call(call, "for")) {
81 | body <- call[[4]]
82 | if (!rlang::is_call(body, "{")) body <- bquote({.(body)})
83 | box <- boxview_rec(body, cli::col_blue, width = width_content, optimization = optimization)
84 | header_chr <- header_for(call, width_content)
85 | box <- c(header_chr, box)
86 | return(box)
87 | }
88 |
89 | # while ------------------------------------------------------------------------
90 | if (rlang::is_call(call, "while")) {
91 | body <- call[[3]]
92 | if (!rlang::is_call(body, "{")) body <- bquote({.(body)})
93 | box <- boxview_rec(body, cli::col_blue, width = width_content, optimization = optimization)
94 | header_chr <- header_while(call, width_content)
95 | box <- c(header_chr, box)
96 | return(box)
97 | }
98 |
99 | # repeat ------------------------------------------------------------------------
100 | if (rlang::is_call(call, "repeat")) {
101 | body <- call[[2]]
102 | if (!rlang::is_call(body, "{")) body <- bquote({.(body)})
103 | box <- boxview_rec(body, cli::col_blue, width = width_content, optimization = optimization)
104 | header_chr <- header_repeat()
105 | box <- c(header_chr, box)
106 | return(box)
107 | }
108 |
109 | if (is_function_definition(call)) {
110 | header_chr <- header_fun(call, width_content)
111 | body <- call[[3]][[3]]
112 | box <- boxview_rec(body, width = width_content, optimization = optimization)
113 | box <- c(header_chr, box)
114 | return(box)
115 | }
116 |
117 | # regular calls or symbols
118 | repeat {
119 | code <- try(cli::code_highlight(styler::style_text(rlang::expr_deparse(call, width = width_content))), silent = TRUE)
120 | stripped <- cli::ansi_strip(code)
121 | if (!inherits(code, "try-error")) {
122 | # FIXME: we should just color the function
123 | if (any(startsWith(stripped[[1]], c("stop(", "abort(", "rlang::abort(", "stopifnot(")))) {
124 | fun <- c("stop", "abort", "rlang::abort", "stopifnot")[startsWith(stripped[[1]], c("stop(", "abort(", "rlang::abort(", "stopifnot("))]
125 | code[[1]] <- paste0(cli::bg_red(cli::col_black(fun)), cli::ansi_substring(code[[1]], cli::ansi_nchar(fun) + 1))
126 | } else if (any(startsWith(stripped[[1]], "return("))) {
127 | code[[1]] <- paste0(cli::bg_green(cli::col_black("return")), cli::ansi_substring(code[[1]], 7))
128 | } else if (any(startsWith(stripped[[1]], c("warning(", "warn(", "rlang::warn(")))) {
129 | fun <- c("warning", "warn", "rlang::warn")[startsWith(stripped[[1]], c("warning(", "warn(", "rlang::warn("))]
130 | code[[1]] <- paste0(cli::bg_yellow(cli::col_black(fun)), cli::ansi_substring(code[[1]], cli::ansi_nchar(fun) + 1))
131 | }
132 | return(code)
133 | }
134 | width <- width + 1
135 | }
136 |
137 | }
138 |
--------------------------------------------------------------------------------
/R/helpers.R:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | ansi_if <- function() cli::code_highlight("if (x) x") |> cli::ansi_substring(1, 3)
5 | ansi_for <- function() cli::code_highlight("for (x in x) x") |> cli::ansi_substring(1, 4)
6 | ansi_in <- function() cli::code_highlight("for (x in x) x") |> cli::ansi_substring(8, 9)
7 | ansi_while <- function() cli::code_highlight("while (x) x") |> cli::ansi_substring(1, 6)
8 | ansi_repeat <- function() cli::code_highlight("repeat x") |> cli::ansi_substring(1, 7)
9 |
10 | header_if <- function(call, width) {
11 | header <- call
12 | header <- header[1:2]
13 | header[[1]] <- quote(.if)
14 | header_chr <- cli::code_highlight(rlang::expr_deparse(header, width = width))
15 | header_chr <- paste(header_chr, collapse = "\n")
16 | header_chr <- paste0(ansi_if(), cli::ansi_substring(header_chr, 4))
17 | header_chr <- strsplit(header_chr, "\n")[[1]]
18 | }
19 |
20 | header_for <- function(call, width) {
21 | header <- call
22 | header <- header[1:2]
23 | header[[2]] <- call("?", call[[2]], call[[3]])
24 | header[[1]] <- quote(.for)
25 | n_sym_chr <- nchar(as.character(call[[2]]))
26 | header_chr <- cli::code_highlight(rlang::expr_deparse(header, width = width))
27 | header_chr <- paste(header_chr, collapse = "\n")
28 | header_chr <- paste0(
29 | ansi_for(),
30 | cli::ansi_substring(header_chr, 5, 5 + n_sym_chr + 1),
31 | ansi_in(),
32 | cli::ansi_substring(header_chr, 5 + n_sym_chr + 3)
33 | )
34 | header_chr <- strsplit(header_chr, "\n")[[1]]
35 | }
36 |
37 | header_while <- function(call, width) {
38 | header <- call
39 | header <- header[1:2]
40 | header[[1]] <- quote(.while)
41 | header_chr <- cli::code_highlight(rlang::expr_deparse(header, width = width))
42 | header_chr <- paste(header_chr, collapse = "\n")
43 | header_chr <- paste0(ansi_while(), cli::ansi_substring(header_chr, 7))
44 | header_chr <- strsplit(header_chr, "\n")[[1]]
45 | }
46 |
47 | header_repeat <- function() {
48 | ansi_repeat()
49 | }
50 |
51 | header_fun <- function(call, width) {
52 | # not great, hacky and width is ignored
53 | call[[3]][[3]] <- quote(expr=...)
54 | header_chr <- rlang::expr_deparse(call, width = width)
55 | header_chr <- cli::code_highlight(header_chr)
56 | header_chr
57 | }
58 |
59 | code_to_box <- function(code, col) {
60 | width_nested_content <- max(cli::ansi_nchar(code))
61 | width_content <- width_nested_content + 4
62 | paddings <- strrep(" ", width_nested_content - cli::ansi_nchar(code))
63 | box <- paste0(col("| "), code, paddings, col(" |"))
64 | top_line <- col(sprintf("\U{250C}%s\U{2510}", strrep("\U{2500}", width_content - 2)))
65 | bottom_line <- col(sprintf("\U{2514}%s\U{2518}", strrep("\U{2500}", width_content - 2)))
66 | box <- c(top_line, box, bottom_line)
67 | }
68 |
69 | optimal_content_width <- function(call, width, optimization) {
70 | if (optimization == "weak") return(width)
71 | if (optimization == "medium") optimization <- "weak"
72 | code_first_pass <- unlist(lapply(call[-1], boxview_rec, width = width, optimization = optimization))
73 | width_nested_content <- max(cli::ansi_nchar(code_first_pass))
74 | width_content <- width_nested_content + 4
75 | max(width_content, width)
76 | }
77 |
78 | is_function_definition <- function(call) {
79 | if (!rlang::is_call(call, "<-") && !rlang::is_call(call, "=")) return(FALSE)
80 | if (length(call) != 3) return(FALSE)
81 | rlang::is_call(call[[3]], "function")
82 | }
83 |
--------------------------------------------------------------------------------
/R/print.R:
--------------------------------------------------------------------------------
1 |
2 | #' @export
3 | print.boxview <- function(x, ...) {
4 | writeLines(x)
5 | invisible(x)
6 | }
7 |
--------------------------------------------------------------------------------
/R/swap_calls.R:
--------------------------------------------------------------------------------
1 | swap_calls <- function (expr) {
2 | if (!is.call(expr))
3 | return(expr)
4 |
5 | expr_is_if_assignment <-
6 | identical(expr[[1]], quote(`<-`)) &&
7 | is.call(expr[[3]]) &&
8 | identical(expr[[3]][[1]], quote(`if`))
9 |
10 | if (expr_is_if_assignment) {
11 | target <- expr[[2]]
12 | if_expr <- expr[[3]]
13 | yes <- if_expr[[3]]
14 | yes_has_braces <- is.call(yes) && identical(yes[[1]], quote(`{`))
15 | if (yes_has_braces) {
16 | # replace last expr of yes clause
17 | yes[[length(yes)]] <- bquote(.(target) <- .(yes[[length(yes)]]))
18 | # the new last expr and other calls in the clause must be checked too
19 | yes <- swap_calls(yes)
20 | } else {
21 | yes <- bquote(.(target) <- .(yes))
22 | yes <- swap_calls(yes)
23 | }
24 | if_expr[[3]] <- yes
25 |
26 | if_has_else <- length(if_expr) == 4
27 |
28 | if (if_has_else) {
29 | no <- if_expr[[4]]
30 | no_has_braces <- is.call(no) && identical(no[[1]], quote(`{`))
31 | if (no_has_braces) {
32 | # replace last expr of yes clause
33 | no[[length(no)]] <- bquote(.(target) <- .(no[[length(no)]]))
34 | # the new last expr and other calls in the clause must be checked too
35 | no <- swap_calls(no)
36 | } else {
37 | no <- bquote(.(target) <- .(no))
38 | no <- swap_calls(no)
39 | }
40 | if_expr[[4]] <- no
41 | }
42 | return(if_expr)
43 | }
44 | expr[] <- lapply(expr, swap_calls)
45 | expr
46 | }
47 |
--------------------------------------------------------------------------------
/README.Rmd:
--------------------------------------------------------------------------------
1 | ---
2 | output: github_document
3 | ---
4 |
5 |
6 |
7 | ```{r, include = FALSE}
8 | knitr::opts_chunk$set(
9 | collapse = TRUE,
10 | comment = "#>",
11 | fig.path = "man/figures/README-",
12 | out.width = "100%"
13 | )
14 | ```
15 |
16 | # boxview
17 |
18 | `boxview::boxview()` displays the code of a function in nested boxes, showing the 'yes' and 'no' clauses of `if` calls side by side. It often makes code easier to skim than the traditional way.
19 |
20 | ## Installation
21 |
22 | You can install the development version of boxview like so:
23 |
24 | ``` r
25 | pak::pak("cynkra/boxview")
26 | ```
27 |
28 | ## Example
29 |
30 | Here's `base::interaction()` shown with boxview and in the console.
31 |
32 | 
33 |
34 | 
35 |
36 | There's also a `width` argument to adjust, and an `optimization` argument that
37 | you might use to get a nicer output, at the cost of taking more time.
38 |
39 | 
40 |
41 | ## See also
42 |
43 | The [flow](https://github.com/moodymudskipper/flow) package and in particular the
44 | function `flow::flow_view()` for a somewhat comparable way to represent functions.
45 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | # boxview
5 |
6 | `boxview::boxview()` displays the code of a function in nested boxes,
7 | showing the ‘yes’ and ‘no’ clauses of `if` calls side by side. It often
8 | makes code easier to skim than the traditional way.
9 |
10 | ## Installation
11 |
12 | You can install the development version of boxview like so:
13 |
14 | ``` r
15 | pak::pak("cynkra/boxview")
16 | ```
17 |
18 | ## Example
19 |
20 | Here’s `base::interaction()` shown with boxview and in the console.
21 |
22 | 
23 |
24 | 
25 |
26 | There’s also a `width` argument to adjust, and an `optimization`
27 | argument that you might use to get a nicer output, at the cost of taking
28 | more time.
29 |
30 | 
31 |
32 | ## See also
33 |
34 | The [flow](https://github.com/moodymudskipper/flow) package and in
35 | particular the function `flow::flow_view()` for a somewhat comparable
36 | way to represent functions.
37 |
--------------------------------------------------------------------------------
/boxview.Rproj:
--------------------------------------------------------------------------------
1 | Version: 1.0
2 |
3 | RestoreWorkspace: No
4 | SaveWorkspace: No
5 | AlwaysSaveHistory: Default
6 |
7 | EnableCodeIndexing: Yes
8 | UseSpacesForTab: Yes
9 | NumSpacesForTab: 2
10 | Encoding: UTF-8
11 |
12 | RnwWeave: Sweave
13 | LaTeX: pdfLaTeX
14 |
15 | AutoAppendNewline: Yes
16 | StripTrailingWhitespace: Yes
17 | LineEndingConversion: Posix
18 |
19 | BuildType: Package
20 | PackageUseDevtools: Yes
21 | PackageInstallArgs: --no-multiarch --with-keep.source
22 | PackageRoxygenize: rd,collate,namespace
23 |
--------------------------------------------------------------------------------
/inst/ave.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cynkra/boxview/00033beeb716b57330d358921ebb75acd340fac7/inst/ave.png
--------------------------------------------------------------------------------
/inst/interaction1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cynkra/boxview/00033beeb716b57330d358921ebb75acd340fac7/inst/interaction1.png
--------------------------------------------------------------------------------
/inst/interaction2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cynkra/boxview/00033beeb716b57330d358921ebb75acd340fac7/inst/interaction2.png
--------------------------------------------------------------------------------
/man/boxview.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/boxview.R
3 | \name{boxview}
4 | \alias{boxview}
5 | \title{Display code logic in nested boxes}
6 | \usage{
7 | boxview(fun, width = 200, optimization = c("weak", "medium", "strong"))
8 | }
9 | \arguments{
10 | \item{fun}{A function}
11 |
12 | \item{width}{The desired width, the output will be wider if the we can't
13 | make it narrow enough by wrapping code, and will be narrower if we don't
14 | need the width when not wrapping at all}
15 |
16 | \item{optimization}{The level of space optimization, to wrap calls only
17 | when needed. \code{boxview()} is quite slow, and strong optimization can take
18 | a long time for big functions. You might not need higher levels most of
19 | the time, especially with sufficient width where the difference is often
20 | barely noticeable.}
21 | }
22 | \value{
23 | a 'boxview' object that prints the boxed code to the console.
24 | }
25 | \description{
26 | \code{boxview()} displays the code of a function in nested boxes, showing the
27 | 'yes' and 'no' clauses of \code{if} calls side by side. It often makes code easier to
28 | skim than the traditional way.
29 | }
30 | \examples{
31 | \dontrun{
32 | boxview(ave)
33 | boxview(ave, width = 10)
34 | boxview(ave, width = 10, optimization = "medium")
35 | boxview(interaction)
36 | boxview(data.frame)
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/man/figures/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cynkra/boxview/00033beeb716b57330d358921ebb75acd340fac7/man/figures/logo.png
--------------------------------------------------------------------------------
/tests/testthat.R:
--------------------------------------------------------------------------------
1 | # This file is part of the standard setup for testthat.
2 | # It is recommended that you do not modify it.
3 | #
4 | # Where should you do additional test configuration?
5 | # Learn more about the roles of various files in:
6 | # * https://r-pkgs.org/testing-design.html#sec-tests-files-overview
7 | # * https://testthat.r-lib.org/articles/special-files.html
8 |
9 | library(testthat)
10 | library(boxview)
11 |
12 | test_check("boxview")
13 |
--------------------------------------------------------------------------------
/tests/testthat/_snaps/boxview.md:
--------------------------------------------------------------------------------
1 | # boxview() snapshots
2 |
3 | Code
4 | boxview(ave)
5 | Output
6 | function (x, ..., FUN = mean)
7 | ┌───────────────────────────────────────────────────────────────┐
8 | | if (missing(...)) |
9 | | ┌───────────────┐ ┌─────────────────────────────────────────┐ |
10 | | | x[] <- FUN(x) | | g <- interaction(...) | |
11 | | └───────────────┘ | split(x, g) <- lapply(split(x, g), FUN) | |
12 | | └─────────────────────────────────────────┘ |
13 | | x |
14 | └───────────────────────────────────────────────────────────────┘
15 |
16 | ---
17 |
18 | Code
19 | boxview(ave, width = 40)
20 | Output
21 | function (x, ..., FUN = mean)
22 | ┌───────────────────────────────┐
23 | | if (missing(...)) |
24 | | ┌────────┐ ┌────────────────┐ |
25 | | | x[] <- | | g <- | |
26 | | | FUN( | | interaction( | |
27 | | | x | | ... | |
28 | | | ) | | ) | |
29 | | └────────┘ | split( | |
30 | | | x, g | |
31 | | | ) <- | |
32 | | | lapply( | |
33 | | | split( | |
34 | | | x, | |
35 | | | g | |
36 | | | ), | |
37 | | | FUN | |
38 | | | ) | |
39 | | └────────────────┘ |
40 | | x |
41 | └───────────────────────────────┘
42 |
43 | ---
44 |
45 | Code
46 | boxview(ave, width = 40, optimization = "strong")
47 | Output
48 | function (x, ..., FUN = mean)
49 | ┌───────────────────────────────┐
50 | | if (missing(...)) |
51 | | ┌────────┐ ┌────────────────┐ |
52 | | | x[] <- | | g <- | |
53 | | | FUN( | | interaction( | |
54 | | | x | | ... | |
55 | | | ) | | ) | |
56 | | └────────┘ | split(x, g) <- | |
57 | | | lapply( | |
58 | | | split( | |
59 | | | x, | |
60 | | | g | |
61 | | | ), FUN | |
62 | | | ) | |
63 | | └────────────────┘ |
64 | | x |
65 | └───────────────────────────────┘
66 |
67 | # swapcall() snapshots
68 |
69 | Code
70 | swap_calls(quote({
71 | a <- if (this) {
72 | if (this) a else b
73 | } else b
74 | }))
75 | Output
76 | {
77 | if (this) {
78 | if (this)
79 | a <- a
80 | else a <- b
81 | }
82 | else a <- b
83 | }
84 |
85 |
--------------------------------------------------------------------------------
/tests/testthat/test-boxview.R:
--------------------------------------------------------------------------------
1 | test_that("boxview() snapshots", {
2 | expect_snapshot(boxview(ave))
3 | expect_snapshot(boxview(ave, width = 40))
4 | expect_snapshot(boxview(ave, width = 40, optimization = "strong"))
5 | })
6 |
7 | test_that("swapcall() snapshots", {
8 | expect_snapshot(
9 | swap_calls(quote({a <- if (this) {if (this) a else b} else b}))
10 | )
11 | })
12 |
--------------------------------------------------------------------------------