thor 0.18.1 → 0.19.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (92) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +13 -7
  3. data/Thorfile +4 -5
  4. data/bin/thor +1 -1
  5. data/lib/thor.rb +78 -67
  6. data/lib/thor/actions.rb +57 -56
  7. data/lib/thor/actions/create_file.rb +33 -35
  8. data/lib/thor/actions/create_link.rb +2 -3
  9. data/lib/thor/actions/directory.rb +37 -38
  10. data/lib/thor/actions/empty_directory.rb +67 -69
  11. data/lib/thor/actions/file_manipulation.rb +17 -15
  12. data/lib/thor/actions/inject_into_file.rb +27 -29
  13. data/lib/thor/base.rb +193 -189
  14. data/lib/thor/command.rb +20 -23
  15. data/lib/thor/core_ext/hash_with_indifferent_access.rb +21 -24
  16. data/lib/thor/core_ext/io_binary_read.rb +2 -4
  17. data/lib/thor/core_ext/ordered_hash.rb +9 -11
  18. data/lib/thor/error.rb +5 -1
  19. data/lib/thor/group.rb +53 -54
  20. data/lib/thor/invocation.rb +44 -38
  21. data/lib/thor/line_editor.rb +17 -0
  22. data/lib/thor/line_editor/basic.rb +35 -0
  23. data/lib/thor/line_editor/readline.rb +88 -0
  24. data/lib/thor/parser.rb +4 -4
  25. data/lib/thor/parser/argument.rb +28 -29
  26. data/lib/thor/parser/arguments.rb +102 -98
  27. data/lib/thor/parser/option.rb +26 -22
  28. data/lib/thor/parser/options.rb +86 -86
  29. data/lib/thor/rake_compat.rb +9 -10
  30. data/lib/thor/runner.rb +141 -141
  31. data/lib/thor/shell.rb +27 -34
  32. data/lib/thor/shell/basic.rb +91 -63
  33. data/lib/thor/shell/color.rb +44 -43
  34. data/lib/thor/shell/html.rb +59 -60
  35. data/lib/thor/util.rb +24 -27
  36. data/lib/thor/version.rb +1 -1
  37. data/spec/actions/create_file_spec.rb +25 -27
  38. data/spec/actions/create_link_spec.rb +19 -18
  39. data/spec/actions/directory_spec.rb +31 -31
  40. data/spec/actions/empty_directory_spec.rb +18 -18
  41. data/spec/actions/file_manipulation_spec.rb +38 -28
  42. data/spec/actions/inject_into_file_spec.rb +13 -13
  43. data/spec/actions_spec.rb +43 -43
  44. data/spec/base_spec.rb +45 -38
  45. data/spec/command_spec.rb +13 -14
  46. data/spec/core_ext/hash_with_indifferent_access_spec.rb +19 -19
  47. data/spec/core_ext/ordered_hash_spec.rb +6 -6
  48. data/spec/exit_condition_spec.rb +4 -4
  49. data/spec/fixtures/invoke.thor +19 -0
  50. data/spec/fixtures/script.thor +1 -1
  51. data/spec/group_spec.rb +30 -24
  52. data/spec/helper.rb +28 -15
  53. data/spec/invocation_spec.rb +39 -19
  54. data/spec/line_editor/basic_spec.rb +28 -0
  55. data/spec/line_editor/readline_spec.rb +69 -0
  56. data/spec/line_editor_spec.rb +43 -0
  57. data/spec/parser/argument_spec.rb +12 -12
  58. data/spec/parser/arguments_spec.rb +11 -11
  59. data/spec/parser/option_spec.rb +33 -25
  60. data/spec/parser/options_spec.rb +66 -52
  61. data/spec/quality_spec.rb +75 -0
  62. data/spec/rake_compat_spec.rb +10 -10
  63. data/spec/register_spec.rb +60 -30
  64. data/spec/runner_spec.rb +67 -62
  65. data/spec/sandbox/application.rb +2 -0
  66. data/spec/sandbox/app{1}/README +3 -0
  67. data/spec/sandbox/bundle/execute.rb +6 -0
  68. data/spec/sandbox/bundle/main.thor +1 -0
  69. data/spec/sandbox/command.thor +10 -0
  70. data/spec/sandbox/doc/%file_name%.rb.tt +1 -0
  71. data/spec/sandbox/doc/COMMENTER +11 -0
  72. data/spec/sandbox/doc/README +3 -0
  73. data/spec/sandbox/doc/block_helper.rb +3 -0
  74. data/spec/sandbox/doc/config.rb +1 -0
  75. data/spec/sandbox/doc/config.yaml.tt +1 -0
  76. data/spec/sandbox/doc/excluding/%file_name%.rb.tt +1 -0
  77. data/spec/sandbox/enum.thor +10 -0
  78. data/spec/sandbox/group.thor +128 -0
  79. data/spec/sandbox/invoke.thor +131 -0
  80. data/spec/sandbox/path with spaces b/data/spec/sandbox/path with → spaces +0 -0
  81. data/spec/sandbox/preserve/script.sh +3 -0
  82. data/spec/sandbox/script.thor +220 -0
  83. data/spec/sandbox/subcommand.thor +17 -0
  84. data/spec/shell/basic_spec.rb +107 -86
  85. data/spec/shell/color_spec.rb +32 -8
  86. data/spec/shell/html_spec.rb +3 -4
  87. data/spec/shell_spec.rb +7 -7
  88. data/spec/subcommand_spec.rb +20 -2
  89. data/spec/thor_spec.rb +111 -97
  90. data/spec/util_spec.rb +30 -30
  91. data/thor.gemspec +14 -14
  92. metadata +69 -25
