diff --git a/DESCRIPTION b/DESCRIPTION index d20c188..0715f40 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -2,7 +2,7 @@ Encoding: UTF-8 Package: optparse Type: Package Title: Command Line Option Parser -Version: 1.8.0-4 +Version: 1.8.0-5 Authors@R: c(person("Trevor L.", "Davis", role=c("aut", "cre"), email="trevor.l.davis@gmail.com", comment = c(ORCID = "0000-0001-6341-4639")), diff --git a/NEWS.md b/NEWS.md index 38ea671..754fc75 100644 --- a/NEWS.md +++ b/NEWS.md @@ -4,16 +4,18 @@ optparse 1.8.0 (development) New features ------------ -* `make_option()` (and `add_option()`) now support the following new actions (#22): +* `add_option()` (and `make_option()`) now support the following new actions (#22): + `action = "append"` which appends each occurrence's value to `default`. + `action = "append_const"` which appends `const` to `default` each time the flag is seen. + `action = "count"`, which counts the number of times a flag is seen and adds it to `default` (treated as `0L` if not supplied). Returns `NULL` if the flag is never seen and no `default` was supplied. + `action = "store_const"` which stores `const` when the flag is seen. -* `make_option()` (and `add_option()`) now support a `const` parameter (intended for new actions `"append_const"` and `"store_const"`). +* `add_option()` (and `make_option()`) now support a `const` parameter (intended for new actions `"append_const"` and `"store_const"`). -* `make_option()` (and `add_option()`) now support a `required` argument. +* `add_option()` (and `make_option()`) now allow non-letter characters in short flags (e.g., `-1`) and at the beginning of long flags (e.g., `--1flag`), following Python's `optparse` convention. However long and short flags may not contain `=` or whitespace (or begin with hyphens). + +* `add_option()` (and `make_option()`) now support a `required` argument. If `TRUE`, `parse_args()` will throw an error if the option is not provided on the command line (#17). Bug fixes and minor improvements diff --git a/R/optparse.R b/R/optparse.R index 4355e88..2cb35c3 100644 --- a/R/optparse.R +++ b/R/optparse.R @@ -44,7 +44,6 @@ #' @slot formatter A function that [print_help()] will use to print out after #' the options statement. Default is [IndentedHelpFormatter()]. This #' package also provides the builtin formatter [TitledHelpFormatter()]. -#' @author Trevor Davis. #' @seealso [OptionParserOption] #' @import methods #' @exportClass OptionParser @@ -97,9 +96,9 @@ setMethod("options<-", "OptionParser", function(x, value) { #' Class to hold information about command-line options #' #' @slot short_flag String of the desired short flag -#' comprised of the \dQuote{-} followed by a letter. -#' @slot long_flag String of the desired long flag comprised of \dQuote{--} -#' followed by a letter and then a sequence of alphanumeric characters. +#' comprised of the `-` followed by a single non-dash character (but not `=` or a whitespace character). +#' @slot long_flag String of the desired long flag comprised of `--` +#' followed by a non-dash character and then (optionally) more characters (but not any `=` or whitespace characters). #' @slot action `r ro_action` #' @slot type `r ro_type` #' @slot dest `r ro_dest` @@ -160,7 +159,6 @@ OptionParserOption <- setClass( #' Default is [IndentedHelpFormatter()]. #' The other builtin formatter provided by this package is [TitledHelpFormatter()]. #' @return An instance of the `OptionParser` class. -#' @author Trevor Davis. #' #' @seealso [parse_args()] [make_option()] [add_option()] #' @references Python's `optparse` library, which inspired this package, @@ -219,9 +217,9 @@ OptionParser <- function( #' @rdname add_make_option #' @param object An instance of the `OptionParser` class #' @param opt_str A character vector containing the string of the desired long -#' flag comprised of \dQuote{--} followed by a letter and then a sequence of -#' alphanumeric characters and optionally a string of the desired short flag -#' comprised of the \dQuote{-} followed by a letter. +#' flag comprised of `--` followed by a non-dash character (and optionally more characters), and +#' optionally a string of the desired short flag comprised of the +#' `-` followed by a single non-dash character. We don't allow `=` or whitespace characters in flags. #' @param action `r ro_action` #' @param type `r ro_type` #' @param dest `r ro_dest` @@ -234,7 +232,6 @@ OptionParser <- function( #' @param callback_args `r ro_callback_args` #' @return Both [make_option()] and [add_option()] return instances of #' class `OptionParserOption`. -#' @author Trevor Davis. #' #' @seealso [parse_args()] [OptionParser()] #' @references Python's `optparse` library, which inspires this package, @@ -278,18 +275,34 @@ make_option <- function( action <- ifelse(is.null(action), ifelse(is.null(callback), "store", "callback"), action) # flags - short_flag <- opt_str[grepl("^-[[:alpha:]]", opt_str)] + short_flag <- opt_str[grepl("^-[^-]", opt_str)] if (length(short_flag) == 0) { short_flag <- NA_character_ } else { if (nchar(short_flag) > 2) { - stop(paste("Short flag", short_flag, "must only be a '-' and a single letter")) + stop(paste( + "Short flag", + short_flag, + "must only be a '-' and a single non-dash character" + )) + } + if (grepl("[[:space:]]", short_flag)) { + stop(paste("Short flag", short_flag, "must not contain whitespace")) + } + if (grepl("=", short_flag, fixed = TRUE)) { + stop(paste("Short flag", short_flag, "must not contain '='")) } } - long_flag <- opt_str[grepl("^--[[:alpha:]]", opt_str)] + long_flag <- opt_str[grepl("^--[^-]", opt_str)] if (length(long_flag) == 0) { stop("We require a long flag option") } + if (grepl("=", long_flag, fixed = TRUE)) { + stop(paste("Long flag", long_flag, "must not contain '='")) + } + if (grepl("[[:space:]]", long_flag)) { + stop(paste("Long flag", long_flag, "must not contain whitespace")) + } # type if (is.null(type)) { @@ -414,7 +427,6 @@ add_option <- function( #' @param object A `OptionParser` instance. #' @return [print_help()] uses the `cat` function to print out a usage #' message. It returns `invisible(NULL)`. -#' @author Trevor Davis. #' #' @seealso [parse_args()] [OptionParser()] #' @references Python's `optparse` library, which inspired this package, @@ -560,7 +572,6 @@ as_string <- function(default) { #' Jonas Zimmermann for bug report; Miroslav Posta for bug reports; #' Stefan Seemayer for bug report and patch; #' Kirill \enc{Müller}{Muller} for patches; Steve Humburg for patch. -#' @author Trevor Davis. #' #' @seealso [OptionParser()] [print_help()] #' @references Python's `optparse` library, which inspired this package, diff --git a/man/OptionParser-class.Rd b/man/OptionParser-class.Rd index c397f73..2c3f9cd 100644 --- a/man/OptionParser-class.Rd +++ b/man/OptionParser-class.Rd @@ -34,6 +34,3 @@ package also provides the builtin formatter \code{\link[=TitledHelpFormatter]{Ti \seealso{ \link{OptionParserOption} } -\author{ -Trevor Davis. -} diff --git a/man/OptionParser.Rd b/man/OptionParser.Rd index 99d059f..cb207f2 100644 --- a/man/OptionParser.Rd +++ b/man/OptionParser.Rd @@ -59,6 +59,3 @@ is described here: \url{https://docs.python.org/3/library/optparse.html} \seealso{ \code{\link[=parse_args]{parse_args()}} \code{\link[=make_option]{make_option()}} \code{\link[=add_option]{add_option()}} } -\author{ -Trevor Davis. -} diff --git a/man/OptionParserOption-class.Rd b/man/OptionParserOption-class.Rd index 603a803..a0e7785 100644 --- a/man/OptionParserOption-class.Rd +++ b/man/OptionParserOption-class.Rd @@ -12,10 +12,10 @@ Class to hold information about command-line options \describe{ \item{\code{short_flag}}{String of the desired short flag -comprised of the \dQuote{-} followed by a letter.} +comprised of the \code{-} followed by a single non-dash character (but not \code{=} or a whitespace character).} -\item{\code{long_flag}}{String of the desired long flag comprised of \dQuote{--} -followed by a letter and then a sequence of alphanumeric characters.} +\item{\code{long_flag}}{String of the desired long flag comprised of \verb{--} +followed by a non-dash character and then (optionally) more characters (but not any \code{=} or whitespace characters).} \item{\code{action}}{A character string describing the action \code{optparse} should take when it encounters an option. One of: \itemize{ diff --git a/man/add_make_option.Rd b/man/add_make_option.Rd index 98d8f14..ebc7704 100644 --- a/man/add_make_option.Rd +++ b/man/add_make_option.Rd @@ -37,9 +37,9 @@ add_option( } \arguments{ \item{opt_str}{A character vector containing the string of the desired long -flag comprised of \dQuote{--} followed by a letter and then a sequence of -alphanumeric characters and optionally a string of the desired short flag -comprised of the \dQuote{-} followed by a letter.} +flag comprised of \verb{--} followed by a non-dash character (and optionally more characters), and +optionally a string of the desired short flag comprised of the +\code{-} followed by a single non-dash character. We don't allow \code{=} or whitespace characters in flags.} \item{action}{A character string describing the action \code{optparse} should take when it encounters an option. One of: \itemize{ @@ -122,6 +122,3 @@ is described here: \url{https://docs.python.org/3/library/optparse.html} \seealso{ \code{\link[=parse_args]{parse_args()}} \code{\link[=OptionParser]{OptionParser()}} } -\author{ -Trevor Davis. -} diff --git a/man/parse_args.Rd b/man/parse_args.Rd index d9d1976..0cc94f4 100644 --- a/man/parse_args.Rd +++ b/man/parse_args.Rd @@ -109,6 +109,3 @@ is described here: \url{https://docs.python.org/3/library/optparse.html} \seealso{ \code{\link[=OptionParser]{OptionParser()}} \code{\link[=print_help]{print_help()}} } -\author{ -Trevor Davis. -} diff --git a/man/print_help.Rd b/man/print_help.Rd index 0143d9e..b74c5c5 100644 --- a/man/print_help.Rd +++ b/man/print_help.Rd @@ -24,6 +24,3 @@ is described here: \url{https://docs.python.org/3/library/optparse.html} \seealso{ \code{\link[=parse_args]{parse_args()}} \code{\link[=OptionParser]{OptionParser()}} } -\author{ -Trevor Davis. -} diff --git a/tests/testthat/_snaps/optparse.md b/tests/testthat/_snaps/optparse.md index f71d671..4ba57c0 100644 --- a/tests/testthat/_snaps/optparse.md +++ b/tests/testthat/_snaps/optparse.md @@ -6,6 +6,38 @@ Error in `make_option()`: ! We require a long flag option +--- + + Code + make_option("- ") + Condition + Error in `make_option()`: + ! Short flag - must not contain whitespace + +--- + + Code + make_option("-=") + Condition + Error in `make_option()`: + ! Short flag -= must not contain '=' + +--- + + Code + make_option("--fo=o") + Condition + Error in `make_option()`: + ! Long flag --fo=o must not contain '=' + +--- + + Code + make_option("--fo o") + Condition + Error in `make_option()`: + ! Long flag --fo o must not contain whitespace + # `required` argument works as expected Code diff --git a/tests/testthat/test-optparse.R b/tests/testthat/test-optparse.R index 870d5d6..795305c 100644 --- a/tests/testthat/test-optparse.R +++ b/tests/testthat/test-optparse.R @@ -67,6 +67,13 @@ test_that("`make_option()` works as expected", { expect_equal(make_option("--filename")@type, "character") expect_snapshot(error = TRUE, make_option("badflag")) expect_error(make_option("-cd"), "must only be") + expect_equal(make_option(c("-1", "--one"))@short_flag, "-1") + expect_equal(make_option("--1flag")@long_flag, "--1flag") + expect_equal(make_option("--add-numbers")@long_flag, "--add-numbers") + expect_snapshot(error = TRUE, make_option("- ")) + expect_snapshot(error = TRUE, make_option("-=")) + expect_snapshot(error = TRUE, make_option("--fo=o")) + expect_snapshot(error = TRUE, make_option("--fo o")) }) get_long_flags <- function(parser) {