Skip to content

Commit

Permalink
Merge pull request #80 from rfdonnelly/gnu-bool-options
Browse files Browse the repository at this point in the history
  • Loading branch information
rfdonnelly authored Nov 6, 2023
2 parents 681dfbe + 195d8ba commit 97dd52b
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 22 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,8 @@ Fourth Ctrl-C sends SIGKILL to active jobs.

* Added `--dry-run` option

* Added GNU style negation for boolean plus options (e.g. `+no-flag` is the same as `+flag=false`)

=== Fixed

* Fixed typo of `--verbose` option
Expand Down
49 changes: 33 additions & 16 deletions lib/jobrnr/plus_option_parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,23 @@ def value=(value)
end

def parse_value(value); end

def format_help
[
" +#{name}=<value>",
" #{description} Default: #{default}"
].join("\n")
end
end

# An option that accepts true/false values
class BooleanOption < PlusOption
def parse_value(value)
case value
when :noarg
when :implicit_true
true
when :implicit_false
false
when /^(true|t|yes|y|1)$/ # rubocop: disable Lint/DuplicateBranch
true
when /^(false|f|no|n|0)$/
Expand All @@ -58,28 +67,45 @@ def parse_value(value)
"type for the '+#{name}' option"
end
end

def format_help
[
" +[no-]#{name}",
" #{description} Default: #{default}"
].join("\n")
end
end

# An option that accepts string values
class StringOption < PlusOption
def parse_value(value)
if value == :noarg
if value == :implicit_true
raise Jobrnr::ArgumentError,
"No argument given for '+#{name}' option"
end

if value == :implicit_false
raise Jobrnr::ArgumentError,
"Unrecognized option '+no-#{name}'"
end

value
end
end

# An option that accepts Integer values
class IntegerOption < PlusOption
def parse_value(value)
if value == :noarg
if value == :implicit_true
raise Jobrnr::ArgumentError,
"No argument given for '+#{name}' option"
end

if value == :implicit_false
raise Jobrnr::ArgumentError,
"Unrecognized option '+no-#{name}'"
end

begin
Integer(value)
rescue StandardError
Expand Down Expand Up @@ -236,7 +262,7 @@ def help(option_definitions, doc_params = {})

lines << [
"OPTIONS",
option_definitions.values.map { |option_definition| help_format_option(option_definition) },
option_definitions.values.map(&:format_help),
" +help\n Show this help and exit."
]

Expand All @@ -249,17 +275,6 @@ def help(option_definitions, doc_params = {})
lines.join("\n\n")
end

def help_format_option(option_definition)
[
" +#{help_format_name(option_definition)}",
" #{option_definition.description} Default: #{option_definition.default}"
].join("\n")
end

def help_format_name(option_definition)
option_definition.name + (option_definition.is_a?(BooleanOption) ? "[=<value>]" : "=<value>")
end

def specs_to_defs(options_spec)
options_spec
.map { |id, spec| [id, spec_to_def(id, spec)] }
Expand Down Expand Up @@ -288,8 +303,10 @@ def plus_options_to_hash(plus_options)
plus_options.each_with_object({}) do |plus_option, plus_options_hash|
if (md = plus_option.match(/^\+(.*?)=(.*)/))
plus_options_hash[s_to_sym(md.captures.first)] = md.captures.last
elsif (md = plus_option.match(/^\+no-((\w|-)+)$/))
plus_options_hash[s_to_sym(md.captures.first)] = :implicit_false
elsif (md = plus_option.match(/^\+((\w|-)+)$/))
plus_options_hash[s_to_sym(md.captures.first)] = :noarg
plus_options_hash[s_to_sym(md.captures.first)] = :implicit_true
end
end
end
Expand Down
26 changes: 20 additions & 6 deletions test/plus_option_parser_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -122,17 +122,31 @@
assert_equal(exp, act)
end

it "accepts gnu negation" do
exp = {
default_true: false,
default_inferred: false,
integer: 1,
string: "hello world",
}
act = @obj.parse(
@specs,
%w[+no-default-true],
)
assert_equal(exp, act)
end

describe "+help" do
it "general" do
e = assert_raises(Jobrnr::HelpException) { @obj.parse(@specs, %w[+help]) }

assert_equal(Jobrnr::Util.strip_heredoc(<<-EOF).strip, e.message)
OPTIONS
+default-true[=<value>]
+[no-]default-true
An option with a default true value. Default: true
+default-inferred[=<value>]
+[no-]default-inferred
An option with an inferred default value. Default: false
+integer=<value>
Expand Down Expand Up @@ -180,10 +194,10 @@
OPTIONS
+default-true[=<value>]
+[no-]default-true
An option with a default true value. Default: true
+default-inferred[=<value>]
+[no-]default-inferred
An option with an inferred default value. Default: false
+integer=<value>
Expand Down Expand Up @@ -212,10 +226,10 @@
OPTIONS
+default-true[=<value>]
+[no-]default-true
An option with a default true value. Default: true
+default-inferred[=<value>]
+[no-]default-inferred
An option with an inferred default value. Default: false
+integer=<value>
Expand Down

0 comments on commit 97dd52b

Please sign in to comment.