@@ -0,0 +1,28 @@
1
+ require "helper"
2
+
3
+ describe Thor::LineEditor::Basic do
4
+ describe ".available?" do
5
+ it "returns true" do
6
+ expect(Thor::LineEditor::Basic).to be_available
7
+ end
8
+ end
9
+
10
+ describe "#readline" do
11
+ it "uses $stdin and $stdout to get input from the user" do
12
+ expect($stdout).to receive(:print).with("Enter your name ")
13
+ expect($stdin).to receive(:gets).and_return("George")
14
+ expect($stdin).not_to receive(:noecho)
15
+ editor = Thor::LineEditor::Basic.new("Enter your name ", {})
16
+ expect(editor.readline).to eq("George")
17
+ end
18
+
19
+ it "disables echo when asked to" do
20
+ expect($stdout).to receive(:print).with("Password: ")
21
+ noecho_stdin = double("noecho_stdin")
22
+ expect(noecho_stdin).to receive(:gets).and_return("secret")
23
+ expect($stdin).to receive(:noecho).and_yield(noecho_stdin)
24
+ editor = Thor::LineEditor::Basic.new("Password: ", :echo => false)
25
+ expect(editor.readline).to eq("secret")
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,69 @@
1
+ require "helper"
2
+
3
+ describe Thor::LineEditor::Readline do
4
+ before do
5
+ unless defined? ::Readline
6
+ ::Readline = double("Readline")
7
+ allow(::Readline).to receive(:completion_append_character=).with(nil)
8
+ end
9
+ end
10
+
11
+ describe ".available?" do
12
+ it "returns true when ::Readline exists" do
13
+ allow(Object).to receive(:const_defined?).with(:Readline).and_return(true)
14
+ expect(described_class).to be_available
15
+ end
16
+
17
+ it "returns false when ::Readline does not exist" do
18
+ allow(Object).to receive(:const_defined?).with(:Readline).and_return(false)
19
+ expect(described_class).not_to be_available
20
+ end
21
+ end
22
+
23
+ describe "#readline" do
24
+ it "invokes the readline library" do
25
+ expect(::Readline).to receive(:readline).with("> ", true).and_return("foo")
26
+ expect(::Readline).not_to receive(:completion_proc=)
27
+ editor = Thor::LineEditor::Readline.new("> ", {})
28
+ expect(editor.readline).to eq("foo")
29
+ end
30
+
31
+ it "supports the add_to_history option" do
32
+ expect(::Readline).to receive(:readline).with("> ", false).and_return("foo")
33
+ expect(::Readline).not_to receive(:completion_proc=)
34
+ editor = Thor::LineEditor::Readline.new("> ", :add_to_history => false)
35
+ expect(editor.readline).to eq("foo")
36
+ end
37
+
38
+ it "provides tab completion when given a limited_to option" do
39
+ expect(::Readline).to receive(:readline)
40
+ expect(::Readline).to receive(:completion_proc=) do |proc|
41
+ expect(proc.call("")).to eq %w[Apples Chicken Chocolate]
42
+ expect(proc.call("Ch")).to eq %w[Chicken Chocolate]
43
+ expect(proc.call("Chi")).to eq ["Chicken"]
44
+ end
45
+
46
+ editor = Thor::LineEditor::Readline.new("Best food: ", :limited_to => %w[Apples Chicken Chocolate])
47
+ editor.readline
48
+ end
49
+
50
+ it "provides path tab completion when given the path option" do
51
+ expect(::Readline).to receive(:readline)
52
+ expect(::Readline).to receive(:completion_proc=) do |proc|
53
+ expect(proc.call("../line_ed").sort).to eq ["../line_editor/", "../line_editor_spec.rb"].sort
54
+ end
55
+
56
+ editor = Thor::LineEditor::Readline.new("Path to file: ", :path => true)
57
+ Dir.chdir(File.dirname(__FILE__)) { editor.readline }
58
+ end
59
+
60
+ it "uses STDIN when asked not to echo input" do
61
+ expect($stdout).to receive(:print).with("Password: ")
62
+ noecho_stdin = double("noecho_stdin")
63
+ expect(noecho_stdin).to receive(:gets).and_return("secret")
64
+ expect($stdin).to receive(:noecho).and_yield(noecho_stdin)
65
+ editor = Thor::LineEditor::Readline.new("Password: ", :echo => false)
66
+ expect(editor.readline).to eq("secret")
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,43 @@
1
+ require "helper"
2
+
3
+ describe Thor::LineEditor, "on a system with Readline support" do
4
+ before do
5
+ @original_readline = ::Readline if defined? ::Readline
6
+ silence_warnings { ::Readline = double("Readline") }
7
+ end
8
+
9
+ after do
10
+ silence_warnings { ::Readline = @original_readline }
11
+ end
12
+
13
+ describe ".readline" do
14
+ it "uses the Readline line editor" do
15
+ editor = double("Readline")
16
+ expect(Thor::LineEditor::Readline).to receive(:new).with("Enter your name ", :default => "Brian").and_return(editor)
17
+ expect(editor).to receive(:readline).and_return("George")
18
+ expect(Thor::LineEditor.readline("Enter your name ", :default => "Brian")).to eq("George")
19
+ end
20
+ end
21
+ end
22
+
23
+ describe Thor::LineEditor, "on a system without Readline support" do
24
+ before do
25
+ if defined? ::Readline
26
+ @original_readline = ::Readline
27
+ Object.send(:remove_const, :Readline)
28
+ end
29
+ end
30
+
31
+ after do
32
+ silence_warnings { ::Readline = @original_readline }
33
+ end
34
+
35
+ describe ".readline" do
36
+ it "uses the Basic line editor" do
37
+ editor = double("Basic")
38
+ expect(Thor::LineEditor::Basic).to receive(:new).with("Enter your name ", :default => "Brian").and_return(editor)
39
+ expect(editor).to receive(:readline).and_return("George")
40
+ expect(Thor::LineEditor.readline("Enter your name ", :default => "Brian")).to eq("George")
41
+ end
42
+ end
43
+ end
@@ -1,35 +1,35 @@
1
- require 'helper'
2
- require 'thor/parser'
1
+ require "helper"
2
+ require "thor/parser"
3
3
 
