When using pipleines in Shiny I find myself wanting to create conditional steps in the pipeline. I want to alter the steps of the pipleine based on the user input. I came up with one idea but I wonder if anyone else has had this problem and if there is an elegant way to handle it.

Thanks for these very helpful suggestions!
Would you mind breaking down what is happening in this line of code?

alistaire:

rlang::eval_tidy(rlang::quo_squash(quo(data %>% !!enquo(call))))

I have a basic understanding of what enquo, quo, and !! do but this line makes my head spin a bit. Is there an easy way you think about all this quoting and unquoting? I just learned that R code can be thought of as a tree. Maybe that would help.

Also I don't fully understand your last comment about API structure. Do you just mean that this API would fail when the call argument was not a function that expected the data as the first argument (i.e. call was not a pipe-able function)?

Working from the inside out, call is some code to pipe the previous result into, so enquo quotes it, keeping it as a language object (a quosure) so R doesn't try to evaluate it as soon as it's referred to. This is placed in another quosure made by quo that pipes the data piped in into the call, unquoted with !! to substitute the code supplied for the variable call.

The unquoting leaves you with a nested quosure, e.g. for the example

<quosure>
expr: ^data %>% (^filter(hp == 245))
env: 0x122dcbb18

quo_squash flattens the structure into a single expression

data %>% filter(hp == 245)

which eval_tidy then runs.

ablack3:

Also I don’t fully understand your last comment about API structure. Do you just mean that this API would fail when the call argument was not a function that expected the data as the first argument (i.e. call was not a pipe-able function)?

Braces and specifying where to send the data with . will work, but yes, the call must work when the preceding data is piped in. My point was more that it's a little weird to write filterwithout a pipe immediately preceding it or the data specified inside. It's probably the only way a piped conjunction function could be expected to work, but it is upping the API complexity.