library(knitr) knitr::opts_chunk$set( error = FALSE, tidy = FALSE, message = FALSE, comment = NA, fig.align = "center") library(GetoptLong)
Global option function such as options()
and par()
provides a way to
control global settings. Here the GlobalOptions package provides a more
general and controlable way to generate such functions, which can:
The most simple use is to generate an option function with default values by
callling setGlobalOptions()
or its short versoin set_opt()
:
library(GlobalOptions) opt = set_opt( a = 1, b = "text" )
The returned value opt
is an option function which can be used to get or set
options. Options in opt
can be accessed either by specifying as arguments or
by using the $
operator.
opt() opt("a") opt$a op = opt() op opt(a = 2, b = "new text") opt() opt$b = "" opt() opt(op) opt()
opt
generated by set_opt()
contains an argument RESET
which is used to
reset the options to the default:
opt(a = 2, b = "new text") opt(RESET = TRUE) opt()
Simply printing opt
gives a summary of all options.
opt
If option values are set as lists, more configurations can be customized.
There are two basic fields that are used to check the input option values:
opt = set_opt( a = list(.value = 1, .length = c(1, 3), .class = "numeric") )
In above code, .value
is the default value for the option a
. The length of
the value is controlled by .length
and the length should be either 1 or 3.
The class of the value should be numeric
. If the input value does not fit
these criterions, there will be an error. The value of .length
or .class
is a vector and the checking will be passed if one of the value fits user's
input.
opt(a = 1:2) # there will be error because the length is 2 opt(a = "text") # there will be error because the input is character
The value can be set as read-only by .read.only
field and modifying such
option will cause an error.
opt = set_opt( a = list(.value = 1, .read.only = TRUE) ) opt(a = 2) # there will be error because a is read-only
There is also a pre-defined argument READ.ONLY
in opt()
which controls
whether to return only the read-only options or not.
opt = set_opt( a = list(.value = 1, .read.only = TRUE), b = 2 ) opt(READ.ONLY = TRUE) opt(READ.ONLY = FALSE) opt(READ.ONLY = NULL) # default, to return both
More customized validation of the option values can be controlled by
.validate
field. The value of .validate
should be a function. The input of
the validation function is the input option value and the function should only
return a logical value.
a
should only between 0 and 10 in following example.
opt = set_opt( a = list(.value = 1, .validate = function(x) x > 0 && x < 10 ) ) opt(a = 20) # This will cause an error
.failed_msg
is used to configure the error message once validation is failed.
opt = set_opt( a = list(.value = 1, .validate = function(x) x > 0 && x < 10, .failed_msg = "'a' should be in (0, 10)." ) ) opt(a = 20) # This will cause an error
Filtering on the option values can be controlled by .filter
field. This is
useful when the input option value is not valid but it is not necessary to
throw errors. More proper way is to modify the value silently. For example,
there is an option to control whether to print messages or not and it should
be set to TRUE
or FALSE
. However, users may set some other type of values
such as NULL
or NA
. In this case, non-TRUE
values can be converted to
logical values by .filter
. Similar as .validate
, the input value for
filter function is the input option value, and it should return a filtered
option value.
opt = set_opt( verbose = list(.value = TRUE, .filter = function(x) { if(is.null(x)) { return(FALSE) } else if(is.na(x)) { return(FALSE) } else { return(x) } }) ) opt(verbose = FALSE); opt("verbose") opt(verbose = NA); opt("verbose") opt(verbose = NULL); opt("verbose")
Another example is when there is an option which controls four margin values
of a plot, the length of the value can either be 1, 2, or 4. With .filter
,
length can be normaliezd to 4 consistently.
opt = set_opt( margin = list(.value = c(1, 1, 1, 1), .length = c(1, 2, 4), .filter = function(x) { if(length(x) == 1) { return(rep(x, 4)) } else if(length(x) == 2) { return(rep(x, 2)) } else { return(x) } }) ) opt(margin = 2); opt("margin") opt(margin = c(2, 4)); opt("margin")
The input option value can be set dynamicly by setting it as a function. When
the option value is set as a function and class of the option is non-function,
it will be executed when querying the option. In the following example, the
prefix
option corresponds to the prefix of log messages. The returned option
value is the string after the execution of the input function.
opt = set_opt( prefix = "" ) opt(prefix = function() paste("[", Sys.time(), "] ", sep = " ")) opt("prefix") # or opt$prefix Sys.sleep(2) opt("prefix")
If the value of the option is a real function and users don't want to execute
it, just set .class
to contain function
, then the function will be treated
as a simple value.
opt = set_opt( test_fun = list(.value = function(x1, x2) t.test(x1, x2)$p.value, .class = "function") ) opt(test_fun = function(x1, x2) cor.test(x1, x2)$p.value) opt("test_fun") # or opt$test_fun
The self-defined function (i.e. value function, validation function or filter
function) is applied per-option independently. But sometimes we want to set
one option based on values of other options. In this case, we need a function
which can get other option values. .v()
can be used to access other option
values defined beforehand. .v("a")
can also be written as .v(a)
or .v$a
.
opt = set_opt( a = 1, b = function() 2 * .v$a ) opt("b") # or opt$b opt(a = 2) opt("b")
However, you can still overwrite option b
:
opt(a = 2, b = 3) # b was overwriiten and will not be 2*a opt()
.v
can also be used in .validate
and .filter
fields. In the second
example, sign of b
should be as same as sign of a
.
opt = set_opt( a = 1, b = list(.value = 0, .validate = function(x) { if(.v$a > 0) x > 0 else x < 0 }, .filter = function(x) { x + .v$a }, .failed_msg = "'b' should have same sign as 'a'.") ) opt(b = 1) opt("b") opt(a = 1, b = -1) # this should cause an error
The option funtion also has a LOCAL
argument which switches local mode and
global mode. When LOCAL
is set to TRUE
, a copy of current options is
generated and all queries are applied on the copy version. The local mode is
turned off when LOCAL
is explicitely specified to FALSE
.
opt = set_opt( a = 1 ) opt(LOCAL = TRUE) opt(a = 2) opt$a opt(LOCAL = FALSE) opt$a
Local mode will be automatically turned off when enrivonment changes. In
following example, local mode only works inside f1()
and f2()
functions
and the local copies are independent in f1()
and f2()
. Note when leaving
e.g. f1()
, the copy of the option is deleted.
opt = set_opt( a = 1 ) f1 = function() { opt(LOCAL = TRUE) opt(a = 2) return(opt$a) } f1() opt$a f2 = function() { opt(LOCAL = TRUE) opt(a = 4) return(opt$a) } f2() opt$a
If f1()
calls f2()
, f2()
will be in the same local mode as f1()
. In other word,
all children frames are in a same local mode if the parent frame is in local mode.
opt = set_opt( a = 1 ) f1 = function() { opt(LOCAL = TRUE) opt(a = 2) return(f2()) } f2 = function() { opt$a } f1() opt$a
It can be possible that several weeks later, developers have better names for
the options. They want to use the new option names but still do not want to
disable the old ones. In this case, .synonymous
field can be set to let the
new option and old option reference to a same internal option object (which
means all other configuration specified for this option is ignored). The change of
values of either one will also affect the companions correspondingly.
opt = set_opt( old = 1, new = list(.value = 1, .synonymous = "old") ) opt() opt$old = 2 opt() opt$new = 3 opt()
There is a .description
field for each option which is only used when
printing the summary of options. As shown before, simply entering the option
object gives a summary table for all options.
opt = set_opt( a = 1, b = "b", c = list(.value = letters[1:4], .class = "character", .description = "26 letters"), d = list(.value = c(0, 0), .class = "numeric", .validate = function(x) x[1]^2 + x[2]^2 <= 1, .failed_msg = "The point should be in the unit circle", .description = "start points in the unit circle"), e = list(.value = rnorm, .class = "function", .description = "distribution to generate random numbers and a very long long long long long long long long text") ) opt
Use dump_opt()
to get summary for each option.
dump_opt(opt, "a") dump_opt(opt, "d")
New options can be added after the option function is created by explicitely
specifying ADD = TRUE
:
opt = set_opt(a = 1) opt(b = 2, ADD = TRUE) opt
Note you cannot add new options by using $
(or more precisely $<-
)
operator because $
can only access options that have already been created.
opt$c = 3
Like using a complex configuration list when creating a new option in set_opt()
,
here you can also use configuration list with ADD = TRUE
.
opt(c = list(.value = "c", .class = "character"), ADD = TRUE) opt opt$c = 1
Of course you can put more than one options in opt()
when adding them.
Two additional fields may be helpful when developing packages. .visible
controls whether options are visible to users. The invisible option can only
be queried or modified by specifying its option name (just like you can
only open the door with the correct unique key). This would be helpful if
users want to put some secret options while do not want others to access. Is
this case, they can assign names with complex strings like
.__MY_PRIVATE_KEY__.
as their secret options and afterwards they can access
it with this special key.
opt = set_opt( a = list(.value = 1, .visible = FALSE), b = 2 ) opt() opt$a opt$a = 2 opt$a opt()
Another field .private
controls whether the option is only private to the
namespace (e.g. packages). If it is set to TRUE
, the option can only be
modified in the same namespace (or top environment) where the option function
is generated. E.g, if you are writing a package named foo and generating
an option function foo_opt()
, by setting the option with .private
to
TRUE
, the value for such options can only be modified inside foo package
while it is not permitted outside foo. At the same time, private options
become read-only options if querying outside foo package.
In following example, we manually modify the namespace where
set_opt()
is called in stats
package.
opt = set_opt( a = list(.value = 1, .private = TRUE) ) require(stats) ns = getNamespace("stats") environment(opt)$options$a$`__generated_namespace__` = ns
There will be error if trying to modify a
which is private in stats
namespace.
opt$a = 2
But you can still access it.
opt$a
The option object generated by set_opt()
is actually a function. It contains four arguments:
...
, RESET
, READ.ONLY
, LOCAL
, ADD
. If you want to put the option function
into a package, remember to document all the four arguments:
args(opt)
The order of validation when modifying an option value is .read.only
,
.private
, .length
, .class
, .validate
, .filter
, .length
, .class
.
Note validation on length and class of the option values will be applied again
after filtering.
Global options are stored in private environments. Each time when generating a option function, there will be new environments created. Thus global options will not conflict if they come from different option functions.
opt1 = set_opt( a = list(.value = 1) ) opt2 = set_opt( a = list(.value = 1) ) opt1$a = 2 opt1$a opt2$a
Note the option values can also be set as a list, so for the list containing configurations,
names of the field is started with a dot .
to be distinguished from the normal list.
opt = set_opt( list = list(a = 1, b = 2) ) opt() opt = set_opt( list = list(.value = list(a = 1, b = 2), .class = "list") ) opt() opt$list = 1 # this will cause an error
If you made a type of the field names when configurating the options (e.g. forgot to type the leading dot), there will be a warning and the whole configuration list is treated as a normal list for this option.
opt = set_opt( a = list(.value = 1, class = "numeric") # <- here it should be .class ) opt$a
The final and the most important thing is the validation by .class
,
.length
, .validate
, .filter
will not be applied on default values
because users who design their option functions should know whether the
default values are valid or not.
opt = set_opt( a = list(.value = -1, .validate = function(x) x > 0) ) opt$a
sessionInfo()
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.