4
4
  describe Thor::Argument do
5
5
 
6
- def argument(name, options={})
6
+ def argument(name, options = {})
7
7
  @argument ||= Thor::Argument.new(name, options)
8
8
  end
9
9
 
10
10
  describe "errors" do
11
11
  it "raises an error if name is not supplied" do
12
- expect {
12
+ expect do
13
13
  argument(nil)
14
- }.to raise_error(ArgumentError, "Argument name can't be nil.")
14
+ end.to raise_error(ArgumentError, "Argument name can't be nil.")
15
15
  end
16
16
 
17
17
  it "raises an error if type is unknown" do
18
- expect {
18
+ expect do
19
19
  argument(:command, :type => :unknown)
20
- }.to raise_error(ArgumentError, "Type :unknown is not valid for arguments.")
20
+ end.to raise_error(ArgumentError, "Type :unknown is not valid for arguments.")
21
21
  end
22
22
 
23
- it "raises an error if argument is required and have default values" do
24
- expect {
23
+ it "raises an error if argument is required and has default values" do
24
+ expect do
25
25
  argument(:command, :type => :string, :default => "bar", :required => true)
26
- }.to raise_error(ArgumentError, "An argument cannot be required and have default value.")
26
+ end.to raise_error(ArgumentError, "An argument cannot be required and have default value.")
27
27
  end
28
28
 
29
29
  it "raises an error if enum isn't an array" do
30
- expect {
30
+ expect do
31
31
  argument(:command, :type => :string, :enum => "bar")
32
- }.to raise_error(ArgumentError, "An argument cannot have an enum other than an array.")
32
+ end.to raise_error(ArgumentError, "An argument cannot have an enum other than an array.")
33
33
  end
34
34
  end
35
35
 
@@ -1,14 +1,14 @@
1
- require 'helper'
2
- require 'thor/parser'
1
+ require "helper"
2
+ require "thor/parser"
3
3
 
4
4
  describe Thor::Arguments do
5
- def create(opts={})
5
+ def create(opts = {})
6
6
  arguments = opts.map do |type, default|
7
7
  options = {:required => default.nil?, :type => type, :default => default}
8
8
  Thor::Argument.new(type.to_s, options)
9
9
  end
10
10
 
11
- arguments.sort!{ |a,b| b.name <=> a.name }
11
+ arguments.sort! { |a, b| b.name <=> a.name }
12
12
  @opt = Thor::Arguments.new(arguments)
13
13
  end
14
14
 
@@ -26,14 +26,14 @@ describe Thor::Arguments do
26
26
  it "accepts hashes" do
27
27
  create :string => nil, :hash => nil
28
28
  expect(parse("product", "title:string", "age:integer")["string"]).to eq("product")
29
- expect(parse("product", "title:string", "age:integer")["hash"]).to eq({ "title" => "string", "age" => "integer"})
30
- expect(parse("product", "url:http://www.amazon.com/gp/product/123")["hash"]).to eq({ "url" => "http://www.amazon.com/gp/product/123" })
29
+ expect(parse("product", "title:string", "age:integer")["hash"]).to eq("title" => "string", "age" => "integer")
30
+ expect(parse("product", "url:http://www.amazon.com/gp/product/123")["hash"]).to eq("url" => "http://www.amazon.com/gp/product/123")
31
31
  end
32
32
 
33
33
  it "accepts arrays" do
34
34
  create :string => nil, :array => nil
