23  One value, applied to every column that matches

Writing the same thing for eight columns is eight chances to write it slightly differently. add where takes the same pattern the last two chapters used and one value to apply to each column it matches. Inside that value, value stands for the column being worked on.

survey |> add(where(startsWith(name, "q"), value * 10))
respondent region q1_score q2_score
1 West 40 20
2 East 50 50
3 West 30 50
survey >> add(where(name.starts("q"), value * 10))
respondent region q1_score q2_score
1 West 40 20
2 East 50 50
3 West 30 50

The matched columns keep their names. That is not a rule this had to invent: add already covers making a column and replacing one, so replacing q1_score with a new q1_score is the ordinary case.

name and value are a pair. One is what the column is called, the other is what it holds, and they are the same two words the reshaping verbs use.

summarize where works the same way and collapses instead.

survey |> summarize(where(endsWith(name, "_score"), average(value)), by = region)
region q1_score q2_score
East 5.0 5.0
West 3.5 3.5
survey >> summarize(where(name.ends("_score"), average(value)), by = col.region)
region q1_score q2_score
East 5.0 5.0
West 3.5 3.5

dplyr calls this across. Here it needed no verb and one word, because the selector was already there for pick and where already introduces a condition.

Every rule that applies to a value written out by hand applies to this one, because the grammar expands it before checking anything. Asking summarize for something that does not collapse a group is refused, and the message names the column it refused rather than the pattern.

collect(survey |> summarize(where(startsWith(name, "q"), value * 2)))
Error:
! 
illegal: `summarize` returns one row for each group, so `[q1_score]` has to be a value that spans the group. Wrap it: `total(...)`, `average(...)`, `first(...)`, or count the rows with `row_count()`
  |
2 |   then summarize where (name starts "q") as (value * 2)
  |                                              ^^^^^^^^^
try:
    collect(survey >> summarize(where(name.starts("q"), value * 2)))
except GodError as refusal:
    print(refusal)

illegal: `summarize` returns one row for each group, so `[q1_score]` has to be a value that spans the group. Wrap it: `total(...)`, `average(...)`, `first(...)`, or count the rows with `row_count()`
  |
2 |   then summarize where (name starts "q") as (value * 2)
  |                                              ^^^^^^^^^

You can see what it expanded to, which is worth doing the first few times. format shows the sentence you wrote; show_as shows the one the grammar settled on.

show_as(survey |> add(where(startsWith(name, "q"), value * 10)), "god")
survey
  then add [q1_score] as ([q1_score] * 10), [q2_score] as ([q2_score] * 10)
show_as(survey >> add(where(name.starts("q"), value * 10)), "god")
survey
  then add [q1_score] as ([q1_score] * 10), [q2_score] as ([q2_score] * 10)