thor 0.18.1 → 0.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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