35
35
  expect(parse("product", "title", "age")["string"]).to eq("product")
36
- expect(parse("product", "title", "age")["array"]).to eq(%w(title age))
36
+ expect(parse("product", "title", "age")["array"]).to eq(%w[title age])
37
37
  end
38
38
 
39
39
  describe "with no inputs" do
@@ -44,23 +44,23 @@ describe Thor::Arguments do
44
44
 
45
45
  it "and required arguments raises an error" do
46
46
  create :string => nil, :numeric => nil
47
- expect{ parse }.to raise_error(Thor::RequiredArgumentMissingError, "No value provided for required arguments 'string', 'numeric'")
47
+ expect { parse }.to raise_error(Thor::RequiredArgumentMissingError, "No value provided for required arguments 'string', 'numeric'")
48
48
  end
49
49
 
50
50
  it "and default arguments returns default values" do
51
51
  create :string => "name", :numeric => 13
52
- expect(parse).to eq({ "string" => "name", "numeric" => 13 })
52
+ expect(parse).to eq("string" => "name", "numeric" => 13)
53
53
  end
54
54
  end
55
55
 
56
56
  it "returns the input if it's already parsed" do
57
57
  create :string => nil, :hash => nil, :array => nil, :numeric => nil
58
- expect(parse("", 0, {}, [])).to eq({ "string" => "", "numeric" => 0, "hash" => {}, "array" => [] })
58
+ expect(parse("", 0, {}, [])).to eq("string" => "", "numeric" => 0, "hash" => {}, "array" => [])
59
59
  end
60
60
 
61
61
  it "returns the default value if none is provided" do
62
62
  create :string => "foo", :numeric => 3.0
63
- expect(parse("bar")).to eq({ "string" => "bar", "numeric" => 3.0 })
63
+ expect(parse("bar")).to eq("string" => "bar", "numeric" => 3.0)
64
64
  end
65
65
  end
66
66
  end
@@ -1,12 +1,12 @@
1
- require 'helper'
2
- require 'thor/parser'
1
+ require "helper"
2
+ require "thor/parser"
3
3
 
4
4
  describe Thor::Option do
5
5
  def parse(key, value)
6
6
  Thor::Option.parse(key, value)
7
7
  end
8
8
 
9
- def option(name, options={})
9
+ def option(name, options = {})
10
10
  @option ||= Thor::Option.new(name, options)
11
11
  end
12
12
 
@@ -19,9 +19,9 @@ describe Thor::Option do
19
19
  expect(parse(:foo, :numeric).type).to eq(:numeric)
20
20
  end
21
21
 
22
- it "has not default value" do
23
- expect(parse(:foo, :string).default).to be_nil
24
- expect(parse(:foo, :numeric).default).to be_nil
22
+ it "has no default value" do
23
+ expect(parse(:foo, :string).default).to be nil
24
+ expect(parse(:foo, :numeric).default).to be nil
25
25
  end
26
26
  end
27
27
 
@@ -31,17 +31,17 @@ describe Thor::Option do
31
31
  end
32
32
 
33
33
  it "has no default value" do
34
- expect(parse(:foo, :required).default).to be_nil
34
+ expect(parse(:foo, :required).default).to be nil
35
35
  end
36
36
  end
37
37
 
38
38
  describe "and symbol is not a reserved key" do
39
- it "has type equals to :string" do
39
+ it "has type equal to :string" do
40
40
  expect(parse(:foo, :bar).type).to eq(:string)
41
41
  end
42
42
 
43
43
  it "has no default value" do
44
- expect(parse(:foo, :bar).default).to be_nil
44
+ expect(parse(:foo, :bar).default).to be nil
45
45
  end
46
46
  end
47
47
  end
@@ -51,8 +51,8 @@ describe Thor::Option do
51
51
  expect(parse(:foo, :a => :b).type).to eq(:hash)
52
52
  end
53
53
 
54
- it "has default value equals to the hash" do
55
- expect(parse(:foo, :a => :b).default).to eq({ :a => :b })
54
+ it "has default value equal to the hash" do
55
+ expect(parse(:foo, :a => :b).default).to eq(:a => :b)
56
56
  end
57
57
  end
58
58
 
@@ -61,7 +61,7 @@ describe Thor::Option do
61
61
  expect(parse(:foo, [:a, :b]).type).to eq(:array)
62
62
  end
63
63
 
64
- it "has default value equals to the array" do
64
+ it "has default value equal to the array" do
65
65
  expect(parse(:foo, [:a, :b]).default).to eq([:a, :b])
66
66
  end
67
67
  end
@@ -71,7 +71,7 @@ describe Thor::Option do
71
71
  expect(parse(:foo, "bar").type).to eq(:string)
72
72
  end
73
73
 
74
- it "has default value equals to the string" do
74
+ it "has default value equal to the string" do
75
75
  expect(parse(:foo, "bar").default).to eq("bar")
76
76
  end
77
77
  end
@@ -81,7 +81,7 @@ describe Thor::Option do
81
81
  expect(parse(:foo, 2.0).type).to eq(:numeric)
82
82
  end
