From 14d26481aa8530249482685138aed706064e7f8c Mon Sep 17 00:00:00 2001 From: Jordan Mark Barbone Date: Sat, 30 Dec 2023 23:58:32 -0500 Subject: [PATCH 01/31] Create super-arg.R (#73) --- R/super-arg.R | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 R/super-arg.R diff --git a/R/super-arg.R b/R/super-arg.R new file mode 100644 index 0000000..daf9eeb --- /dev/null +++ b/R/super-arg.R @@ -0,0 +1,49 @@ +scribe_super_help_arg <- function() { + new_arg( + aliases = "---help", + action = "flag", + default = FALSE, + n = 0, + info = "prints help information for {scribe} and quietly exits", + options = list(no = FALSE), + stop = "hard", + execute = function(self, ca) { + # TODO include more information + if (isTRUE(self$get_value())) { + cat( + "{scribe} v ", scribe_version, + "For more information, see https://jmbarbone.github.io/scribe/" + ) + return(exit()) + } + } + ) +} + +scribe_super_version_arg <- function() { + new_arg( + aliases = "---version", + action = "flag", + default = FALSE, + n = 0, + info = "prints the version of {scribe} and quietly exits", + options = list(no = FALSE), + stop = "hard", + execute = function(self, ca) { + if (isTRUE(self$get_value())) { + ca$version() + return(exit()) + } + + if (isFALSE(self$get_value())) { + # remove 'version' + values <- ca$get_values() + ca$field("values", values[-match("version", names(values))]) + } + } + ) +} + +scribe_version <- function() { + format(utils::packageVersion("scribe")) +} From a64df219c3607f164c9d9d5d4857949b220391a2 Mon Sep 17 00:00:00 2001 From: Jordan Mark Barbone Date: Sat, 30 Dec 2023 23:58:47 -0500 Subject: [PATCH 02/31] create scribeSuperArg object (#73) --- R/class-args.R | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/R/class-args.R b/R/class-args.R index ca4369b..75658af 100644 --- a/R/class-args.R +++ b/R/class-args.R @@ -171,3 +171,24 @@ scribeArg$methods( arg_is_resolved(.self) } ) + +scribeSuperArg <- methods::setRefClass( + "scribeSuperArg", + contains = "scribeArg", + methods = list( + initialize = function( + aliases = "", + ... + ) { + if (!all(startsWith(aliases, "---"))) { + stop("super args aliases must start with ---") + } + + arg_initialize( + self = .self, + aliases = aliases, + ... + ) + } + ) +) From ad1dce45187ad1177234e2f0545d087279fecb85 Mon Sep 17 00:00:00 2001 From: Jordan Mark Barbone Date: Sat, 30 Dec 2023 23:59:10 -0500 Subject: [PATCH 03/31] begin implementing super args (#73) --- R/class-command-args.R | 8 +++++--- R/command-args.R | 15 ++++++++++----- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/R/class-command-args.R b/R/class-command-args.R index 3565aea..124dc4c 100644 --- a/R/class-command-args.R +++ b/R/class-command-args.R @@ -96,7 +96,8 @@ scribeCommandArgs <- methods::setRefClass( # nolint: object_name_linter. comments = "character", resolved = "logical", working = "character", - stop = "character" + stop = "character", + super = "logical" ) ) @@ -104,7 +105,8 @@ scribeCommandArgs$methods( # creates the object initialize = function( input = "", - include = c("help", "version", NA_character_) + include = c("help", "version", NA_character_), + super = TRUE ) { "Initialize the \\link{scribeCommandArgs} object. The wrapper \\code{\\link[=command_args]{command_args()}} is recommended rather than @@ -116,7 +118,7 @@ scribeCommandArgs$methods( \\item{\\code{include}}{A character vector denoting which default \\link{scribeArg}s to include in \\code{args}} }" - ca_initialize(.self, input = input, include = include) + ca_initialize(.self, input = input, include = include, super = super) }, show = function(...) { diff --git a/R/command-args.R b/R/command-args.R index de1acef..43195a7 100644 --- a/R/command-args.R +++ b/R/command-args.R @@ -9,8 +9,10 @@ #' Otherwise the value of `x` is converted to a `character`. If `string` is #' not `NULL`, [scan()] will be used to split the value into a `character` #' vector. -#' @param include Special default arguments to included. See `$initialize()` -#' in [scribeCommandArgs] for more details. +#' @param include Special default arguments to included. See `$initialize()` in +#' [scribeCommandArgs] for more details. +#' @param super When `TRUE` the [scribeCommandArgs] object will be initialized +#' with standard _super_ arguments (e.g., `---help`, `---version`) #' @examples #' command_args() #' command_args(c("-a", 1, "-b", 2)) @@ -21,7 +23,8 @@ command_args <- function( x = NULL, include = getOption("scribe.include", c("help", "version", NA_character_)), - string = NULL + string = NULL, + super = TRUE ) { if (is.null(string)) { if (is.null(x)) { @@ -37,7 +40,7 @@ command_args <- function( x <- scan(text = string, what = "character", quiet = TRUE) } - scribeCommandArgs(input = x, include = include) + scribeCommandArgs(input = x, include = include, super = super) } # wrappers ---------------------------------------------------------------- @@ -45,7 +48,8 @@ command_args <- function( ca_initialize <- function( self, input = NULL, - include = c("help", "version", NA_character_) + include = c("help", "version", NA_character_), + super = TRUE ) { # default values self$initFields( @@ -75,6 +79,7 @@ ca_initialize <- function( self$add_argument(scribe_version_arg()) } + self$field("super", super) self$field("input", as.character(input) %||% character()) self$field("working", self$input) self$field("included", include) From c8a24afc223fe6fff63c186de9cc17fadc4d9d4a Mon Sep 17 00:00:00 2001 From: Jordan Mark Barbone Date: Sun, 31 Dec 2023 00:33:30 -0500 Subject: [PATCH 04/31] add checks for super (#73) --- R/arg.R | 1 + R/class-command-args.R | 3 ++- R/command-args.R | 29 +++++++++++++++++++++++++++++ R/super-arg.R | 36 ++++++++++++++---------------------- 4 files changed, 46 insertions(+), 23 deletions(-) diff --git a/R/arg.R b/R/arg.R index 7176737..25e3676 100644 --- a/R/arg.R +++ b/R/arg.R @@ -61,6 +61,7 @@ scribe_help_arg <- function() { } scribe_version_arg <- function() { + # TODO deprecate for ---version new_arg( aliases = "--version", action = "flag", diff --git a/R/class-command-args.R b/R/class-command-args.R index 124dc4c..36f4a47 100644 --- a/R/class-command-args.R +++ b/R/class-command-args.R @@ -97,7 +97,8 @@ scribeCommandArgs <- methods::setRefClass( # nolint: object_name_linter. resolved = "logical", working = "character", stop = "character", - super = "logical" + super = "logical", + supers = "character" ) ) diff --git a/R/command-args.R b/R/command-args.R index 43195a7..f6fbed6 100644 --- a/R/command-args.R +++ b/R/command-args.R @@ -210,6 +210,27 @@ ca_resolve <- function(self) { self$field("values", vector("list", length(arg_order))) names(self$values) <- arg_names[arg_order] + if (self$super) { + # NOTE if a third is added, this should probably be a function + for (i in seq_along(ca_get_working(self))) { + switch( + ca_get_working(self)[i], + "---help" = { + scribe_help_super() + self$field("stop", "hard") + self$field("supers", c(self$supers, "help")) + self$field("working", ca_get_working(self)[-i]) + }, + "---version" = { + scribe_version_super() + self$field("stop", "hard") + self$field("supers", c(self$supers, "version")) + self$field("working", ca_get_working(self)[-i]) + } + ) + } + } + for (arg in args[arg_order]) { self$set_values(arg$get_name(), arg_parse_value(arg, self)) } @@ -230,6 +251,14 @@ ca_resolve <- function(self) { ca_parse <- function(self) { self$resolve() + for (arg in self$supers) { + switch( + arg, + "help" = scribe_help_super()$execute(), + "version" = scribe_version_super()$execute() + ) + } + for (arg in self$get_args()) { ca_do_execute(self, arg) } diff --git a/R/super-arg.R b/R/super-arg.R index daf9eeb..6bfe4c5 100644 --- a/R/super-arg.R +++ b/R/super-arg.R @@ -1,4 +1,4 @@ -scribe_super_help_arg <- function() { +scribe_help_super <- function() { new_arg( aliases = "---help", action = "flag", @@ -7,20 +7,18 @@ scribe_super_help_arg <- function() { info = "prints help information for {scribe} and quietly exits", options = list(no = FALSE), stop = "hard", - execute = function(self, ca) { - # TODO include more information - if (isTRUE(self$get_value())) { - cat( - "{scribe} v ", scribe_version, - "For more information, see https://jmbarbone.github.io/scribe/" - ) - return(exit()) - } + execute = function() { + cat( + "{scribe} v ", format(scribe_version()), "\n", + "For more information, see https://jmbarbone.github.io/scribe/", + sep = + ) + exit() } ) } -scribe_super_version_arg <- function() { +scribe_version_super <- function() { new_arg( aliases = "---version", action = "flag", @@ -30,20 +28,14 @@ scribe_super_version_arg <- function() { options = list(no = FALSE), stop = "hard", execute = function(self, ca) { - if (isTRUE(self$get_value())) { - ca$version() - return(exit()) - } - - if (isFALSE(self$get_value())) { - # remove 'version' - values <- ca$get_values() - ca$field("values", values[-match("version", names(values))]) - } + cat(format(scribe_version()), "\n", sep = "") + exit() } ) } scribe_version <- function() { - format(utils::packageVersion("scribe")) + package_version( + asNamespace("scribe")[[".__NAMESPACE__."]][["spec"]][["version"]] + ) } From 0d363071fd8870c68abcb30d39e530dcbc02d8d7 Mon Sep 17 00:00:00 2001 From: Jordan Mark Barbone Date: Sun, 31 Dec 2023 00:33:34 -0500 Subject: [PATCH 05/31] redoc (#73) --- man/command_args.Rd | 10 +++++++--- man/scribeCommandArgs-class.Rd | 6 +++++- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/man/command_args.Rd b/man/command_args.Rd index 1a05277..0052d14 100644 --- a/man/command_args.Rd +++ b/man/command_args.Rd @@ -7,7 +7,8 @@ command_args( x = NULL, include = getOption("scribe.include", c("help", "version", NA_character_)), - string = NULL + string = NULL, + super = TRUE ) } \arguments{ @@ -18,8 +19,11 @@ Otherwise the value of \code{x} is converted to a \code{character}. If \code{st not \code{NULL}, \code{\link[=scan]{scan()}} will be used to split the value into a \code{character} vector.} -\item{include}{Special default arguments to included. See \verb{$initialize()} -in \link{scribeCommandArgs} for more details.} +\item{include}{Special default arguments to included. See \verb{$initialize()} in +\link{scribeCommandArgs} for more details.} + +\item{super}{When \code{TRUE} the \link{scribeCommandArgs} object will be initialized +with standard \emph{super} arguments (e.g., \code{---help}, \code{---version})} } \value{ A \link{scribeCommandArgs} object diff --git a/man/scribeCommandArgs-class.Rd b/man/scribeCommandArgs-class.Rd index 5715f79..134cac4 100644 --- a/man/scribeCommandArgs-class.Rd +++ b/man/scribeCommandArgs-class.Rd @@ -121,7 +121,11 @@ track parsing progress and is not meant to be accessed directly.} \item{\code{help()}}{Print the help information} -\item{\code{initialize(input = "", include = c("help", "version", NA_character_))}}{Initialize the \link{scribeCommandArgs} object. The wrapper +\item{\code{initialize( + input = "", + include = c("help", "version", NA_character_), + super = TRUE +)}}{Initialize the \link{scribeCommandArgs} object. The wrapper \code{\link[=command_args]{command_args()}} is recommended rather than calling this method directly. From beabb7aa663f80a6afb36a2e35ed8f4db319f9f2 Mon Sep 17 00:00:00 2001 From: Jordan Mark Barbone Date: Sun, 31 Dec 2023 18:00:26 -0500 Subject: [PATCH 06/31] deprecate --version (or the default one) (#73) --- R/arg.R | 1 + 1 file changed, 1 insertion(+) diff --git a/R/arg.R b/R/arg.R index 25e3676..c34d0e3 100644 --- a/R/arg.R +++ b/R/arg.R @@ -72,6 +72,7 @@ scribe_version_arg <- function() { stop = "hard", execute = function(self, ca) { if (isTRUE(self$get_value())) { + .Deprecated("For {scribe} package version, use ---version instead") ca$version() return(exit()) } From 282cabc264b061bf6c220948cafce7f184939134 Mon Sep 17 00:00:00 2001 From: Jordan Mark Barbone Date: Sun, 31 Dec 2023 18:00:37 -0500 Subject: [PATCH 07/31] add deprecated check (#73) --- tests/testthat/test-class-command-args.R | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/testthat/test-class-command-args.R b/tests/testthat/test-class-command-args.R index 3769fdc..f255184 100644 --- a/tests/testthat/test-class-command-args.R +++ b/tests/testthat/test-class-command-args.R @@ -332,7 +332,10 @@ test_that("versions", { ca$add_argument("--foo") ca$add_argument("--bar") ca$add_description("This does things") - expect_output((obj <- ca$parse())) + expect_warning( + expect_output((obj <- ca$parse())), + class = "deprecatedWarning" + ) exp <- list(version = TRUE) expect_identical(obj, exp) expect_output(ca$version()) From eec6047ae31aef07244ed1ae89302ca2a1efa2fe Mon Sep 17 00:00:00 2001 From: Jordan Mark Barbone Date: Sun, 31 Dec 2023 18:00:43 -0500 Subject: [PATCH 08/31] formatting (#73) --- R/super-arg.R | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/R/super-arg.R b/R/super-arg.R index 6bfe4c5..0003d27 100644 --- a/R/super-arg.R +++ b/R/super-arg.R @@ -1,3 +1,6 @@ +# default super helpers. though these may be the only super helpers. the +# object is not exported so these should only be used internally. + scribe_help_super <- function() { new_arg( aliases = "---help", @@ -9,7 +12,7 @@ scribe_help_super <- function() { stop = "hard", execute = function() { cat( - "{scribe} v ", format(scribe_version()), "\n", + "{scribe} v", format(scribe_version()), "\n", "For more information, see https://jmbarbone.github.io/scribe/", sep = ) From f338fd3c0cb500e77061a8f05f2b38dc9633ae2a Mon Sep 17 00:00:00 2001 From: Jordan Mark Barbone Date: Mon, 1 Jan 2024 23:30:11 -0500 Subject: [PATCH 09/31] Update super-arg.R (#73) --- R/super-arg.R | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/R/super-arg.R b/R/super-arg.R index 0003d27..9f3e65f 100644 --- a/R/super-arg.R +++ b/R/super-arg.R @@ -2,7 +2,7 @@ # object is not exported so these should only be used internally. scribe_help_super <- function() { - new_arg( + scribeSuperArg$new( aliases = "---help", action = "flag", default = FALSE, @@ -10,11 +10,15 @@ scribe_help_super <- function() { info = "prints help information for {scribe} and quietly exits", options = list(no = FALSE), stop = "hard", - execute = function() { + execute = function(self, ca) { + if (!self$get_value()) { + return() + } + cat( "{scribe} v", format(scribe_version()), "\n", "For more information, see https://jmbarbone.github.io/scribe/", - sep = + sep = "" ) exit() } @@ -22,7 +26,7 @@ scribe_help_super <- function() { } scribe_version_super <- function() { - new_arg( + scribeSuperArg$new( aliases = "---version", action = "flag", default = FALSE, @@ -31,6 +35,10 @@ scribe_version_super <- function() { options = list(no = FALSE), stop = "hard", execute = function(self, ca) { + if (!isTRUE(self$get_value())) { + return() + } + cat(format(scribe_version()), "\n", sep = "") exit() } From dbf9e65cbc8d5a6e04ca2b70c7232c03c2b0c392 Mon Sep 17 00:00:00 2001 From: Jordan Mark Barbone Date: Mon, 1 Jan 2024 23:30:43 -0500 Subject: [PATCH 10/31] include setting supers for command args (#73) --- R/class-command-args.R | 18 +++++---- R/command-args.R | 89 +++++++++++++++++++----------------------- 2 files changed, 51 insertions(+), 56 deletions(-) diff --git a/R/class-command-args.R b/R/class-command-args.R index 36f4a47..2d4283a 100644 --- a/R/class-command-args.R +++ b/R/class-command-args.R @@ -39,7 +39,7 @@ #' See also [command_args()] #' @field values `[list]`\cr A named `list` of values. Empty on initialization #' and populated during argument resolving. -#' @field args `[list]`\cr a List of [scribeArg]s +#' @field args `[list]`\cr A List of [scribeArg]s #' @field description `[character]`\cr Additional help information #' @field included `[character]`\cr Default [scribeArg]s to include #' @field examples `[character]`\cr Examples to print with help @@ -49,6 +49,7 @@ #' @field working `[character]`\cr A copy of `input`. Note: this is used to #' track parsing progress and is not meant to be accessed directly. #' @field stop `[character]`\cr Determines parsing +#' @field supers `[list]`\cr A list of `scribeSuperArgs`s #' #' @examples #' # command_args() is recommended over direct use of scribeCommandArgs$new() @@ -97,8 +98,7 @@ scribeCommandArgs <- methods::setRefClass( # nolint: object_name_linter. resolved = "logical", working = "character", stop = "character", - super = "logical", - supers = "character" + supers = "list" ) ) @@ -107,7 +107,7 @@ scribeCommandArgs$methods( initialize = function( input = "", include = c("help", "version", NA_character_), - super = TRUE + supers = include ) { "Initialize the \\link{scribeCommandArgs} object. The wrapper \\code{\\link[=command_args]{command_args()}} is recommended rather than @@ -118,8 +118,11 @@ scribeCommandArgs$methods( to parse} \\item{\\code{include}}{A character vector denoting which default \\link{scribeArg}s to include in \\code{args}} + \\item{\\code{supers}}{A character vector denoting which default + \\code{scribeSuperArg}s to include in \\code{supers} (i.e., arguments + called with `---` prefixes) }" - ca_initialize(.self, input = input, include = include, super = super) + ca_initialize(.self, input = input, include = include, supers = supers) }, show = function(...) { @@ -179,14 +182,15 @@ scribeCommandArgs$methods( ca_set_values(.self, i = i, value = value) }, - get_args = function(included = TRUE) { + get_args = function(included = TRUE, super = FALSE) { "Retrieve \\code{args} \\describe{ \\item{\\code{included}}{If \\code{TRUE} also returns included default \\link{scribeArg}s defined in \\code{$initialize()}} + \\item{\\code{super}}{If \\code{TRUE} also returns super args }" - ca_get_args(.self, included = included) + ca_get_args(.self, included = included, super = super) }, add_argument = function( diff --git a/R/command-args.R b/R/command-args.R index f6fbed6..a9419a9 100644 --- a/R/command-args.R +++ b/R/command-args.R @@ -24,7 +24,7 @@ command_args <- function( x = NULL, include = getOption("scribe.include", c("help", "version", NA_character_)), string = NULL, - super = TRUE + super = include ) { if (is.null(string)) { if (is.null(x)) { @@ -49,7 +49,7 @@ ca_initialize <- function( self, input = NULL, include = c("help", "version", NA_character_), - super = TRUE + supers = include ) { # default values self$initFields( @@ -66,6 +66,12 @@ ca_initialize <- function( several.ok = TRUE ) + supers <- match.arg( + as.character(supers), + c("help", "version", NA_character_), + several.ok = TRUE + ) + include <- include[!is.na(include)] if (!length(include)) { include <- character() @@ -79,7 +85,11 @@ ca_initialize <- function( self$add_argument(scribe_version_arg()) } - self$field("super", super) + self$field("supers", c( + if ("help" %in% supers) scribe_help_super(), + if ("version" %in% supers) scribe_version_super() + ) %||% list()) + self$field("input", as.character(input) %||% character()) self$field("working", self$input) self$field("included", include) @@ -183,7 +193,7 @@ ca_resolve <- function(self) { # dropped. Single value arguments are easier to match, should always have # that value present if arg is present. Non-multiple value arguments have at # least a limit to the number of values that can be found. - args <- self$get_args() + args <- self$get_args(super = TRUE) arg_order <- unique( c( @@ -192,45 +202,23 @@ ca_resolve <- function(self) { seq_along(args), # dots must always be parsed last wapply(args, function(i) i$positional), - wapply(args, function(i) i$action == "dots") + wapply(args, function(i) i$action == "dots"), + wapply(args, function(i) inherits(i, "scribeSuperArg")) ), fromLast = TRUE ) # move stops earlier - arg_order <- unique( - c( - wapply(args, function(i) i$stop == "hard"), - wapply(args, function(i) i$stop == "soft"), - arg_order - ) - ) + arg_order <- unique(c( + wapply(args, function(i) i$stop == "hard"), + wapply(args, function(i) i$stop == "soft"), + arg_order + )) arg_names <- vapply(args, function(arg) arg$get_name(), NA_character_) self$field("values", vector("list", length(arg_order))) names(self$values) <- arg_names[arg_order] - if (self$super) { - # NOTE if a third is added, this should probably be a function - for (i in seq_along(ca_get_working(self))) { - switch( - ca_get_working(self)[i], - "---help" = { - scribe_help_super() - self$field("stop", "hard") - self$field("supers", c(self$supers, "help")) - self$field("working", ca_get_working(self)[-i]) - }, - "---version" = { - scribe_version_super() - self$field("stop", "hard") - self$field("supers", c(self$supers, "version")) - self$field("working", ca_get_working(self)[-i]) - } - ) - } - } - for (arg in args[arg_order]) { self$set_values(arg$get_name(), arg_parse_value(arg, self)) } @@ -251,23 +239,20 @@ ca_resolve <- function(self) { ca_parse <- function(self) { self$resolve() - for (arg in self$supers) { - switch( - arg, - "help" = scribe_help_super()$execute(), - "version" = scribe_version_super()$execute() - ) - } - - for (arg in self$get_args()) { + for (arg in self$get_args(super = TRUE)) { ca_do_execute(self, arg) } # clean up names values <- self$get_values() + values <- values[!startsWith(names(values), "_")] regmatches(names(values), regexpr("^-+", names(values))) <- "" regmatches(names(values), gregexpr("-", names(values))) <- "_" - values + if (length(values)) { + values + } else { + list() + } } ca_get_input <- function(self) { @@ -296,14 +281,20 @@ ca_set_values <- function(self, i = NULL, value) { invisible(self) } -ca_get_args <- function(self, included = TRUE) { - if (included) { - return(self$args) +ca_get_args <- function(self, included = TRUE, super = FALSE) { + args <- self$args + + if (!included) { + nms <- sapply(args, function(arg) arg$get_name()) + ok <- match(nms, self$included, 0L) == 0L + args <- args[ok] + } + + if (super) { + args <- c(self$supers, args) } - nms <- sapply(self$args, function(arg) arg$get_name()) - ok <- match(nms, self$included, 0L) == 0L - self$args[ok] + args } ca_add_argument <- function( From 408a2a5fc4c6a2bea433a2cae74f2e52f37fd020 Mon Sep 17 00:00:00 2001 From: Jordan Mark Barbone Date: Mon, 1 Jan 2024 23:56:06 -0500 Subject: [PATCH 11/31] account for three dashes better (#73) --- R/arg.R | 59 ++++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 46 insertions(+), 13 deletions(-) diff --git a/R/arg.R b/R/arg.R index c34d0e3..60a0cc3 100644 --- a/R/arg.R +++ b/R/arg.R @@ -215,9 +215,17 @@ arg_initialize <- function( # nolint: cyclocomp_linter. positional <- !dash_args if (action == "flag" && isTRUE(options$no)) { - dash2 <- grep("^--", aliases) - if (dash2 && length(dash2)) { - aliases <- c(aliases, paste0("--no-", sub("^--", "", aliases[dash2]))) + dashes <- n_dashes(aliases) + ok <- dashes >= 2L + if (any(ok)) { + aliases <- c( + aliases, + paste0( + strrep("-", dashes[ok]), + "no-", + sub("^-{2,3}", "", aliases[ok]) + ) + ) } else if (positional) { aliases <- c(aliases, paste0("no-", aliases)) } @@ -253,18 +261,32 @@ arg_initialize <- function( # nolint: cyclocomp_linter. } arg_show <- function(self) { - value <- self$get_default() + value <- + if (self$is_resolved()) { + self$get_value() + } else { + self$get_default() + } + value <- if (is.null(value)) { "" + } else if (inherits(value, "scribe_empty_value")) { + "" + } else if (!nzchar(value)) { + "<>" } else { paste(vapply(value, format, NA_character_), collapse = " ") } aliases <- self$get_aliases() aliases <- to_string(aliases) - - print_line(sprintf("Argument [%s] : %s", aliases, value)) + print_line(sprintf( + "Argument [%s] %s: %s", + aliases, + if (self$is_resolved()) "R " else "", + value + )) invisible(self) } @@ -342,7 +364,12 @@ arg_get_name <- function(self, clean = TRUE) { nm <- aliases[n] if (clean) { - nm <- sub("^--?", "", nm) + nm <- + if (startsWith(nm, "---")) { + paste0("_", substr(nm, 4L, nchar(nm))) + } else { + sub("^-{1,2}", "", nm) + } } nm @@ -379,7 +406,7 @@ arg_parse_value <- function(self, ca) { # nolint: cyclocomp_linter. if (is_arg(self$default)) { self$default$get_value() } else { - self$default + self$get_default() } if (ca$stop == "soft") { @@ -444,9 +471,9 @@ arg_parse_value <- function(self, ca) { # nolint: cyclocomp_linter. }, list = { m <- m + seq.int(0L, self$n) - value <- ca_get_working(ca)[m[-off]] + value <- ca_get_working(ca, m[-off]) - if (self$positional && is.na(value)) { + if (self$positional && !isFALSE(is.na(value))) { default <- TRUE value <- self$get_default() } @@ -454,8 +481,8 @@ arg_parse_value <- function(self, ca) { # nolint: cyclocomp_linter. ca_remove_working(ca, m) }, flag = { - value <- !grepl("^--?no-", ca_get_working(ca)[m + off]) - ca_remove_working(ca, m) + value <- !grepl("^-{2,3}no-", ca_get_working(ca, m + off)) + ca_remove_working(ca, m + off) } ) @@ -481,7 +508,7 @@ is_arg <- function(x) { methods::is(x, "scribeArg") } -ARG_PAT <- "^-[a-z]$|^--[a-z]+$|^--[a-z](+[-]?[a-z]+)+$" # nolint: object_name_linter, line_length_linter. +ARG_PAT <- "^-[a-z]$|^---?[a-z]+$|^--?[a-z](+[-]?[a-z]+)+$" # nolint: object_name_linter, line_length_linter. arg_actions <- function() { c("default", "list", "flag", "dots") @@ -490,3 +517,9 @@ arg_actions <- function() { scribe_empty_value <- function() { structure(list(), class = c("scribe_empty_value")) } + +n_dashes <- function(x) { + n <- attr(regexpr("^-+", x), "match.length") + n[n == -1] <- 0L + n +} From a2d20f8acf66e336f20b83c4ba7c2290806f544f Mon Sep 17 00:00:00 2001 From: Jordan Mark Barbone Date: Mon, 1 Jan 2024 23:56:13 -0500 Subject: [PATCH 12/31] formatting (#73) --- tests/testthat/test-class-args.R | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tests/testthat/test-class-args.R b/tests/testthat/test-class-args.R index 710995f..a9fad55 100644 --- a/tests/testthat/test-class-args.R +++ b/tests/testthat/test-class-args.R @@ -56,10 +56,7 @@ test_that("help() [#16]", { exp <- c("...", "help text") expect_identical(obj, exp) - obj <- new_arg( - c("...", "dots"), - info = "more help here" - )$get_help() + obj <- new_arg(c("...", "dots"), info = "more help here")$get_help() exp <- c("...", "dots: more help here") expect_identical(obj, exp) From 1dd4142d0c415840c07376e8ea2a63fd40ddeeda Mon Sep 17 00:00:00 2001 From: Jordan Mark Barbone Date: Mon, 1 Jan 2024 23:56:27 -0500 Subject: [PATCH 13/31] redoc (#73) --- man/command_args.Rd | 2 +- man/scribeCommandArgs-class.Rd | 12 +++++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/man/command_args.Rd b/man/command_args.Rd index 0052d14..b3f406b 100644 --- a/man/command_args.Rd +++ b/man/command_args.Rd @@ -8,7 +8,7 @@ command_args( x = NULL, include = getOption("scribe.include", c("help", "version", NA_character_)), string = NULL, - super = TRUE + super = include ) } \arguments{ diff --git a/man/scribeCommandArgs-class.Rd b/man/scribeCommandArgs-class.Rd index 134cac4..9298bc9 100644 --- a/man/scribeCommandArgs-class.Rd +++ b/man/scribeCommandArgs-class.Rd @@ -48,7 +48,7 @@ See also \code{\link[=command_args]{command_args()}}} \item{\code{values}}{\verb{[list]}\cr A named \code{list} of values. Empty on initialization and populated during argument resolving.} -\item{\code{args}}{\verb{[list]}\cr a List of \link{scribeArg}s} +\item{\code{args}}{\verb{[list]}\cr A List of \link{scribeArg}s} \item{\code{description}}{\verb{[character]}\cr Additional help information} @@ -65,6 +65,8 @@ and populated during argument resolving.} track parsing progress and is not meant to be accessed directly.} \item{\code{stop}}{\verb{[character]}\cr Determines parsing} + +\item{\code{supers}}{\verb{[list]}\cr A list of \code{scribeSuperArgs}s} }} \section{Methods}{ @@ -104,11 +106,12 @@ track parsing progress and is not meant to be accessed directly.} \item{\code{prefix}}{An optional prefix for the example} }} -\item{\code{get_args(included = TRUE)}}{Retrieve \code{args} +\item{\code{get_args(included = TRUE, super = FALSE)}}{Retrieve \code{args} \describe{ \item{\code{included}}{If \code{TRUE} also returns included default \link{scribeArg}s defined in \code{$initialize()}} + \item{\code{super}}{If \code{TRUE} also returns super args }} \item{\code{get_description()}}{Retrieve \code{description}} @@ -124,7 +127,7 @@ track parsing progress and is not meant to be accessed directly.} \item{\code{initialize( input = "", include = c("help", "version", NA_character_), - super = TRUE + supers = include )}}{Initialize the \link{scribeCommandArgs} object. The wrapper \code{\link[=command_args]{command_args()}} is recommended rather than calling this method directly. @@ -134,6 +137,9 @@ track parsing progress and is not meant to be accessed directly.} to parse} \item{\code{include}}{A character vector denoting which default \link{scribeArg}s to include in \code{args}} + \item{\code{supers}}{A character vector denoting which default + \code{scribeSuperArg}s to include in \code{supers} (i.e., arguments + called with `---` prefixes) }} \item{\code{parse()}}{Return a named \code{list} of parsed values of from each \link{scribeArg} From 559ff0564c615b31889b5cbe2e811da9dd73b2e5 Mon Sep 17 00:00:00 2001 From: Jordan Mark Barbone Date: Sun, 21 Jan 2024 23:58:23 -0500 Subject: [PATCH 14/31] add super tests (#73) --- tests/testthat/test-class-command-args.R | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/testthat/test-class-command-args.R b/tests/testthat/test-class-command-args.R index f255184..8129899 100644 --- a/tests/testthat/test-class-command-args.R +++ b/tests/testthat/test-class-command-args.R @@ -413,3 +413,18 @@ test_that("snapshots", { expect_snapshot(ca$show()) expect_snapshot(ca$help()) }) + +test_that("snapshots - empty values", { + ca <- command_args(string = "--bar zero") + ca$add_argument("--foo", stop = "hard") + ca$add_argument("--bar", action = "list", default = character(), stop = "hard") + ca$add_argument("--fizz", action = "list", default = character()) + ca$resolve() + ca$get_args() + expect_snapshot(ca$get_args()) +}) + +test_that("snapshots - super args", { + expect_snapshot(command_args("---help")$parse()) + expect_snapshot(command_args("---version")$parse()) +}) From 9b1aba4a4f992af06a6422d5f7f5a42055041108 Mon Sep 17 00:00:00 2001 From: Jordan Mark Barbone Date: Sun, 21 Jan 2024 23:58:34 -0500 Subject: [PATCH 15/31] update snaps (#73) --- tests/testthat/_snaps/class-args.md | 14 ++++++++ tests/testthat/_snaps/class-command-args.md | 38 +++++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/tests/testthat/_snaps/class-args.md b/tests/testthat/_snaps/class-args.md index 8bf2d61..dc868b2 100644 --- a/tests/testthat/_snaps/class-args.md +++ b/tests/testthat/_snaps/class-args.md @@ -12,3 +12,17 @@ Output [...] help text +--- + + Code + arg$show() + Output + Argument [foo] : 0 + +--- + + Code + arg$show() + Output + Argument [foo] R : 1 + diff --git a/tests/testthat/_snaps/class-command-args.md b/tests/testthat/_snaps/class-command-args.md index 0cc9e57..24841cd 100644 --- a/tests/testthat/_snaps/class-command-args.md +++ b/tests/testthat/_snaps/class-command-args.md @@ -168,3 +168,41 @@ --help prints this and quietly exits --version prints the version of {scribe} and quietly exits +# snapshots - empty values + + Code + ca$get_args() + Output + [[1]] + Argument [--help] R : FALSE + + [[2]] + Argument [--version] R : FALSE + + [[3]] + Argument [--foo] R : + + [[4]] + Argument [--bar] R : zero + + [[5]] + Argument [--fizz] R : + + +# snapshots - super args + + Code + command_args("---help")$parse() + Output + {scribe} v0.3.0.9000 + For more information, see https://jmbarbone.github.io/scribe/ + named list() + +--- + + Code + command_args("---version")$parse() + Output + 0.3.0.9000 + named list() + From 6d96e90b1e3758b8b90cd59138e0ccb5f0d5bb74 Mon Sep 17 00:00:00 2001 From: Jordan Mark Barbone Date: Sun, 21 Jan 2024 23:59:06 -0500 Subject: [PATCH 16/31] Update test-class-args.R (#73) --- tests/testthat/test-class-args.R | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/testthat/test-class-args.R b/tests/testthat/test-class-args.R index a9fad55..afba539 100644 --- a/tests/testthat/test-class-args.R +++ b/tests/testthat/test-class-args.R @@ -171,4 +171,13 @@ test_that("snapshots", { expect_output(arg$help()) expect_snapshot(arg$show()) expect_snapshot(arg$help()) + + ca <- command_args(1) + arg <- new_arg("foo", default = 0) + ca$add_argument(arg) + expect_snapshot(arg$show()) + + # now resolve the argument so we have a different print + ca$resolve() + expect_snapshot(arg$show()) }) From d2f3c83ecec701bcb127203809a73ab249d13d8b Mon Sep 17 00:00:00 2001 From: Jordan Mark Barbone Date: Mon, 22 Jan 2024 00:05:05 -0500 Subject: [PATCH 17/31] add option for all values (#73) --- R/class-command-args.R | 10 +++++++--- R/command-args.R | 14 +++++++------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/R/class-command-args.R b/R/class-command-args.R index 2d4283a..394f65b 100644 --- a/R/class-command-args.R +++ b/R/class-command-args.R @@ -167,9 +167,13 @@ scribeCommandArgs$methods( ca_set_input(.self, value = value) }, - get_values = function() { - "Retrieve \\code{values}" - ca_get_values(.self) + get_values = function(all = FALSE) { + "Retrieve \\code{values} + \\describe{ + \\item{\\code{{all}}}{If \\code{TRUE} returns all values, including empty + ones} + }" + ca_get_values(.self, all = all) }, set_values = function(i = TRUE, value) { diff --git a/R/command-args.R b/R/command-args.R index a9419a9..3ebeeb0 100644 --- a/R/command-args.R +++ b/R/command-args.R @@ -97,7 +97,7 @@ ca_initialize <- function( invisible(self) } -ca_show <- function(self, ...) { +ca_show <- function(self, all_values = FALSE, ...) { print_line("Initial call: ", to_string(self$get_input())) if (!self$resolved) { @@ -248,11 +248,7 @@ ca_parse <- function(self) { values <- values[!startsWith(names(values), "_")] regmatches(names(values), regexpr("^-+", names(values))) <- "" regmatches(names(values), gregexpr("-", names(values))) <- "_" - if (length(values)) { - values - } else { - list() - } + values } ca_get_input <- function(self) { @@ -266,7 +262,11 @@ ca_set_input <- function(self, value) { invisible(self) } -ca_get_values <- function(self) { +ca_get_values <- function(self, all = FALSE) { + if (all) { + return(self$values) + } + Filter(function(x) !inherits(x, "scribe_empty_value"), self$values) } From 63d6d8c5bdd297d503485e8302abf16218caa253 Mon Sep 17 00:00:00 2001 From: Jordan Mark Barbone Date: Mon, 22 Jan 2024 00:05:16 -0500 Subject: [PATCH 18/31] clean up docs (#73) --- DESCRIPTION | 3 ++- R/arg.R | 32 ++++++++++++++++++++++---------- R/class-command-args.R | 9 ++++----- R/super-arg.R | 2 +- man/scribeCommandArgs-class.Rd | 15 +++++++++------ 5 files changed, 38 insertions(+), 23 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index e04b156..27d80b0 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -16,7 +16,7 @@ License: MIT + file LICENSE Encoding: UTF-8 Language: en-US Roxygen: list(markdown = TRUE) -RoxygenNote: 7.2.3 +RoxygenNote: 7.3.0 Depends: R (>= 3.6) Imports: @@ -33,3 +33,4 @@ Config/testthat/edition: 3 VignetteBuilder: knitr URL: https://jmbarbone.github.io/scribe/, https://github.com/jmbarbone/scribe BugReports: https://github.com/jmbarbone/scribe/issues +Config/testthat/parallel: true diff --git a/R/arg.R b/R/arg.R index 60a0cc3..7ca1d67 100644 --- a/R/arg.R +++ b/R/arg.R @@ -183,9 +183,20 @@ arg_initialize <- function( # nolint: cyclocomp_linter. } ) - if (!is.null(default)) { - if (!identical(value_convert(default, to = convert), default)) { - stop("default value doesn't convert to itself", call. = FALSE) + if (!is.null(default) && !is.null(convert)) { + attempt <- value_convert(default, to = convert) + if (!identical(attempt, default)) { + stop( + "default value doesn't convert to itself:\n", + "default:\n", + utils::capture.output(utils::str(default)), + "\nconverted:\n", + utils::capture.output(utils::str(attempt)), + "\n\n", + "to disable this check, set `convert = scribe_conert(\"none\")`", + " or review the `convert` argument in `?scribe_arg`", + call. = FALSE + ) } } @@ -273,8 +284,9 @@ arg_show <- function(self) { "" } else if (inherits(value, "scribe_empty_value")) { "" - } else if (!nzchar(value)) { - "<>" + # is this even needed? + # } else if (length(value) == 0 || !nzchar(value)) { + # "<>" } else { paste(vapply(value, format, NA_character_), collapse = " ") } @@ -282,11 +294,11 @@ arg_show <- function(self) { aliases <- self$get_aliases() aliases <- to_string(aliases) print_line(sprintf( - "Argument [%s] %s: %s", - aliases, - if (self$is_resolved()) "R " else "", - value - )) + "Argument [%s] %s: %s", + aliases, + if (self$is_resolved()) "R " else "", + value + )) invisible(self) } diff --git a/R/class-command-args.R b/R/class-command-args.R index 394f65b..80f0343 100644 --- a/R/class-command-args.R +++ b/R/class-command-args.R @@ -120,7 +120,7 @@ scribeCommandArgs$methods( \\link{scribeArg}s to include in \\code{args}} \\item{\\code{supers}}{A character vector denoting which default \\code{scribeSuperArg}s to include in \\code{supers} (i.e., arguments - called with `---` prefixes) + called with `---` prefixes)} }" ca_initialize(.self, input = input, include = include, supers = supers) }, @@ -161,9 +161,8 @@ scribeCommandArgs$methods( "Set \\code{input}. Note: when called, \\code{resolved} is (re)set to \\code{FALSE} and values need to be parsed again. - \\describe{ - \\item{\\code{value}}{Value to set} - }" + \\describe{\\item{\\code{value}}{Value to set}} + " ca_set_input(.self, value = value) }, @@ -192,7 +191,7 @@ scribeCommandArgs$methods( \\describe{ \\item{\\code{included}}{If \\code{TRUE} also returns included default \\link{scribeArg}s defined in \\code{$initialize()}} - \\item{\\code{super}}{If \\code{TRUE} also returns super args + \\item{\\code{super}}{If \\code{TRUE} also returns super args} }" ca_get_args(.self, included = included, super = super) }, diff --git a/R/super-arg.R b/R/super-arg.R index 9f3e65f..b4437ff 100644 --- a/R/super-arg.R +++ b/R/super-arg.R @@ -17,7 +17,7 @@ scribe_help_super <- function() { cat( "{scribe} v", format(scribe_version()), "\n", - "For more information, see https://jmbarbone.github.io/scribe/", + "For more information, see https://jmbarbone.github.io/scribe/\n", sep = "" ) exit() diff --git a/man/scribeCommandArgs-class.Rd b/man/scribeCommandArgs-class.Rd index 9298bc9..23917f0 100644 --- a/man/scribeCommandArgs-class.Rd +++ b/man/scribeCommandArgs-class.Rd @@ -111,7 +111,7 @@ track parsing progress and is not meant to be accessed directly.} \describe{ \item{\code{included}}{If \code{TRUE} also returns included default \link{scribeArg}s defined in \code{$initialize()}} - \item{\code{super}}{If \code{TRUE} also returns super args + \item{\code{super}}{If \code{TRUE} also returns super args} }} \item{\code{get_description()}}{Retrieve \code{description}} @@ -120,7 +120,11 @@ track parsing progress and is not meant to be accessed directly.} \item{\code{get_input()}}{Retrieve \code{input}} -\item{\code{get_values()}}{Retrieve \code{values}} +\item{\code{get_values(all = FALSE)}}{Retrieve \code{values} +\describe{ + \item{\code{{all}}}{If \code{TRUE} returns all values, including empty + ones} +}} \item{\code{help()}}{Print the help information} @@ -139,7 +143,7 @@ track parsing progress and is not meant to be accessed directly.} \link{scribeArg}s to include in \code{args}} \item{\code{supers}}{A character vector denoting which default \code{scribeSuperArg}s to include in \code{supers} (i.e., arguments - called with `---` prefixes) + called with `---` prefixes)} }} \item{\code{parse()}}{Return a named \code{list} of parsed values of from each \link{scribeArg} @@ -166,9 +170,8 @@ is called prior to $parse()} \item{\code{set_input(value)}}{Set \code{input}. Note: when called, \code{resolved} is (re)set to \code{FALSE} and values need to be parsed again. - \describe{ - \item{\code{value}}{Value to set} - }} + \describe{\item{\code{value}}{Value to set}} + } \item{\code{set_values(i = TRUE, value)}}{Set \code{values} From debc599b12eca0d38cf02e309a50ed71311475fa Mon Sep 17 00:00:00 2001 From: Jordan Mark Barbone Date: Mon, 22 Jan 2024 00:20:32 -0500 Subject: [PATCH 19/31] formatting, mostly (#73) --- R/arg.R | 29 +++++++++--------- R/class-args.R | 38 ++++++++++++------------ R/class-command-args.R | 3 +- R/scribe-package.R | 4 +-- R/utils.R | 4 +-- tests/testthat/test-class-command-args.R | 4 +-- 6 files changed, 41 insertions(+), 41 deletions(-) diff --git a/R/arg.R b/R/arg.R index 7ca1d67..f9064ea 100644 --- a/R/arg.R +++ b/R/arg.R @@ -88,17 +88,18 @@ scribe_version_arg <- function() { # wrappers ---------------------------------------------------------------- -arg_initialize <- function( # nolint: cyclocomp_linter. - self, - aliases = "", - action = arg_actions(), - default = NULL, - convert = scribe_convert(), - n = NA_integer_, - info = NA_character_, - options = list(), - stop = c("none", "hard", "soft"), - execute = invisible +# nolint next: cyclocomp_linter. +arg_initialize <- function( + self, + aliases = "", + action = arg_actions(), + default = NULL, + convert = scribe_convert(), + n = NA_integer_, + info = NA_character_, + options = list(), + stop = c("none", "hard", "soft"), + execute = invisible ) { action <- match.arg(action, arg_actions()) info <- info %||% NA_character_ @@ -284,9 +285,6 @@ arg_show <- function(self) { "" } else if (inherits(value, "scribe_empty_value")) { "" - # is this even needed? - # } else if (length(value) == 0 || !nzchar(value)) { - # "<>" } else { paste(vapply(value, format, NA_character_), collapse = " ") } @@ -413,7 +411,8 @@ arg_is_resolved <- function(self) { # internal ---------------------------------------------------------------- -arg_parse_value <- function(self, ca) { # nolint: cyclocomp_linter. +# nolint next: cyclocomp_linter. +arg_parse_value <- function(self, ca) { default <- if (is_arg(self$default)) { self$default$get_value() diff --git a/R/class-args.R b/R/class-args.R index 75658af..f6a58b9 100644 --- a/R/class-args.R +++ b/R/class-args.R @@ -72,7 +72,8 @@ #' new_arg("...", info = "list of values") # defaults when alias is "..." #' @family scribe #' @export -scribeArg <- methods::setRefClass( # nolint: object_name_linter. +# nolint next: object_name_linter. +scribeArg <- methods::setRefClass( "scribeArg", fields = list( aliases = "character", @@ -172,23 +173,22 @@ scribeArg$methods( } ) -scribeSuperArg <- methods::setRefClass( - "scribeSuperArg", - contains = "scribeArg", - methods = list( - initialize = function( - aliases = "", - ... - ) { - if (!all(startsWith(aliases, "---"))) { - stop("super args aliases must start with ---") - } - - arg_initialize( - self = .self, - aliases = aliases, - ... - ) +# nolint next: object_name_linter. +scribeSuperArg <- methods::setRefClass("scribeSuperArg", contains = "scribeArg") + +scribeSuperArg$methods( + initialize = function( + aliases = "", + ... + ) { + if (!all(startsWith(aliases, "---"))) { + stop("super args aliases must start with ---") } - ) + + arg_initialize( + self = .self, + aliases = aliases, + ... + ) + } ) diff --git a/R/class-command-args.R b/R/class-command-args.R index 80f0343..9384436 100644 --- a/R/class-command-args.R +++ b/R/class-command-args.R @@ -85,7 +85,8 @@ #' do.call(my_function, args) #' @family scribe #' @export -scribeCommandArgs <- methods::setRefClass( # nolint: object_name_linter. +# nolint next: object_name_linter. +scribeCommandArgs <- methods::setRefClass( "scribeCommandArgs", fields = list( input = "character", diff --git a/R/scribe-package.R b/R/scribe-package.R index 3fa0487..9cc47b6 100644 --- a/R/scribe-package.R +++ b/R/scribe-package.R @@ -15,8 +15,8 @@ NULL # nolint end: line_length_linter. - -op.scribe <- list( # nolint: object_name_linter. +# nolint next: object_name_linter. +op.scribe <- list( scribe.flag.no = TRUE, scribe.interactive = NULL, scribe.include = c("help", "version") diff --git a/R/utils.R b/R/utils.R index b53594a..258bc37 100644 --- a/R/utils.R +++ b/R/utils.R @@ -54,10 +54,10 @@ exit <- function(force = !getOption("scribe.interactive", interactive())) { invisible() } -# nolint start: object_name_linter. +# nolint next: object_name_linter. wapply <- function(x, FUN, ...) { + # nolint next: object_name_linter. FUN <- match.fun(FUN) - # nolint end: object_name_linter. fun <- function(x, ...) isTRUE(FUN(x, ...)) which(do.call(vapply, list(X = x, FUN = fun, FUN.VALUE = NA))) } diff --git a/tests/testthat/test-class-command-args.R b/tests/testthat/test-class-command-args.R index 8129899..bcc8c58 100644 --- a/tests/testthat/test-class-command-args.R +++ b/tests/testthat/test-class-command-args.R @@ -416,8 +416,8 @@ test_that("snapshots", { test_that("snapshots - empty values", { ca <- command_args(string = "--bar zero") - ca$add_argument("--foo", stop = "hard") - ca$add_argument("--bar", action = "list", default = character(), stop = "hard") + ca$add_argument("--foo", stop = TRUE) + ca$add_argument("--bar", action = "list", default = character(), stop = TRUE) ca$add_argument("--fizz", action = "list", default = character()) ca$resolve() ca$get_args() From 03d405de2f07702e951431a9a405e5abe748585d Mon Sep 17 00:00:00 2001 From: Jordan Mark Barbone Date: Tue, 23 Jan 2024 23:59:35 -0500 Subject: [PATCH 20/31] get values (#73) --- R/command-args.R | 25 +++++++++++++++++-------- R/super-arg.R | 24 ++++++++++-------------- 2 files changed, 27 insertions(+), 22 deletions(-) diff --git a/R/command-args.R b/R/command-args.R index 3ebeeb0..6c72564 100644 --- a/R/command-args.R +++ b/R/command-args.R @@ -244,11 +244,10 @@ ca_parse <- function(self) { } # clean up names - values <- self$get_values() - values <- values[!startsWith(names(values), "_")] - regmatches(names(values), regexpr("^-+", names(values))) <- "" - regmatches(names(values), gregexpr("-", names(values))) <- "_" - values + res <- self$get_values(super = FALSE) + regmatches(names(res), regexpr("^-+", names(res))) <- "" + regmatches(names(res), gregexpr("-", names(res))) <- "_" + res } ca_get_input <- function(self) { @@ -262,12 +261,22 @@ ca_set_input <- function(self, value) { invisible(self) } -ca_get_values <- function(self, all = FALSE) { +ca_get_values <- function(self, all = FALSE, super = FALSE) { + values <- self$values + + if (is.null(values) || length(values) == 0) { + return(list()) + } + + if (!super) { + values <- values[!startsWith(names(values), "_")] + } + if (all) { - return(self$values) + return(values) } - Filter(function(x) !inherits(x, "scribe_empty_value"), self$values) + Filter(function(x) !inherits(x, "scribe_empty_value"), values) } ca_set_values <- function(self, i = NULL, value) { diff --git a/R/super-arg.R b/R/super-arg.R index b4437ff..c8e5f25 100644 --- a/R/super-arg.R +++ b/R/super-arg.R @@ -11,16 +11,14 @@ scribe_help_super <- function() { options = list(no = FALSE), stop = "hard", execute = function(self, ca) { - if (!self$get_value()) { - return() + if (isTRUE(self$get_value())) { + cat( + "{scribe} v", format(scribe_version()), "\n", + "For more information, see https://jmbarbone.github.io/scribe/\n", + sep = "" + ) + exit() } - - cat( - "{scribe} v", format(scribe_version()), "\n", - "For more information, see https://jmbarbone.github.io/scribe/\n", - sep = "" - ) - exit() } ) } @@ -35,12 +33,10 @@ scribe_version_super <- function() { options = list(no = FALSE), stop = "hard", execute = function(self, ca) { - if (!isTRUE(self$get_value())) { - return() + if (isTRUE(self$get_value())) { + cat(format(scribe_version()), "\n", sep = "") + exit() } - - cat(format(scribe_version()), "\n", sep = "") - exit() } ) } From abc9fef784d6b137838d2c3df91e93343a30d4b6 Mon Sep 17 00:00:00 2001 From: Jordan Mark Barbone Date: Tue, 23 Jan 2024 23:59:52 -0500 Subject: [PATCH 21/31] improve get values and redoc (#73) --- R/class-command-args.R | 5 +++-- man/scribeCommandArgs-class.Rd | 3 ++- scribe.Rproj | 6 +++--- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/R/class-command-args.R b/R/class-command-args.R index 9384436..de58278 100644 --- a/R/class-command-args.R +++ b/R/class-command-args.R @@ -167,13 +167,14 @@ scribeCommandArgs$methods( ca_set_input(.self, value = value) }, - get_values = function(all = FALSE) { + get_values = function(all = FALSE, super = FALSE) { "Retrieve \\code{values} \\describe{ \\item{\\code{{all}}}{If \\code{TRUE} returns all values, including empty ones} + \\item{\\code{super}}{If \\code{TRUE} also returns values from super args} }" - ca_get_values(.self, all = all) + ca_get_values(.self, all = all, super = super) }, set_values = function(i = TRUE, value) { diff --git a/man/scribeCommandArgs-class.Rd b/man/scribeCommandArgs-class.Rd index 23917f0..e455017 100644 --- a/man/scribeCommandArgs-class.Rd +++ b/man/scribeCommandArgs-class.Rd @@ -120,10 +120,11 @@ track parsing progress and is not meant to be accessed directly.} \item{\code{get_input()}}{Retrieve \code{input}} -\item{\code{get_values(all = FALSE)}}{Retrieve \code{values} +\item{\code{get_values(all = FALSE, super = FALSE)}}{Retrieve \code{values} \describe{ \item{\code{{all}}}{If \code{TRUE} returns all values, including empty ones} + \item{\code{super}}{If \code{TRUE} also returns values from super args} }} \item{\code{help()}}{Print the help information} diff --git a/scribe.Rproj b/scribe.Rproj index 0a45aae..7a1f5b9 100644 --- a/scribe.Rproj +++ b/scribe.Rproj @@ -1,8 +1,8 @@ Version: 1.0 -RestoreWorkspace: Default -SaveWorkspace: Default -AlwaysSaveHistory: Default +RestoreWorkspace: No +SaveWorkspace: No +AlwaysSaveHistory: No EnableCodeIndexing: Yes UseSpacesForTab: Yes From 11b2d1c1de3fc274e909b49797200cb71bd243fa Mon Sep 17 00:00:00 2001 From: Jordan Mark Barbone Date: Wed, 24 Jan 2024 23:56:00 -0500 Subject: [PATCH 22/31] Create test-class-super-args.R (#73) --- tests/testthat/test-class-super-args.R | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 tests/testthat/test-class-super-args.R diff --git a/tests/testthat/test-class-super-args.R b/tests/testthat/test-class-super-args.R new file mode 100644 index 0000000..0c8457f --- /dev/null +++ b/tests/testthat/test-class-super-args.R @@ -0,0 +1,14 @@ +withr::local_options(list(scribe.interactive = TRUE)) + +test_that("---version, ---help", { + expect_output(command_args("---version")$parse()) + expect_output(command_args("---help")$parse()) +}) + +test_that("errors", { + expect_error( + scribeSuperArg$new("foo"), + regexp = "super args aliases must start with ---", + fixed = TRUE + ) +}) From c2fc2e4c3e3105dc55146c2e25b257c8cf1547dd Mon Sep 17 00:00:00 2001 From: Jordan Mark Barbone Date: Wed, 24 Jan 2024 23:56:13 -0500 Subject: [PATCH 23/31] add more tests for new values (#73) --- tests/testthat/test-class-command-args.R | 40 ++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/tests/testthat/test-class-command-args.R b/tests/testthat/test-class-command-args.R index bcc8c58..4271d60 100644 --- a/tests/testthat/test-class-command-args.R +++ b/tests/testthat/test-class-command-args.R @@ -161,6 +161,46 @@ test_that("$add_argument(arg) [#45]", { expect_identical(obj, exp) }) +test_that("$get_values() [#73]", { + # #73 includes super args + ca <- command_args(1L) + ca$add_argument("foo") + ca$add_argument("bar") + obj <- ca$get_values() + exp <- list() + expect_identical(obj, exp) + + ca$resolve() + + obj <- ca$get_values() + exp <- list(foo = 1L, bar = NULL) + expect_identical(obj, exp) + obj <- ca$get_values() + + obj <- ca$get_values(included = TRUE) + exp <- list(help = FALSE, version = FALSE, foo = 1L, bar = NULL) + expect_identical(obj, exp) + + obj <- ca$get_values(super = TRUE) + exp <- list(`_help` = FALSE, `_version` = FALSE, foo = 1L, bar = NULL) + expect_identical(obj, exp) +}) + +test_that("$get_values(empty)", { + ca <- command_args("--stop") + ca$add_argument("foo") + ca$add_argument("--stop", stop = TRUE) + ca$resolve() + + obj <- ca$get_values() + exp <- list(stop = NA) + expect_identical(obj, exp) + + obj <- ca$get_values(empty = TRUE) + exp <- list(foo = scribe_empty_value(), stop = NA) + expect_identical(obj, exp) +}) + test_that("args are returned in original order [#25]", { ca <- command_args( c("-b", "one", "-c", "two", "-a", "three", "foo", "bar"), From 00e7abd21558703e845e61c9616d941a12d720cd Mon Sep 17 00:00:00 2001 From: Jordan Mark Barbone Date: Thu, 25 Jan 2024 23:35:07 -0500 Subject: [PATCH 24/31] remove attempts to remove 'help' and 'version' from values (#73) --- R/arg.R | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/R/arg.R b/R/arg.R index f9064ea..aaed608 100644 --- a/R/arg.R +++ b/R/arg.R @@ -50,12 +50,6 @@ scribe_help_arg <- function() { ca$help() return(exit()) } - - if (isFALSE(self$get_value())) { - # remove 'help' - values <- ca$get_values() - ca$field("values", values[-match("help", names(values))]) - } } ) } @@ -76,12 +70,6 @@ scribe_version_arg <- function() { ca$version() return(exit()) } - - if (isFALSE(self$get_value())) { - # remove 'version' - values <- ca$get_values() - ca$field("values", values[-match("version", names(values))]) - } } ) } From 7fa12c3e8db105c0b752ba5448872c4a2d0d85b2 Mon Sep 17 00:00:00 2001 From: Jordan Mark Barbone Date: Thu, 25 Jan 2024 23:35:21 -0500 Subject: [PATCH 25/31] update tests with new get_values() (#73) --- tests/testthat/test-class-command-args.R | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/testthat/test-class-command-args.R b/tests/testthat/test-class-command-args.R index 4271d60..143550f 100644 --- a/tests/testthat/test-class-command-args.R +++ b/tests/testthat/test-class-command-args.R @@ -298,7 +298,7 @@ test_that("--help has early stop", { ca <- command_args("--help") ca$add_argument("-v") ca$add_argument("-f") - exp <- list(help = TRUE) + exp <- structure(list(), names = character()) expect_output(obj <- try(ca$parse())) expect_identical(obj, exp) }) @@ -376,7 +376,7 @@ test_that("versions", { expect_output((obj <- ca$parse())), class = "deprecatedWarning" ) - exp <- list(version = TRUE) + exp <- structure(list(), names = character()) expect_identical(obj, exp) expect_output(ca$version()) }) From 9870b4fedc71b30251ddd381dad76dbf7efbe948 Mon Sep 17 00:00:00 2001 From: Jordan Mark Barbone Date: Thu, 25 Jan 2024 23:35:26 -0500 Subject: [PATCH 26/31] clean up (#73) --- R/class-command-args.R | 13 +++++++++---- R/command-args.R | 31 +++++++++++++++++++------------ man/scribeCommandArgs-class.Rd | 7 ++++--- 3 files changed, 32 insertions(+), 19 deletions(-) diff --git a/R/class-command-args.R b/R/class-command-args.R index de58278..978013c 100644 --- a/R/class-command-args.R +++ b/R/class-command-args.R @@ -167,14 +167,19 @@ scribeCommandArgs$methods( ca_set_input(.self, value = value) }, - get_values = function(all = FALSE, super = FALSE) { + get_values = function( + empty = FALSE, + super = FALSE, + included = FALSE + ) { "Retrieve \\code{values} \\describe{ - \\item{\\code{{all}}}{If \\code{TRUE} returns all values, including empty - ones} + \\item{\\code{{empty}}}{If \\code{TRUE} returns empty values, too} \\item{\\code{super}}{If \\code{TRUE} also returns values from super args} + \\item{\\code{included}}{If \\code{TRUE} also returns included default + \\link{scribeArg}s defined in \\code{$initialize()}} }" - ca_get_values(.self, all = all, super = super) + ca_get_values(.self, empty = empty, super = super, included = included) }, set_values = function(i = TRUE, value) { diff --git a/R/command-args.R b/R/command-args.R index 6c72564..9a9f43f 100644 --- a/R/command-args.R +++ b/R/command-args.R @@ -193,7 +193,7 @@ ca_resolve <- function(self) { # dropped. Single value arguments are easier to match, should always have # that value present if arg is present. Non-multiple value arguments have at # least a limit to the number of values that can be found. - args <- self$get_args(super = TRUE) + args <- self$get_args(included = TRUE, super = TRUE) arg_order <- unique( c( @@ -216,8 +216,10 @@ ca_resolve <- function(self) { )) arg_names <- vapply(args, function(arg) arg$get_name(), NA_character_) - self$field("values", vector("list", length(arg_order))) - names(self$values) <- arg_names[arg_order] + self$field("values", structure( + vector("list", length(arg_order)), + names = arg_names[arg_order] + )) for (arg in args[arg_order]) { self$set_values(arg$get_name(), arg_parse_value(arg, self)) @@ -239,12 +241,12 @@ ca_resolve <- function(self) { ca_parse <- function(self) { self$resolve() - for (arg in self$get_args(super = TRUE)) { + for (arg in self$get_args(super = TRUE, included = TRUE)) { ca_do_execute(self, arg) } # clean up names - res <- self$get_values(super = FALSE) + res <- self$get_values() regmatches(names(res), regexpr("^-+", names(res))) <- "" regmatches(names(res), gregexpr("-", names(res))) <- "_" res @@ -261,22 +263,27 @@ ca_set_input <- function(self, value) { invisible(self) } -ca_get_values <- function(self, all = FALSE, super = FALSE) { +ca_get_values <- function( + self, + empty = FALSE, + super = FALSE, + included = FALSE +) { values <- self$values - if (is.null(values) || length(values) == 0) { - return(list()) + if (!included && !is.null(names(values))) { + values <- values[setdiff(names(values), self$included)] } - if (!super) { + if (!super && !is.null(names(values))) { values <- values[!startsWith(names(values), "_")] } - if (all) { - return(values) + if (!empty) { + values <- values[vapply(values, Negate(inherits), NA, "scribe_empty_value")] } - Filter(function(x) !inherits(x, "scribe_empty_value"), values) + values } ca_set_values <- function(self, i = NULL, value) { diff --git a/man/scribeCommandArgs-class.Rd b/man/scribeCommandArgs-class.Rd index e455017..7901b0a 100644 --- a/man/scribeCommandArgs-class.Rd +++ b/man/scribeCommandArgs-class.Rd @@ -120,11 +120,12 @@ track parsing progress and is not meant to be accessed directly.} \item{\code{get_input()}}{Retrieve \code{input}} -\item{\code{get_values(all = FALSE, super = FALSE)}}{Retrieve \code{values} +\item{\code{get_values(empty = FALSE, super = FALSE, included = FALSE)}}{Retrieve \code{values} \describe{ - \item{\code{{all}}}{If \code{TRUE} returns all values, including empty - ones} + \item{\code{{empty}}}{If \code{TRUE} returns empty values, too} \item{\code{super}}{If \code{TRUE} also returns values from super args} + \item{\code{included}}{If \code{TRUE} also returns included default + \link{scribeArg}s defined in \code{$initialize()}} }} \item{\code{help()}}{Print the help information} From 6321dc8fb7f4a255bc605f9b6bd2b300f7e202ee Mon Sep 17 00:00:00 2001 From: Jordan Mark Barbone Date: Fri, 26 Jan 2024 23:59:18 -0500 Subject: [PATCH 27/31] Update NEWS.md (#73) --- NEWS.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/NEWS.md b/NEWS.md index 4c39679..a31eca1 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,7 +1,14 @@ # scribe (development version) -- improves `ca$help()` printing +- `---help`, `---version` _super_ arguments (`scribeSuperArg` objects) are now included with `scribeCommandArgs` + - `command_args(super = included)` added + - internal `scribe_version_arg()` function (used with `command_args(include = "verison")` and called with `--version`) is now deprecated. Using `---version` now returns the version of `{scribe}` + - internal `scribe_help_super()` now available via `---help` and returns information about `{scribe}` + `ca$get_args(super = TRUE)` returns `scribeSuerArg`s +- `ca$help()` printing has been improved - corrects issue with `ca$parse()` +- `ca$get_values(empty, super, included)` added to prevent filtering of specific argument types and values +- internal linting improvements # scribe 0.3.0 From 92b58abb8d30b3b5d532e858de74b81ade569ca0 Mon Sep 17 00:00:00 2001 From: Jordan Mark Barbone Date: Sun, 28 Jan 2024 23:27:53 -0500 Subject: [PATCH 28/31] clean up help text (#73) --- R/arg.R | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/R/arg.R b/R/arg.R index aaed608..31c4f91 100644 --- a/R/arg.R +++ b/R/arg.R @@ -182,7 +182,8 @@ arg_initialize <- function( "\nconverted:\n", utils::capture.output(utils::str(attempt)), "\n\n", - "to disable this check, set `convert = scribe_conert(\"none\")`", + "to disable this check, use", + " `new_arg(convert = scribe_convert(\"none\"))`", " or review the `convert` argument in `?scribe_arg`", call. = FALSE ) From 37f0f2d971f44561525e58dacd3aad2e87e4b031 Mon Sep 17 00:00:00 2001 From: Jordan Mark Barbone Date: Sun, 28 Jan 2024 23:29:10 -0500 Subject: [PATCH 29/31] only check for included when pulling values (#73) --- R/command-args.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/command-args.R b/R/command-args.R index 9a9f43f..c9b136e 100644 --- a/R/command-args.R +++ b/R/command-args.R @@ -271,7 +271,7 @@ ca_get_values <- function( ) { values <- self$values - if (!included && !is.null(names(values))) { + if (!included) { values <- values[setdiff(names(values), self$included)] } From 3c62f04ea533910d723e0c88fd778fa000316810 Mon Sep 17 00:00:00 2001 From: Jordan Mark Barbone Date: Sun, 28 Jan 2024 23:31:35 -0500 Subject: [PATCH 30/31] bump version (#73) --- DESCRIPTION | 2 +- tests/testthat/_snaps/class-command-args.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 27d80b0..ece63c5 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: scribe Title: Command Argument Parsing -Version: 0.3.0.9000 +Version: 0.3.0.9001 Authors@R: person( given = "Jordan Mark", diff --git a/tests/testthat/_snaps/class-command-args.md b/tests/testthat/_snaps/class-command-args.md index 24841cd..eea3eee 100644 --- a/tests/testthat/_snaps/class-command-args.md +++ b/tests/testthat/_snaps/class-command-args.md @@ -194,7 +194,7 @@ Code command_args("---help")$parse() Output - {scribe} v0.3.0.9000 + {scribe} v0.3.0.9001 For more information, see https://jmbarbone.github.io/scribe/ named list() @@ -203,6 +203,6 @@ Code command_args("---version")$parse() Output - 0.3.0.9000 + 0.3.0.9001 named list() From e00146a99ff6c60cd54c353fecd6af46ea343362 Mon Sep 17 00:00:00 2001 From: Jordan Mark Barbone Date: Sun, 28 Jan 2024 23:31:50 -0500 Subject: [PATCH 31/31] update NEWS (#73) --- NEWS.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/NEWS.md b/NEWS.md index a31eca1..c247dd8 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,6 +1,9 @@ # scribe (development version) -- `---help`, `---version` _super_ arguments (`scribeSuperArg` objects) are now included with `scribeCommandArgs` +- `---help`, `---version` _super_ arguments (`scribeSuperArg` objects) are now included with `scribeCommandArgs`. +This are objects that (by default) can be called within any `scribeCommandArgs` and intended to hold additional information about the `{scribe}` package. +These are not meant to be user accessible. + - `scribeCommandArgs` gain a new `field`, `supers`; a list of `scribeSuperArg` objects - `command_args(super = included)` added - internal `scribe_version_arg()` function (used with `command_args(include = "verison")` and called with `--version`) is now deprecated. Using `---version` now returns the version of `{scribe}` - internal `scribe_help_super()` now available via `---help` and returns information about `{scribe}` @@ -9,6 +12,9 @@ - corrects issue with `ca$parse()` - `ca$get_values(empty, super, included)` added to prevent filtering of specific argument types and values - internal linting improvements +- `new_arg()` now throws a more helpful error when _value doesn't convert to itself_ +- `arg$show()` now denotes if the argument is resolves by display an `"R"` before the value +- `arg$show()` now prints values of class `"scribe_empty_value"` as `` # scribe 0.3.0