Skip to content

Commit fab45f5

Browse files
author
José Valim
committed
Merge pull request #2311 from alco/option-parser-fixes
Do not assume invalid options are of boolean type
2 parents 44d4b5a + a937590 commit fab45f5

File tree

2 files changed

+24
-11
lines changed

2 files changed

+24
-11
lines changed

lib/elixir/lib/option_parser.ex

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -216,13 +216,13 @@ defmodule OptionParser do
216216

217217
defp next(["-" <> option|rest], aliases, switches, strict) do
218218
{option, value} = split_option(option)
219-
opt = tag_option(option, value, switches, aliases)
219+
tagged = tag_option(option, value, switches, aliases)
220220

221-
if strict and not option_defined?(opt, switches) do
222-
{_, opt_name} = opt
221+
if strict and not option_defined?(tagged, switches) do
222+
{_, opt_name} = tagged
223223
{:undefined, opt_name, value, rest}
224224
else
225-
{opt_name, kinds, value} = normalize_option(opt, value, switches)
225+
{opt_name, kinds, value} = normalize_option(tagged, value, switches)
226226
{value, kinds, rest} = normalize_value(value, kinds, rest, strict)
227227
case validate_option(opt_name, value, kinds) do
228228
{:ok, new_value} -> {:ok, opt_name, new_value, rest}
@@ -330,7 +330,7 @@ defmodule OptionParser do
330330
kinds == [] ->
331331
{option, kinds, true}
332332
true ->
333-
{option, [:invalid], false}
333+
{reverse_negated(option), [:invalid], nil}
334334
end
335335
end
336336

@@ -343,17 +343,17 @@ defmodule OptionParser do
343343
end
344344

345345
defp normalize_value(nil, kinds, t, strict) do
346-
null = if strict, do: nil, else: true
346+
nil_or_true = if strict, do: nil, else: true
347347
cond do
348348
:boolean in kinds ->
349349
{true, kinds, t}
350350
value_in_tail?(t) ->
351351
[h|t] = t
352352
{h, kinds, t}
353353
kinds == [] ->
354-
{null, kinds, t}
354+
{nil_or_true, kinds, t}
355355
true ->
356-
{null, [:invalid], t}
356+
{nil, [:invalid], t}
357357
end
358358
end
359359

@@ -382,6 +382,10 @@ defmodule OptionParser do
382382
option |> to_underscore |> String.to_atom
383383
end
384384

385+
defp reverse_negated(negated) do
386+
String.to_atom("no_" <> Atom.to_string(negated))
387+
end
388+
385389
defp get_negated("no-" <> rest = option, value, switches) do
386390
negated = get_option(rest)
387391
option = if Keyword.has_key?(switches, negated) and value == nil do

lib/elixir/test/elixir/option_parser_test.exs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,15 @@ defmodule OptionParserTest do
4242
== {[source: "from_docs/"], ["other"], []}
4343
end
4444

45+
test "does not interpret undefined options with value as boolean" do
46+
assert OptionParser.parse(["--no-bool"])
47+
== {[no_bool: true], [], []}
48+
assert OptionParser.parse(["--no-bool"], strict: [])
49+
== {[], [], [no_bool: nil]}
50+
assert OptionParser.parse(["--no-bool=...", "other"])
51+
== {[], ["other"], [no_bool: "..."]}
52+
end
53+
4554
test "does not parse -- as an alias" do
4655
assert OptionParser.parse(["--s=from_docs/"], aliases: [s: :source])
4756
== {[s: "from_docs/"], [], []}
@@ -83,7 +92,7 @@ defmodule OptionParserTest do
8392
== {[require: "foo", require: "bar"], ["baz"], []}
8493

8594
assert OptionParser.parse(["--require"], switches: [require: :keep])
86-
== {[], [], [require: true]}
95+
== {[], [], [require: nil]}
8796
end
8897

8998
test "parses configured strings" do
@@ -92,9 +101,9 @@ defmodule OptionParserTest do
92101
assert OptionParser.parse(["--value=1", "foo"], switches: [value: :string])
93102
== {[value: "1"], ["foo"], []}
94103
assert OptionParser.parse(["--value"], switches: [value: :string])
95-
== {[], [], [value: true]}
104+
== {[], [], [value: nil]}
96105
assert OptionParser.parse(["--no-value"], switches: [value: :string])
97-
== {[], [], [value: false]}
106+
== {[], [], [no_value: nil]}
98107
end
99108

100109
test "parses configured integers" do

0 commit comments

Comments
 (0)