83
83
 
84
- it "has default value equals to the numeric" do
84
+ it "has default value equal to the numeric" do
85
85
  expect(parse(:foo, 2.0).default).to eq(2.0)
86
86
  end
87
87
  end
@@ -92,14 +92,14 @@ describe Thor::Option do
92
92
  expect(parse(:foo, false).type).to eq(:boolean)
93
93
  end
94
94
 
95
- it "has default value equals to the boolean" do
95
+ it "has default value equal to the boolean" do
96
96
  expect(parse(:foo, true).default).to eq(true)
97
97
  expect(parse(:foo, false).default).to eq(false)
98
98
  end
99
99
  end
100
100
 
101
101
  describe "with key as a symbol" do
102
- it "sets the name equals to the key" do
102
+ it "sets the name equal to the key" do
103
103
  expect(parse(:foo, true).name).to eq("foo")
104
104
  end
105
105
  end
@@ -135,10 +135,10 @@ describe Thor::Option do
135
135
  expect(option).to be_required
136
136
  end
137
137
 
138
- it "cannot be required and have type boolean" do
139
- expect {
138
+ it "boolean options cannot be required" do
139
+ expect do
140
140
  option("foo", :required => true, :type => :boolean)
141
- }.to raise_error(ArgumentError, "An option cannot be boolean and required.")
141
+ end.to raise_error(ArgumentError, "An option cannot be boolean and required.")
142
142
  end
143
143
 
144
144
  it "allows type predicates" do
@@ -148,9 +148,9 @@ describe Thor::Option do
148
148
  end
149
149
 
150
150
  it "raises an error on method missing" do
151
- expect {
151
+ expect do
152
152
  parse(:foo, :string).unknown?
153
- }.to raise_error(NoMethodError)
153
+ end.to raise_error(NoMethodError)
154
154
  end
155
155
 
156
156
  describe "#usage" do
@@ -172,18 +172,22 @@ describe Thor::Option do
172
172
  end
173
173
 
174
174
  it "returns usage for boolean types" do
175
- expect(parse(:foo, :boolean).usage).to eq("[--foo]")
175
+ expect(parse(:foo, :boolean).usage).to eq("[--foo], [--no-foo]")
176
+ end
177
+
178
+ it "does not use padding when no aliases are given" do
179
+ expect(parse(:foo, :boolean).usage).to eq("[--foo], [--no-foo]")
176
180
  end
177
181
 
178
- it "uses padding when no aliases is given" do
179
- expect(parse(:foo, :boolean).usage(4)).to eq(" [--foo]")
182
+ it "documents a negative option when boolean" do
183
+ expect(parse(:foo, :boolean).usage).to include("[--no-foo]")
180
184
  end
181
185
 
182
186
  it "uses banner when supplied" do
183
187
  expect(option(:foo, :required => false, :type => :string, :banner => "BAR").usage).to eq("[--foo=BAR]")
184
188
  end
185
189
 
186
- it "checkes when banner is an empty string" do
190
+ it "checks when banner is an empty string" do
187
191
  expect(option(:foo, :required => false, :type => :string, :banner => "").usage).to eq("[--foo]")
188
192
  end
189
193
 
@@ -197,6 +201,10 @@ describe Thor::Option do
197
201
  it "does not show the usage between brackets" do
198
202
  expect(parse([:foo, "-f", "-b"], :required).usage).to eq("-f, -b, --foo=FOO")
199
203
  end
204
+
205
+ it "does not negate the aliases" do
206
+ expect(parse([:foo, "-f", "-b"], :boolean).usage).to eq("-f, -b, [--foo], [--no-foo]")
207
+ end
200
208
  end
201
209
  end
202
210
  end
@@ -1,8 +1,8 @@
1
- require 'helper'
2
- require 'thor/parser'
1
+ require "helper"
2
+ require "thor/parser"
3
3
 
4
4
  describe Thor::Options do
5
- def create(opts, defaults={}, stop_on_unknown=false)
5
+ def create(opts, defaults = {}, stop_on_unknown = false)
6
6
  opts.each do |key, value|
7
7
  opts[key] = Thor::Option.parse(key, value) unless value.is_a?(Thor::Option)
8
8
  end
@@ -40,12 +40,12 @@ describe Thor::Options do
40
40
  end
41
41
 
42
42
  it "joins several values" do
43
- switches = Thor::Options.to_switches(:color => true, :foo => "bar").split(' ').sort
44
- expect(switches).to eq(['"bar"', "--color", "--foo"])
43
+ switches = Thor::Options.to_switches(:color => true, :foo => "bar").split(" ").sort
44
+ expect(switches).to eq(%w["bar" --color --foo])
45
45
  end
46
46
 
47
47
  it "accepts arrays" do
48
- expect(Thor::Options.to_switches(:count => [1,2,3])).to eq("--count 1 2 3")
48
+ expect(Thor::Options.to_switches(:count => [1, 2, 3])).to eq("--count 1 2 3")
49
49
  end
50
50
 
51
51
  it "accepts hashes" do
@@ -60,7 +60,7 @@ describe Thor::Options do
60
60
 
