Comments (16)
It's possible, although it is a little tricky (maybe there's a better way).
BTW, what is dplyr calling on after a last pipe?
Anyway, here's a small boiled down example, maybe it can be prettier.
# Check whether inside a pipeline.
is_piped <- function()
{
parents <- lapply(sys.frames(), parent.env)
is_magrittr_env <-
vapply(parents, identical, logical(1), y = environment(`%>%`))
answer <- any(is_magrittr_env)
list(answer = answer,
env = if (answer) sys.frames()[[min(which(is_magrittr_env))]])
}
# This is just a jq placeholder.
# Here just squares the number
jq <- function(x)
{
print("jq Called!")
x^2
}
# Utility for hacking the effect into the pipeline
activate_jq_for_result <- function(env)
{
res <- NULL
jq_result <- function(v)
{
if (missing(v)) {
res
}
else {
res <<- v
res$value <<- jq(res$value)
}
}
makeActiveBinding("result", jq_result, env)
}
# If this function is used in a pipeline it will end up calling jq!
# other than activating jq, it is just an identity function.
f <- function(x)
{
piped <- is_piped()
if (isTRUE(piped$answer) &&
!exists('.jq_activated', envir = piped$env, inherits = FALSE)) {
piped$env$.jq_activated <- TRUE
activate_jq_for_result(piped$env)
}
x
}
10 %>% f %>% f %>% f
#> "jq Called!"
#> 100
f(f(f(10)))
#> 10
from jqr.
PS: This is activated if f
is anywhere in the pipeline, and only if it has not already been done.
It will be called on the final result, before returning from the pipe.
from jqr.
@smbache thanks very much, this looks like exactly what I need!
BTW, what is dplyr calling on after a last pipe?
I don't know. @hadley how do you know to execute commands in dplyr
after the last pipe?
from jqr.
no worries! BTW seems like a cool pkg, this!
from jqr.
It's in the print method in dplyr, but it doesn't run the whole query - it just runs enough to retrieve n rows. You have to use an explicit collect()
to get everything
from jqr.
@sckott let me know if the above is useful then, and if you need me to elaborate on what's going on. The names should help a bit, but they can do only so much...
from jqr.
Thanks @hadley !
@smbache will do, will try implementing soon
from jqr.
@smbache works great - implemented on dsl-pipe-fix
, devtools::install_github("ropensci/jqr", ref="dsl-pipe-fix")
e.g.,
'[0, false, [], {}, null, "hello"]' %>% types
#> ["number","boolean","array","object","null","string"]
'{"foo": 5, "bar": 7}' %>% keys
#> ["bar","foo"]
'{"foo": 5, "bar": 7}' %>% select(a = .foo)
#> {"a":5}
no need for the jq()
call at the end now :)
from jqr.
This is super cool! 💯
from jqr.
thx - almost to a CRAN 1st version
from jqr.
Great!! :)
from jqr.
Thanks so much @smbache and @hadley
from jqr.
Wondering if you need some of the functions to switch off the mechanism? Say peek
...
from jqr.
@smbache Yes, for peek
, combine
, and possibly others, Any ideas?
from jqr.
Sure. I have modified my original example to go both ways. I included example documentation, which you can use if you feel like it. I could have made a PR, but I'll let you do the dirty work ;-) Let me know if this is successful:
#' Information on Potential Pipeline
#'
#' This function figures out whether it is called from within a pipeline.
#' It does so by examining the parent evironment of the active system frames,
#' and whether any of these are the same as the enclosing environment of
#' \code{\%>\%}.
#'
#' @return A list with the values \code{is_piped} (logical) and \code{env}
#' (an environment reference). The former is \code{TRUE} if a pipeline is
#' identified as \code{FALSE} otherwise. The latter holds a reference to
#' the \code{\%>\%} frame where the pipeline is created and evaluated.
#'
#' @noRd
pipeline_info <- function()
{
parents <- lapply(sys.frames(), parent.env)
is_magrittr_env <-
vapply(parents, identical, logical(1), y = environment(`%>%`))
is_piped <- any(is_magrittr_env)
list(is_piped = is_piped,
env = if (is_piped) sys.frames()[[min(which(is_magrittr_env))]])
}
# This is just a jq placeholder.
# Here just squares the number
jq <- function(x)
{
print("jq Called!")
x^2
}
#' Toggle Auto Execution On or Off for Pipelines
#'
#' A call to \code{pipe_autoexec} allows a function to toggle auto execution of
#' \code{jq} on or off at the end of a pipeline.
#'
#' @param toggle logical: \code{TRUE} toggles auto execution on, \code{FALSE}
#' toggles auto execution off.
#'
#' @details Once auto execution is turned on the \code{result} identifier inside
#' the pipeline is bound to an "Active Binding". This will not be changed on
#' toggling auto execution off, but rather the function to be executed is
#' changed to \code{identity}.
#'
#' @noRd
pipe_autoexec <- function(toggle)
{
if (!identical(toggle, TRUE) && !identical(toggle, FALSE)) {
stop("Argument 'toggle' must be logical.")
}
info <- pipeline_info()
if (isTRUE(info[["is_piped"]])) {
pipeline_on_exit(info$env)
info$env$.jq_exitfun <- if (toggle) jq else identity
}
invisible()
}
#' Setup On-Exit Action for a Pipeline
#'
#' A call to \code{pipeline_on_exit} will setup the pipeline for auto execution by
#' making \code{result} inside \code{\%>\%} an active binding. The initial
#' call will register the \code{identity} function as the exit action,
#' but this can be changed to \code{jq} with a call to \code{pipe_autoexec}.
#' Subsequent calls to \code{pipeline_on_exit} has no effect.
#'
#' @param env A reference to the \code{\%>\%} environment, in which
#' \code{result} is to be bound.
#'
#' @noRd
pipeline_on_exit <- function(env)
{
# Only activate the first time; after this the binding is already active.
if (exists(".jq_exitfun", envir = env, inherits = FALSE, mode = "function")) {
return(invisible())
}
env$.jq_exitfun <- identity
res <- NULL
jq_result <- function(v)
{
if (missing(v)) {
res
}
else {
res <<- `$<-`(v, value, env$.jq_exitfun(v$value))
}
}
makeActiveBinding("result", jq_result, env)
}
# Example of function toggling auto execution on
f <- function(x)
{
pipe_autoexec(toggle = TRUE)
x
}
# Example of function toggling auto execution off
g <- function(x)
{
pipe_autoexec(toggle = FALSE)
x
}
10 %>% f %>% f %>% f
#> "jq Called"
#> 100
10 %>% f %>% f %>% g
#> 10
10 %>% f %>% g %>% f
#> "jq Called"
#> 100
f(f(f(10)))
#> 10
from jqr.
@smbache Awesome, thanks, will try this soon...
from jqr.
Related Issues (20)
- Look into ndjson-cli HOT 1
- make it clear/possible how to use modules
- Fix flags HOT 3
- Encoding with jqr::jq HOT 7
- Unhandled exception HOT 4
- sysreqs HOT 2
- Release 1.1.0 or note that build_object is only available if installed from GitHub HOT 6
- cran warning: strncpy HOT 1
- protection stack overflow errors on medium(?)-sized inputs HOT 6
- libjq was not found on Linux systems HOT 2
- NA handling HOT 4
- jq() paste bare numbers together HOT 8
- Error message suppressed and incorrect result returned HOT 4
- Better error message in check1() HOT 2
- jqr in CentOS8 : * rpm: jq-devel (Fedora, EPEL) EXist? HOT 3
- Passing --raw-output jq flag to enable json -> csv conversion to be "pushed down" to jq and enabling jqr to picking up nonjson results HOT 4
- Change to new cran checks badge URL HOT 1
- How to change values in the high level
- configure does not work correctly
- JSON field missing HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from jqr.