-
Notifications
You must be signed in to change notification settings - Fork 1.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix #1359: shinyApp options argument ignored when passed to runApp #1483
Conversation
Another note: as for I think this is a bit unfortunate because we don't want to allow all shiny-options to be able to be passed through If the goal instead is that |
Hmm, so based on app.R line 373: print.shiny.appobj <- function(x, ...) {
opts <- x$options %OR% list()
opts <- opts[names(opts) %in%
c("port", "launch.browser", "host", "quiet", "display.mode")]
args <- c(list(x), opts)
do.call(runApp, args)
} I think I've found my answer: we want to be able to pass "port", "launch.browser", "host", "quiet" and "display.mode", right? I think I'll make that clearer in the documentation for
Too bad we can't change the PS: I get that |
So, in summary:
|
LGTM. |
@@ -551,6 +551,28 @@ runApp <- function(appDir=getwd(), | |||
handlerManager$clear() | |||
}, add = TRUE) | |||
|
|||
appParts <- as.shiny.appobj(appDir) | |||
|
|||
if (missing(port)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are these missing()
checks necessary? In general, it's best to avoid using missing()
, because it can make it hard to call the function programmatically.
@@ -551,6 +551,28 @@ runApp <- function(appDir=getwd(), | |||
handlerManager$clear() | |||
}, add = TRUE) | |||
|
|||
appParts <- as.shiny.appobj(appDir) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not 100% sure, but I don't think it's safe to move this line up here. This probably merits a discussion with @jcheng5.
fa8857d
to
2e95d19
Compare
41fc399
to
ee01d45
Compare
else val <- thisEnv[[arg]] | ||
|
||
# make sure that Ts and Fs are kept as logicals | ||
if (is.name(val) && val == "T") val <- TRUE |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do the strings "T"
and "F"
ever get passed in?
# I tried to make this as compact and intuitive as possible, | ||
# given that there are four distinct possibilities to check | ||
runOpts <- appParts$options | ||
passedArgs <- as.list(match.call())[-1] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the previous way, with the missing
calls, had clearer intent. The match.call()
and environment()
assignment makes things kind of confusing. You could do something like this, where f
is like runApp
; x
is like the app object; and, arg1
is an argument like port
:
f <- function(x, arg1 = 1) {
objValueOrDefault <- function(obj, name, default) {
if (name %in% names(obj))
obj[[name]]
else
default
}
if (missing(arg1)) arg1 <- objValueOrDefault(x, "arg1", arg1)
arg1
}
The drawback is that arg1
appears 4 times on one line, and that the if(missing())
part needs to be done for each argument. But it's easier to understand what it's doing.
It passes the following:
library(testthat)
expect_identical(f(list()), 1)
expect_identical(f(list(), 2), 2)
expect_identical(f(list(arg1 = 3)), 3)
expect_identical(f(list(arg1 = 3), 2), 2)
expect_identical(f(list(arg1 = NULL)), NULL)
expect_identical(f(list(arg1 = NULL), 2), 2)
The one tricky case is in the fifth test: the object has arg1=NULL
, and that NULL gets used. I think that behavior makes the most sense.
If we didn't do things that way (if it returned f
's default value for arg1
, which is 1), then f
could be simplified:
f <- function(x, arg1 = 1) {
`%OR2%` <- function(x, y) {
if (!is.null(x)) x
else y
}
if (missing(arg1)) arg1 <- x$arg1 %OR2% arg1
arg1
}
# | ||
# I tried to make this as compact and intuitive as possible, | ||
# given that there are four distinct possibilities to check | ||
runOpts <- appParts$options |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would the name appOpts
make more sense here? Because these are options from the app object (as opposed to those given to runApp
).
# I tried to make this as compact and intuitive as possible, | ||
# given that there are four distinct possibilities to check | ||
runOpts <- appParts$options | ||
assignVal <- function(arg, default) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function doesn't assign values, so maybe a name like defaultVal
would be better. Or maybe valueDefault
?
Fix #1359: shinyApp options argument ignored when passed to runApp.
The
options
arg toshinyApp()
now works as expected, accepting the following shiny options:port
launch.browser
host
There are other params that
runApp()
accepts thatshinyApp()
'soptions
argument does not yet accept (these areworkerId
,quiet
,display.mode
). It may be worth having a discussion about whether any (or all, for consistency) of these should be promoted to a shiny option...Here's the matrix of possibilities and the correspoding demo app:
shinyApp()
or inrunApp()
-- defaults kick in (same behavior as before this PR):shinyApp()
-- these should be followed (this did not work before this PR):runApp()
-- these should be followed (same behavior as before this PR):shinyApp()
and inrunApp()
-- options fromrunApp
win (same behavior as before this PR):