61
61
  describe "#parse" do
62
62
  it "allows multiple aliases for a given switch" do
63
- create ["--foo", "--bar", "--baz"] => :string
63
+ create %w[--foo --bar --baz] => :string
64
64
  expect(parse("--foo", "12")["foo"]).to eq("12")
65
65
  expect(parse("--bar", "12")["foo"]).to eq("12")
66
66
  expect(parse("--baz", "12")["foo"]).to eq("12")
@@ -68,27 +68,27 @@ describe Thor::Options do
68
68
 
69
69
  it "allows custom short names" do
70
70
  create "-f" => :string
71
- expect(parse("-f", "12")).to eq({"f" => "12"})
71
+ expect(parse("-f", "12")).to eq("f" => "12")
72
72
  end
73
73
 
74
74
  it "allows custom short-name aliases" do
75
- create ["--bar", "-f"] => :string
76
- expect(parse("-f", "12")).to eq({"bar" => "12"})
75
+ create %w[--bar -f] => :string
76
+ expect(parse("-f", "12")).to eq("bar" => "12")
77
77
  end
78
78
 
79
79
  it "accepts conjoined short switches" do
80
- create ["--foo", "-f"] => true, ["--bar", "-b"] => true, ["--app", "-a"] => true
80
+ create %w[--foo -f] => true, %w[--bar -b] => true, %w[--app -a] => true
81
81
  opts = parse("-fba")
82
- expect(opts["foo"]).to be_true
83
- expect(opts["bar"]).to be_true
84
- expect(opts["app"]).to be_true
82
+ expect(opts["foo"]).to be true
83
+ expect(opts["bar"]).to be true
84
+ expect(opts["app"]).to be true
85
85
  end
86
86
 
87
87
  it "accepts conjoined short switches with input" do
88
- create ["--foo", "-f"] => true, ["--bar", "-b"] => true, ["--app", "-a"] => :required
88
+ create %w[--foo -f] => true, %w[--bar -b] => true, %w[--app -a] => :required
89
89
  opts = parse "-fba", "12"
90
- expect(opts["foo"]).to be_true
91
- expect(opts["bar"]).to be_true
90
+ expect(opts["foo"]).to be true
91
+ expect(opts["bar"]).to be true
92
92
  expect(opts["app"]).to eq("12")
93
93
  end
94
94
 
@@ -110,18 +110,18 @@ describe Thor::Options do
110
110
  it "raises an error for unknown switches" do
111
111
  create :foo => "baz", :bar => :required
112
112
  parse("--bar", "baz", "--baz", "unknown")
113
- expect{ check_unknown! }.to raise_error(Thor::UnknownArgumentError, "Unknown switches '--baz'")
113
+ expect { check_unknown! }.to raise_error(Thor::UnknownArgumentError, "Unknown switches '--baz'")
114
114
  end
115
115
 
116
116
  it "skips leading non-switches" do
117
117
  create(:foo => "baz")
118
118
 
119
- expect(parse("asdf", "--foo", "bar")).to eq({"foo" => "bar"})
119
+ expect(parse("asdf", "--foo", "bar")).to eq("foo" => "bar")
120
120
  end
121
121
 
122
122
  it "correctly recognizes things that look kind of like options, but aren't, as not options" do
123
123
  create(:foo => "baz")
124
- expect(parse("--asdf---asdf", "baz", "--foo", "--asdf---dsf--asdf")).to eq({"foo" => "--asdf---dsf--asdf"})
124
+ expect(parse("--asdf---asdf", "baz", "--foo", "--asdf---dsf--asdf")).to eq("foo" => "--asdf---dsf--asdf")
125
125
  check_unknown!
126
126
  end
127
127
 
@@ -139,31 +139,31 @@ describe Thor::Options do
139
139
 
140
140
  it "interprets everything after -- as args instead of options" do
141
141
  create(:foo => :string, :bar => :required)
142
- expect(parse(%w[--bar abc moo -- --foo def -a])).to eq({"bar" => "abc"})
142
+ expect(parse(%w[--bar abc moo -- --foo def -a])).to eq("bar" => "abc")
143
143
  expect(remaining).to eq(%w[moo --foo def -a])
144
144
  end
145
145
 
146
146
  it "ignores -- when looking for single option values" do
147
147
  create(:foo => :string, :bar => :required)
148
- expect(parse(%w[--bar -- --foo def -a])).to eq({"bar" => "--foo"})
148
+ expect(parse(%w[--bar -- --foo def -a])).to eq("bar" => "--foo")
149
149
  expect(remaining).to eq(%w[def -a])
150
150
  end
151
151
 
152
152
  it "ignores -- when looking for array option values" do
153
153
  create(:foo => :array)
154
- expect(parse(%w[--foo a b -- c d -e])).to eq({"foo" => %w[a b c d -e]})
154
+ expect(parse(%w[--foo a b -- c d -e])).to eq("foo" => %w[a b c d -e])
155
155
  expect(remaining).to eq([])
156
156
  end
157
157
 
158
158
  it "ignores -- when looking for hash option values" do
159
159
  create(:foo => :hash)
