AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified MIT Self-run

Tidy Evaluation

skill-jsperger-llm-r-skills-tidy-evaluation · by jsperger

>

No reviews yet
0 installs
31 views
0.0% view→install

Install

$ agentstack add skill-jsperger-llm-r-skills-tidy-evaluation

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets Used
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-jsperger-llm-r-skills-tidy-evaluation)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
2mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Tidy Evaluation? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Tidy Evaluation Programming Patterns

Data masking lets you refer to data frame columns as if they were regular objects. Programming with data-masked functions requires special patterns to pass column references through your functions.

Quick Reference

| Goal | Pattern | |------|---------| | Forward single argument | {{ var }} | | Forward ... to data-mask | ... directly | | Forward ... to tidy-select (single arg) | c(...) | | Use column name from string | .data[[var]] | | Use column names from vector | across(all_of(vars)) | | Disambiguate env-variable | .env$x | | Disambiguate data-variable | .data$x | | Bridge selection to data-mask | across({{ var }}) | | Bridge names to data-mask | across(all_of(vars)) | | Bridge data-mask to selection | transmute() then all_of() | | Prevent double evaluation | Assign to column first |

What is Data Masking?

Data masking inserts a data frame at the bottom of the environment chain, giving columns precedence over user-defined variables:

# Without masking: must use $ notation
mean(mtcars$cyl + mtcars$am)

# With masking: columns are directly accessible
with(mtcars, mean(cyl + am))
dplyr::summarise(mtcars, mean(cyl + am))

Why Injection is Needed

Data-masking functions defuse their arguments. When you wrap them, you must inject the user's expression:

# Without injection: summarise sees literal "var1 + var2"
my_mean  Column to summarize.
#' @param cols  Columns to pivot.
#' @param ...  Name-value pairs.

Forwarding Patterns

Single Argument with {{}}

The embrace operator forwards an argument, inheriting behavior from the wrapped function:

# Forwarding to data-masked context
my_summarise  dplyr::summarise({{ var }})
}
mtcars |> my_summarise(mean(cyl))

# Forwarding to tidy-select context
my_pivot  tidyr::pivot_longer(cols = {{ cols }})
}
mtcars |> my_pivot(starts_with("c"))

Multiple Arguments with ...

Pass ... directly to data-masked functions:

my_group_by  dplyr::group_by(...)
}
mtcars |> my_group_by(cyl, am)

For tidy-select functions taking a single argument, wrap in c():

my_pivot  tidyr::pivot_longer(c(...))
}
mtcars |> my_pivot(cyl, am, vs)

Names Patterns

Use strings or character vectors instead of expressions. Your function becomes "regular" with no data-masking complications.

.data[[var]] for Single Column

my_mean  dplyr::summarise(mean = mean(.data[[var]]))
}
my_mean(mtcars, "cyl")

# No masking surprises
am  tidyr::pivot_longer(all_of(vars))
mtcars |> dplyr::select(all_of(vars))

Loop Pattern

vars 
    dplyr::summarise(mean = mean(.data[[var]]))
  print(result)
}

# Or with purrr
purrr::map(vars, ~ dplyr::summarise(mtcars, mean = mean(.data[[.x]])))

Bridge Patterns

Convert between argument behaviors when the wrapped function doesn't match your desired interface.

Selection to Data-Mask: across()

Give your function tidy-select behavior when wrapping a data-masked function:

my_group_by  dplyr::group_by(across({{ var }}))
}
# Now supports selection helpers:
mtcars |> my_group_by(starts_with("c"))

For ..., wrap in c():

my_group_by  dplyr::group_by(across(c(...)))
}

Names to Data-Mask: across(all_of())

Accept character vectors for data-masked operations:

my_group_by  dplyr::group_by(across(all_of(vars)))
}
my_group_by(mtcars, c("cyl", "am"))

Data-Mask to Selection: transmute() Bridge

Three-step pattern for data-masked input to tidy-select functions:

my_pivot_longer  my_pivot_longer(cyl, am_scaled = am * 100)

Transformation Patterns

Named Arguments: Code Around {{}}

Add code around embraced arguments:

my_mean  dplyr::summarise(mean = mean({{ var }}, na.rm = TRUE))
}

... Arguments: Use across()

Map an expression across multiple columns:

my_mean  dplyr::summarise(
    across(c(...), ~ mean(.x, na.rm = TRUE))
  )
}
mtcars |> my_mean(cyl, disp, hp)

Filter with if_all() / if_any()

Combine logical conditions across columns:

filter_non_min  dplyr::filter(
    if_all(c(...), ~ .x != min(.x, na.rm = TRUE))
  )
}

filter_any_max  dplyr::filter(
    if_any(c(...), ~ .x == max(.x, na.rm = TRUE))
  )
}

Disambiguation: .data and .env Pronouns

Data masking can cause collisions when variable names exist in both the data and environment.

Column Collisions

x  dplyr::mutate(z = y / x)
#> Uses column x (data takes precedence)

# Explicit: use environment x
df |> dplyr::mutate(z = y / .env$x)

In Functions (Critical)

Always use .env for function parameters that might collide:

my_rescale  dplyr::mutate(
    "{{ var }}" := {{ var }} / .env$factor
  )
}

Full Disambiguation

df |> dplyr::mutate(
  result = .data$y / .env$x
)

Pitfalls

Double Evaluation

Expressions injected multiple times execute multiple times:

# BAD: times100() runs twice
summarise_stats  dplyr::summarise(
    mean = mean({{ var }}),
    sd = sd({{ var }})
  )
}
# If var = times100(cyl), function executes twice

# GOOD: Evaluate once, reference result
summarise_stats 
    dplyr::transmute(var = {{ var }}) |>
    dplyr::summarise(mean = mean(var), sd = sd(var))
}

Exception: Glue strings ("{{ var }}") don't suffer from double evaluation.

{{ Out of Context

Outside data-masking, {{ becomes literal double-braces and silently returns the value:

# In non-tidy-eval function:
f  [1] 2  # No error, but not defuse-and-inject

!! and !!! Out of Context

Outside injection context, these become logical negation:

x  dplyr::select(data:ncol(data))
#> Works correctly

# Data masking: potential collision
data |> dplyr::mutate(y = data + 1)
#> Uses column 'data', not the data frame

See Also

  • r-metaprogramming: Defusing, quosures, expression building mechanics
  • designing-tidy-r-functions: Function API design principles
  • rlang-conditions: Error handling with rlang

Vignettes

Access detailed rlang documentation via R:

# Data masking concepts
vignette("data-mask", package = "rlang")

# Programming with data masking
vignette("data-mask-programming", package = "rlang")

# Or browse all vignettes
browseVignettes("rlang")

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.