160
- expect(parse(%w[--foo a:b -- c:d -e])).to eq({"foo" => {'a' => 'b', 'c' => 'd'}})
160
+ expect(parse(%w[--foo a:b -- c:d -e])).to eq("foo" => {"a" => "b", "c" => "d"})
161
161
  expect(remaining).to eq(%w[-e])
162
162
  end
163
163
 
164
164
  it "ignores trailing --" do
165
165
  create(:foo => :string)
166
- expect(parse(%w[--foo --])).to eq({"foo" => nil})
166
+ expect(parse(%w[--foo --])).to eq("foo" => nil)
167
167
  expect(remaining).to eq([])
168
168
  end
169
169
 
@@ -180,7 +180,7 @@ describe Thor::Options do
180
180
 
181
181
  it "and a required switch raises an error" do
182
182
  create "--foo" => :required
183
- expect{ parse }.to raise_error(Thor::RequiredArgumentMissingError, "No value provided for required options '--foo'")
183
+ expect { parse }.to raise_error(Thor::RequiredArgumentMissingError, "No value provided for required options '--foo'")
184
184
  end
185
185
  end
186
186
 
@@ -190,21 +190,21 @@ describe Thor::Options do
190
190
  end
191
191
 
192
192
  it "raises an error if the required switch has no argument" do
193
- expect{ parse("--foo") }.to raise_error(Thor::MalformattedArgumentError)
193
+ expect { parse("--foo") }.to raise_error(Thor::MalformattedArgumentError)
194
194
  end
195
195
 
196
196
  it "raises an error if the required switch isn't given" do
197
- expect{ parse("--bar") }.to raise_error(Thor::RequiredArgumentMissingError)
197
+ expect { parse("--bar") }.to raise_error(Thor::RequiredArgumentMissingError)
198
198
  end
199
199
 
200
200
  it "raises an error if the required switch is set to nil" do
201
- expect{ parse("--no-foo") }.to raise_error(Thor::RequiredArgumentMissingError)
201
+ expect { parse("--no-foo") }.to raise_error(Thor::RequiredArgumentMissingError)
202
202
  end
203
203
 
204
204
  it "does not raises an error if the required option has a default value" do
205
205
  options = {:required => true, :type => :string, :default => "baz"}
206
206
  create :foo => Thor::Option.new("foo", options), :bar => :boolean
207
- expect{ parse("--bar") }.not_to raise_error
207
+ expect { parse("--bar") }.not_to raise_error
208
208
  end
209
209
  end
210
210
 
@@ -215,38 +215,38 @@ describe Thor::Options do
215
215
 
216
216
  it "stops parsing on first non-option" do
217
217
  expect(parse(%w[foo --verbose])).to eq({})
218
- expect(remaining).to eq(["foo", "--verbose"])
218
+ expect(remaining).to eq(%w[foo --verbose])
219
219
  end
220
220
 
221
221
  it "stops parsing on unknown option" do
222
222
  expect(parse(%w[--bar --verbose])).to eq({})
223
- expect(remaining).to eq(["--bar", "--verbose"])
223
+ expect(remaining).to eq(%w[--bar --verbose])
224
224
  end
225
225
 
226
226
  it "retains -- after it has stopped parsing" do
227
227
  expect(parse(%w[--bar -- whatever])).to eq({})
228
- expect(remaining).to eq(["--bar", "--", "whatever"])
228
+ expect(remaining).to eq(%w[--bar -- whatever])
229
229
  end
230
230
 
231
231
  it "still accepts options that are given before non-options" do
232
- expect(parse(%w[--verbose foo])).to eq({"verbose" => true})
233
- expect(remaining).to eq(["foo"])
232
+ expect(parse(%w[--verbose foo])).to eq("verbose" => true)
233
+ expect(remaining).to eq(%w[foo])
234
234
  end
235
235
 
236
236
  it "still accepts options that require a value" do
237
- expect(parse(%w[--foo bar baz])).to eq({"foo" => "bar"})
238
- expect(remaining).to eq(["baz"])
237
+ expect(parse(%w[--foo bar baz])).to eq("foo" => "bar")
238
+ expect(remaining).to eq(%w[baz])
239
239
  end
240
240
 
241
241
  it "still interprets everything after -- as args instead of options" do
242
242
  expect(parse(%w[-- --verbose])).to eq({})
243
- expect(remaining).to eq(["--verbose"])
243
+ expect(remaining).to eq(%w[--verbose])
244
244
  end
245
245
  end
246
246
 
247
247
  describe "with :string type" do
248
248
  before do
249
- create ["--foo", "-f"] => :required
249
+ create %w[--foo -f] => :required
250
250
  end
251
251
 
252
252
  it "accepts a switch <value> assignment" do
@@ -266,12 +266,12 @@ describe Thor::Options do
266
266
 
267
267
  it "accepts a --no-switch format" do
268
268
  create "--foo" => "bar"
269
- expect(parse("--no-foo")["foo"]).to be_nil
269
+ expect(parse("--no-foo")["foo"]).to be nil
270
270
  end
271
271
 
272
272
  it "does not consume an argument for --no-switch format" do
273
273
  create "--cheese" => :string
274
- expect(parse('burger', '--no-cheese', 'fries')["cheese"]).to be_nil
274
+ expect(parse("burger", "--no-cheese", "fries")["cheese"]).to be nil
275
275
  end
276
276
 
277
277
  it "accepts a --switch format on non required types" do
@@ -288,6 +288,13 @@ describe Thor::Options do
288
288
  expect(parse("--foo=bar", "--foo", "12")["foo"]).to eq("12")
289
289
  expect(parse("--foo", "12", "--foo", "13")["foo"]).to eq("13")
290
290
  end
291
+
292
+ it "raises error when value isn't in enum" do
293
+ enum = %w[apple banana]
294
+ create :fruit => Thor::Option.new("fruit", :type => :string, :enum => enum)
295
+ expect { parse("--fruit", "orange") }.to raise_error(Thor::MalformattedArgumentError,
296
+ "Expected '--fruit' to be one of #{enum.join(', ')}; got orange")
297
+ end
291
298
  end
292
299
 
293
300
  describe "with :boolean type" do
@@ -336,8 +343,8 @@ describe Thor::Options do
336
343
 
337
344
  it "doesn't eat the next part of the param" do
338
345
  create :foo => :boolean
339
- expect(parse("--foo", "bar")).to eq({"foo" => true})
340
- expect(@opt.remaining).to eq(["bar"])
346
+ expect(parse("--foo", "bar")).to eq("foo" => true)
347
+ expect(@opt.remaining).to eq(%w[bar])
341
348
  end
342
349
  end
343
350
 
@@ -347,15 +354,15 @@ describe Thor::Options do
347
354
  end
348
355
 
349
356
  it "accepts a switch=<value> assignment" do
350
- expect(parse("--attributes=name:string", "age:integer")["attributes"]).to eq({"name" => "string", "age" => "integer"})
357
+ expect(parse("--attributes=name:string", "age:integer")["attributes"]).to eq("name" => "string", "age" => "integer")
351
358
  end
352
359
 
353
360
  it "accepts a switch <value> assignment" do
354
- expect(parse("--attributes", "name:string", "age:integer")["attributes"]).to eq({"name" => "string", "age" => "integer"})
361
+ expect(parse("--attributes", "name:string", "age:integer")["attributes"]).to eq("name" => "string", "age" => "integer")
355
362
  end
356
363
 
357
364
  it "must not mix values with other switches" do
358
- expect(parse("--attributes", "name:string", "age:integer", "--baz", "cool")["attributes"]).to eq({"name" => "string", "age" => "integer"})
365
+ expect(parse("--attributes", "name:string", "age:integer", "--baz", "cool")["attributes"]).to eq("name" => "string", "age" => "integer")
359
366
  end
360
367
  end
361
368
 
@@ -365,15 +372,15 @@ describe Thor::Options do
365
372
  end
366
373
 
367
374
  it "accepts a switch=<value> assignment" do
368
- expect(parse("--attributes=a", "b", "c")["attributes"]).to eq(["a", "b", "c"])
375
+ expect(parse("--attributes=a", "b", "c")["attributes"]).to eq(%w[a b c])
369
376
  end
370
377
 
371
378
  it "accepts a switch <value> assignment" do
372
- expect(parse("--attributes", "a", "b", "c")["attributes"]).to eq(["a", "b", "c"])
379
+ expect(parse("--attributes", "a", "b", "c")["attributes"]).to eq(%w[a b c])
373
380
  end
374
381
 
375
382
  it "must not mix values with other switches" do
376
- expect(parse("--attributes", "a", "b", "c", "--baz", "cool")["attributes"]).to eq(["a", "b", "c"])
383
+ expect(parse("--attributes", "a", "b", "c", "--baz", "cool")["attributes"]).to eq(%w[a b c])
377
384
  end
378
385
  end
379
386
 
@@ -387,12 +394,19 @@ describe Thor::Options do
387
394
  end
388
395
 
389
396
  it "converts values to numeric types" do
390
- expect(parse("-n", "3", "-m", ".5")).to eq({"n" => 3, "m" => 0.5})
397
+ expect(parse("-n", "3", "-m", ".5")).to eq("n" => 3, "m" => 0.5)
391
398
  end
392
399
 
393
400
  it "raises error when value isn't numeric" do
394
- expect{ parse("-n", "foo") }.to raise_error(Thor::MalformattedArgumentError,
395
- "Expected numeric value for '-n'; got \"foo\"")
401
+ expect { parse("-n", "foo") }.to raise_error(Thor::MalformattedArgumentError,
402
+ "Expected numeric value for '-n'; got \"foo\"")
403
+ end
404
+
405
+ it "raises error when value isn't in enum" do
406
+ enum = [1, 2]
407
+ create :limit => Thor::Option.new("limit", :type => :numeric, :enum => enum)
408
+ expect { parse("--limit", "3") }.to raise_error(Thor::MalformattedArgumentError,
409
+ "Expected '--limit' to be one of #{enum.join(', ')}; got 3")
396
410
  end
397
411
  end
398
412