thor 0.19.1 → 0.19.2

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 (105) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +24 -0
  3. data/CONTRIBUTING.md +15 -0
  4. data/README.md +7 -1
  5. data/lib/thor.rb +31 -23
  6. data/lib/thor/actions.rb +21 -22
  7. data/lib/thor/actions/create_file.rb +1 -1
  8. data/lib/thor/actions/create_link.rb +1 -1
  9. data/lib/thor/actions/directory.rb +2 -2
  10. data/lib/thor/actions/empty_directory.rb +8 -8
  11. data/lib/thor/actions/file_manipulation.rb +23 -12
  12. data/lib/thor/actions/inject_into_file.rb +10 -14
  13. data/lib/thor/base.rb +33 -33
  14. data/lib/thor/command.rb +9 -9
  15. data/lib/thor/core_ext/hash_with_indifferent_access.rb +9 -1
  16. data/lib/thor/core_ext/io_binary_read.rb +7 -5
  17. data/lib/thor/core_ext/ordered_hash.rb +94 -63
  18. data/lib/thor/error.rb +3 -3
  19. data/lib/thor/group.rb +12 -12
  20. data/lib/thor/invocation.rb +4 -5
  21. data/lib/thor/parser/argument.rb +4 -7
  22. data/lib/thor/parser/arguments.rb +16 -16
  23. data/lib/thor/parser/option.rb +39 -19
  24. data/lib/thor/parser/options.rb +7 -5
  25. data/lib/thor/runner.rb +25 -25
  26. data/lib/thor/shell.rb +1 -1
  27. data/lib/thor/shell/basic.rb +41 -26
  28. data/lib/thor/shell/color.rb +1 -1
  29. data/lib/thor/shell/html.rb +4 -4
  30. data/lib/thor/util.rb +8 -7
  31. data/lib/thor/version.rb +1 -1
  32. data/thor.gemspec +6 -9
  33. metadata +6 -148
  34. data/Thorfile +0 -29
  35. data/spec/actions/create_file_spec.rb +0 -168
  36. data/spec/actions/create_link_spec.rb +0 -96
  37. data/spec/actions/directory_spec.rb +0 -169
  38. data/spec/actions/empty_directory_spec.rb +0 -129
  39. data/spec/actions/file_manipulation_spec.rb +0 -392
  40. data/spec/actions/inject_into_file_spec.rb +0 -135
  41. data/spec/actions_spec.rb +0 -331
  42. data/spec/base_spec.rb +0 -298
  43. data/spec/command_spec.rb +0 -79
  44. data/spec/core_ext/hash_with_indifferent_access_spec.rb +0 -48
  45. data/spec/core_ext/ordered_hash_spec.rb +0 -115
  46. data/spec/exit_condition_spec.rb +0 -19
  47. data/spec/fixtures/application.rb +0 -2
  48. data/spec/fixtures/app{1}/README +0 -3
  49. data/spec/fixtures/bundle/execute.rb +0 -6
  50. data/spec/fixtures/bundle/main.thor +0 -1
  51. data/spec/fixtures/command.thor +0 -10
  52. data/spec/fixtures/doc/%file_name%.rb.tt +0 -1
  53. data/spec/fixtures/doc/COMMENTER +0 -11
  54. data/spec/fixtures/doc/README +0 -3
  55. data/spec/fixtures/doc/block_helper.rb +0 -3
  56. data/spec/fixtures/doc/config.rb +0 -1
  57. data/spec/fixtures/doc/config.yaml.tt +0 -1
  58. data/spec/fixtures/doc/excluding/%file_name%.rb.tt +0 -1
  59. data/spec/fixtures/enum.thor +0 -10
  60. data/spec/fixtures/group.thor +0 -128
  61. data/spec/fixtures/invoke.thor +0 -131
  62. data/spec/fixtures/path with spaces b/data/spec/fixtures/path with → spaces +0 -0
  63. data/spec/fixtures/preserve/script.sh +0 -3
  64. data/spec/fixtures/script.thor +0 -220
  65. data/spec/fixtures/subcommand.thor +0 -17
  66. data/spec/group_spec.rb +0 -222
  67. data/spec/helper.rb +0 -80
  68. data/spec/invocation_spec.rb +0 -120
  69. data/spec/line_editor/basic_spec.rb +0 -28
  70. data/spec/line_editor/readline_spec.rb +0 -69
  71. data/spec/line_editor_spec.rb +0 -43
  72. data/spec/parser/argument_spec.rb +0 -53
  73. data/spec/parser/arguments_spec.rb +0 -66
  74. data/spec/parser/option_spec.rb +0 -210
  75. data/spec/parser/options_spec.rb +0 -414
  76. data/spec/quality_spec.rb +0 -75
  77. data/spec/rake_compat_spec.rb +0 -72
  78. data/spec/register_spec.rb +0 -227
  79. data/spec/runner_spec.rb +0 -246
  80. data/spec/sandbox/application.rb +0 -2
  81. data/spec/sandbox/app{1}/README +0 -3
  82. data/spec/sandbox/bundle/execute.rb +0 -6
  83. data/spec/sandbox/bundle/main.thor +0 -1
  84. data/spec/sandbox/command.thor +0 -10
  85. data/spec/sandbox/doc/%file_name%.rb.tt +0 -1
  86. data/spec/sandbox/doc/COMMENTER +0 -11
  87. data/spec/sandbox/doc/README +0 -3
  88. data/spec/sandbox/doc/block_helper.rb +0 -3
  89. data/spec/sandbox/doc/config.rb +0 -1
  90. data/spec/sandbox/doc/config.yaml.tt +0 -1
  91. data/spec/sandbox/doc/excluding/%file_name%.rb.tt +0 -1
  92. data/spec/sandbox/enum.thor +0 -10
  93. data/spec/sandbox/group.thor +0 -128
  94. data/spec/sandbox/invoke.thor +0 -131
  95. data/spec/sandbox/path with spaces b/data/spec/sandbox/path with → spaces +0 -0
  96. data/spec/sandbox/preserve/script.sh +0 -3
  97. data/spec/sandbox/script.thor +0 -220
  98. data/spec/sandbox/subcommand.thor +0 -17
  99. data/spec/shell/basic_spec.rb +0 -337
  100. data/spec/shell/color_spec.rb +0 -119
  101. data/spec/shell/html_spec.rb +0 -31
  102. data/spec/shell_spec.rb +0 -47
  103. data/spec/subcommand_spec.rb +0 -48
  104. data/spec/thor_spec.rb +0 -505
  105. data/spec/util_spec.rb +0 -196
@@ -1,69 +0,0 @@
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
@@ -1,43 +0,0 @@
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,53 +0,0 @@
1
- require "helper"
2
- require "thor/parser"
3
-
4
- describe Thor::Argument do
5
-
6
- def argument(name, options = {})
7
- @argument ||= Thor::Argument.new(name, options)
8
- end
9
-
10
- describe "errors" do
11
- it "raises an error if name is not supplied" do
12
- expect do
13
- argument(nil)
14
- end.to raise_error(ArgumentError, "Argument name can't be nil.")
15
- end
16
-
17
- it "raises an error if type is unknown" do
18
- expect do
19
- argument(:command, :type => :unknown)
20
- end.to raise_error(ArgumentError, "Type :unknown is not valid for arguments.")
21
- end
22
-
23
- it "raises an error if argument is required and has default values" do
24
- expect do
25
- argument(:command, :type => :string, :default => "bar", :required => true)
26
- end.to raise_error(ArgumentError, "An argument cannot be required and have default value.")
27
- end
28
-
29
- it "raises an error if enum isn't an array" do
30
- expect do
31
- argument(:command, :type => :string, :enum => "bar")
32
- end.to raise_error(ArgumentError, "An argument cannot have an enum other than an array.")
33
- end
34
- end
35
-
36
- describe "#usage" do
37
- it "returns usage for string types" do
38
- expect(argument(:foo, :type => :string).usage).to eq("FOO")
39
- end
40
-
41
- it "returns usage for numeric types" do
42
- expect(argument(:foo, :type => :numeric).usage).to eq("N")
43
- end
44
-
45
- it "returns usage for array types" do
46
- expect(argument(:foo, :type => :array).usage).to eq("one two three")
47
- end
48
-
49
- it "returns usage for hash types" do
50
- expect(argument(:foo, :type => :hash).usage).to eq("key:value")
51
- end
52
- end
53
- end
@@ -1,66 +0,0 @@
1
- require "helper"
2
- require "thor/parser"
3
-
4
- describe Thor::Arguments do
5
- def create(opts = {})
6
- arguments = opts.map do |type, default|
7
- options = {:required => default.nil?, :type => type, :default => default}
8
- Thor::Argument.new(type.to_s, options)
9
- end
10
-
11
- arguments.sort! { |a, b| b.name <=> a.name }
12
- @opt = Thor::Arguments.new(arguments)
13
- end
14
-
15
- def parse(*args)
16
- @opt.parse(args)
17
- end
18
-
19
- describe "#parse" do
20
- it "parses arguments in the given order" do
21
- create :string => nil, :numeric => nil
22
- expect(parse("name", "13")["string"]).to eq("name")
23
- expect(parse("name", "13")["numeric"]).to eq(13)
24
- end
25
-
26
- it "accepts hashes" do
27
- create :string => nil, :hash => nil
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")
31
- end
32
-
33
- it "accepts arrays" do
34
- create :string => nil, :array => nil
35
- expect(parse("product", "title", "age")["string"]).to eq("product")
36
- expect(parse("product", "title", "age")["array"]).to eq(%w[title age])
37
- end
38
-
39
- describe "with no inputs" do
40
- it "and no arguments returns an empty hash" do
41
- create
42
- expect(parse).to eq({})
43
- end
44
-
45
- it "and required arguments raises an error" do
46
- create :string => nil, :numeric => nil
47
- expect { parse }.to raise_error(Thor::RequiredArgumentMissingError, "No value provided for required arguments 'string', 'numeric'")
48
- end
49
-
50
- it "and default arguments returns default values" do
51
- create :string => "name", :numeric => 13
52
- expect(parse).to eq("string" => "name", "numeric" => 13)
53
- end
54
- end
55
-
56
- it "returns the input if it's already parsed" do
57
- create :string => nil, :hash => nil, :array => nil, :numeric => nil
58
- expect(parse("", 0, {}, [])).to eq("string" => "", "numeric" => 0, "hash" => {}, "array" => [])
59
- end
60
-
61
- it "returns the default value if none is provided" do
62
- create :string => "foo", :numeric => 3.0
63
- expect(parse("bar")).to eq("string" => "bar", "numeric" => 3.0)
64
- end
65
- end
66
- end
@@ -1,210 +0,0 @@
1
- require "helper"
2
- require "thor/parser"
3
-
4
- describe Thor::Option do
5
- def parse(key, value)
6
- Thor::Option.parse(key, value)
7
- end
8
-
9
- def option(name, options = {})
10
- @option ||= Thor::Option.new(name, options)
11
- end
12
-
13
- describe "#parse" do
14
-
15
- describe "with value as a symbol" do
16
- describe "and symbol is a valid type" do
17
- it "has type equals to the symbol" do
18
- expect(parse(:foo, :string).type).to eq(:string)
19
- expect(parse(:foo, :numeric).type).to eq(:numeric)
20
- end
21
-
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
- end
26
- end
27
-
28
- describe "equals to :required" do
29
- it "has type equals to :string" do
30
- expect(parse(:foo, :required).type).to eq(:string)
31
- end
32
-
33
- it "has no default value" do
34
- expect(parse(:foo, :required).default).to be nil
35
- end
36
- end
37
-
38
- describe "and symbol is not a reserved key" do
39
- it "has type equal to :string" do
40
- expect(parse(:foo, :bar).type).to eq(:string)
41
- end
42
-
43
- it "has no default value" do
44
- expect(parse(:foo, :bar).default).to be nil
45
- end
46
- end
47
- end
48
-
49
- describe "with value as hash" do
50
- it "has default type :hash" do
51
- expect(parse(:foo, :a => :b).type).to eq(:hash)
52
- end
53
-
54
- it "has default value equal to the hash" do
55
- expect(parse(:foo, :a => :b).default).to eq(:a => :b)
56
- end
57
- end
58
-
59
- describe "with value as array" do
60
- it "has default type :array" do
61
- expect(parse(:foo, [:a, :b]).type).to eq(:array)
62
- end
63
-
64
- it "has default value equal to the array" do
65
- expect(parse(:foo, [:a, :b]).default).to eq([:a, :b])
66
- end
67
- end
68
-
69
- describe "with value as string" do
70
- it "has default type :string" do
71
- expect(parse(:foo, "bar").type).to eq(:string)
72
- end
73
-
74
- it "has default value equal to the string" do
75
- expect(parse(:foo, "bar").default).to eq("bar")
76
- end
77
- end
78
-
79
- describe "with value as numeric" do
80
- it "has default type :numeric" do
81
- expect(parse(:foo, 2.0).type).to eq(:numeric)
82
- end
83
-
84
- it "has default value equal to the numeric" do
85
- expect(parse(:foo, 2.0).default).to eq(2.0)
86
- end
87
- end
88
-
89
- describe "with value as boolean" do
90
- it "has default type :boolean" do
91
- expect(parse(:foo, true).type).to eq(:boolean)
92
- expect(parse(:foo, false).type).to eq(:boolean)
93
- end
94
-
95
- it "has default value equal to the boolean" do
96
- expect(parse(:foo, true).default).to eq(true)
97
- expect(parse(:foo, false).default).to eq(false)
98
- end
99
- end
100
-
101
- describe "with key as a symbol" do
102
- it "sets the name equal to the key" do
103
- expect(parse(:foo, true).name).to eq("foo")
104
- end
105
- end
106
-
107
- describe "with key as an array" do
108
- it "sets the first items in the array to the name" do
109
- expect(parse([:foo, :bar, :baz], true).name).to eq("foo")
110
- end
111
-
112
- it "sets all other items as aliases" do
113
- expect(parse([:foo, :bar, :baz], true).aliases).to eq([:bar, :baz])
114
- end
115
- end
116
- end
117
-
118
- it "returns the switch name" do
119
- expect(option("foo").switch_name).to eq("--foo")
120
- expect(option("--foo").switch_name).to eq("--foo")
121
- end
122
-
123
- it "returns the human name" do
124
- expect(option("foo").human_name).to eq("foo")
125
- expect(option("--foo").human_name).to eq("foo")
126
- end
127
-
128
- it "converts underscores to dashes" do
129
- expect(option("foo_bar").switch_name).to eq("--foo-bar")
130
- end
131
-
132
- it "can be required and have default values" do
133
- option = option("foo", :required => true, :type => :string, :default => "bar")
134
- expect(option.default).to eq("bar")
135
- expect(option).to be_required
136
- end
137
-
138
- it "boolean options cannot be required" do
139
- expect do
140
- option("foo", :required => true, :type => :boolean)
141
- end.to raise_error(ArgumentError, "An option cannot be boolean and required.")
142
- end
143
-
144
- it "allows type predicates" do
145
- expect(parse(:foo, :string)).to be_string
146
- expect(parse(:foo, :boolean)).to be_boolean
147
- expect(parse(:foo, :numeric)).to be_numeric
148
- end
149
-
150
- it "raises an error on method missing" do
151
- expect do
152
- parse(:foo, :string).unknown?
153
- end.to raise_error(NoMethodError)
154
- end
155
-
156
- describe "#usage" do
157
-
158
- it "returns usage for string types" do
159
- expect(parse(:foo, :string).usage).to eq("[--foo=FOO]")
160
- end
161
-
162
- it "returns usage for numeric types" do
163
- expect(parse(:foo, :numeric).usage).to eq("[--foo=N]")
164
- end
165
-
166
- it "returns usage for array types" do
167
- expect(parse(:foo, :array).usage).to eq("[--foo=one two three]")
168
- end
169
-
170
- it "returns usage for hash types" do
171
- expect(parse(:foo, :hash).usage).to eq("[--foo=key:value]")
172
- end
173
-
174
- it "returns usage for boolean types" do
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]")
180
- end
181
-
182
- it "documents a negative option when boolean" do
183
- expect(parse(:foo, :boolean).usage).to include("[--no-foo]")
184
- end
185
-
186
- it "uses banner when supplied" do
187
- expect(option(:foo, :required => false, :type => :string, :banner => "BAR").usage).to eq("[--foo=BAR]")
188
- end
189
-
190
- it "checks when banner is an empty string" do
191
- expect(option(:foo, :required => false, :type => :string, :banner => "").usage).to eq("[--foo]")
192
- end
193
-
194
- describe "with required values" do
195
- it "does not show the usage between brackets" do
196
- expect(parse(:foo, :required).usage).to eq("--foo=FOO")
197
- end
198
- end
199
-
200
- describe "with aliases" do
201
- it "does not show the usage between brackets" do
202
- expect(parse([:foo, "-f", "-b"], :required).usage).to eq("-f, -b, --foo=FOO")
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
208
- end
209
- end
210
- end
@@ -1,414 +0,0 @@
1
- require "helper"
2
- require "thor/parser"
3
-
4
- describe Thor::Options do
5
- def create(opts, defaults = {}, stop_on_unknown = false)
6
- opts.each do |key, value|
7
- opts[key] = Thor::Option.parse(key, value) unless value.is_a?(Thor::Option)
8
- end
9
-
10
- @opt = Thor::Options.new(opts, defaults, stop_on_unknown)
11
- end
12
-
13
- def parse(*args)
14
- @opt.parse(args.flatten)
15
- end
16
-
17
- def check_unknown!
18
- @opt.check_unknown!
19
- end
20
-
21
- def remaining
22
- @opt.remaining
23
- end
24
-
25
- describe "#to_switches" do
26
- it "turns true values into a flag" do
27
- expect(Thor::Options.to_switches(:color => true)).to eq("--color")
28
- end
29
-
30
- it "ignores nil" do
31
- expect(Thor::Options.to_switches(:color => nil)).to eq("")
32
- end
33
-
34
- it "ignores false" do
35
- expect(Thor::Options.to_switches(:color => false)).to eq("")
36
- end
37
-
38
- it "writes --name value for anything else" do
39
- expect(Thor::Options.to_switches(:format => "specdoc")).to eq('--format "specdoc"')
40
- end
41
-
42
- it "joins several values" do
43
- switches = Thor::Options.to_switches(:color => true, :foo => "bar").split(" ").sort
44
- expect(switches).to eq(%w["bar" --color --foo])
45
- end
46
-
47
- it "accepts arrays" do
48
- expect(Thor::Options.to_switches(:count => [1, 2, 3])).to eq("--count 1 2 3")
49
- end
50
-
51
- it "accepts hashes" do
52
- expect(Thor::Options.to_switches(:count => {:a => :b})).to eq("--count a:b")
53
- end
54
-
55
- it "accepts underscored options" do
56
- expect(Thor::Options.to_switches(:under_score_option => "foo bar")).to eq('--under_score_option "foo bar"')
57
- end
58
-
59
- end
60
-
61
- describe "#parse" do
62
- it "allows multiple aliases for a given switch" do
63
- create %w[--foo --bar --baz] => :string
64
- expect(parse("--foo", "12")["foo"]).to eq("12")
65
- expect(parse("--bar", "12")["foo"]).to eq("12")
66
- expect(parse("--baz", "12")["foo"]).to eq("12")
67
- end
68
-
69
- it "allows custom short names" do
70
- create "-f" => :string
71
- expect(parse("-f", "12")).to eq("f" => "12")
72
- end
73
-
74
- it "allows custom short-name aliases" do
75
- create %w[--bar -f] => :string
76
- expect(parse("-f", "12")).to eq("bar" => "12")
77
- end
78
-
79
- it "accepts conjoined short switches" do
80
- create %w[--foo -f] => true, %w[--bar -b] => true, %w[--app -a] => true
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
85
- end
86
-
87
- it "accepts conjoined short switches with input" do
88
- create %w[--foo -f] => true, %w[--bar -b] => true, %w[--app -a] => :required
89
- opts = parse "-fba", "12"
90
- expect(opts["foo"]).to be true
91
- expect(opts["bar"]).to be true
92
- expect(opts["app"]).to eq("12")
93
- end
94
-
95
- it "returns the default value if none is provided" do
96
- create :foo => "baz", :bar => :required
97
- expect(parse("--bar", "boom")["foo"]).to eq("baz")
98
- end
99
-
100
- it "returns the default value from defaults hash to required arguments" do
101
- create Hash[:bar => :required], Hash[:bar => "baz"]
102
- expect(parse["bar"]).to eq("baz")
103
- end
104
-
105
- it "gives higher priority to defaults given in the hash" do
106
- create Hash[:bar => true], Hash[:bar => false]
107
- expect(parse["bar"]).to eq(false)
108
- end
109
-
110
- it "raises an error for unknown switches" do
111
- create :foo => "baz", :bar => :required
112
- parse("--bar", "baz", "--baz", "unknown")
113
- expect { check_unknown! }.to raise_error(Thor::UnknownArgumentError, "Unknown switches '--baz'")
114
- end
115
-
116
- it "skips leading non-switches" do
117
- create(:foo => "baz")
118
-
119
- expect(parse("asdf", "--foo", "bar")).to eq("foo" => "bar")
120
- end
121
-
122
- it "correctly recognizes things that look kind of like options, but aren't, as not options" do
123
- create(:foo => "baz")
124
- expect(parse("--asdf---asdf", "baz", "--foo", "--asdf---dsf--asdf")).to eq("foo" => "--asdf---dsf--asdf")
125
- check_unknown!
126
- end
127
-
128
- it "accepts underscores in commandline args hash for boolean" do
129
- create :foo_bar => :boolean
130
- expect(parse("--foo_bar")["foo_bar"]).to eq(true)
131
- expect(parse("--no_foo_bar")["foo_bar"]).to eq(false)
132
- end
133
-
134
- it "accepts underscores in commandline args hash for strings" do
135
- create :foo_bar => :string, :baz_foo => :string
136
- expect(parse("--foo_bar", "baz")["foo_bar"]).to eq("baz")
137
- expect(parse("--baz_foo", "foo bar")["baz_foo"]).to eq("foo bar")
138
- end
139
-
140
- it "interprets everything after -- as args instead of options" do
141
- create(:foo => :string, :bar => :required)
142
- expect(parse(%w[--bar abc moo -- --foo def -a])).to eq("bar" => "abc")
143
- expect(remaining).to eq(%w[moo --foo def -a])
144
- end
145
-
146
- it "ignores -- when looking for single option values" do
147
- create(:foo => :string, :bar => :required)
148
- expect(parse(%w[--bar -- --foo def -a])).to eq("bar" => "--foo")
149
- expect(remaining).to eq(%w[def -a])
150
- end
151
-
152
- it "ignores -- when looking for array option values" do
153
- create(:foo => :array)
154
- expect(parse(%w[--foo a b -- c d -e])).to eq("foo" => %w[a b c d -e])
155
- expect(remaining).to eq([])
156
- end
157
-
158
- it "ignores -- when looking for hash option values" do
159
- create(:foo => :hash)
160
- expect(parse(%w[--foo a:b -- c:d -e])).to eq("foo" => {"a" => "b", "c" => "d"})
161
- expect(remaining).to eq(%w[-e])
162
- end
163
-
164
- it "ignores trailing --" do
165
- create(:foo => :string)
166
- expect(parse(%w[--foo --])).to eq("foo" => nil)
167
- expect(remaining).to eq([])
168
- end
169
-
170
- describe "with no input" do
171
- it "and no switches returns an empty hash" do
172
- create({})
173
- expect(parse).to eq({})
174
- end
175
-
176
- it "and several switches returns an empty hash" do
177
- create "--foo" => :boolean, "--bar" => :string
178
- expect(parse).to eq({})
179
- end
180
-
181
- it "and a required switch raises an error" do
182
- create "--foo" => :required
183
- expect { parse }.to raise_error(Thor::RequiredArgumentMissingError, "No value provided for required options '--foo'")
184
- end
185
- end
186
-
187
- describe "with one required and one optional switch" do
188
- before do
189
- create "--foo" => :required, "--bar" => :boolean
190
- end
191
-
192
- it "raises an error if the required switch has no argument" do
193
- expect { parse("--foo") }.to raise_error(Thor::MalformattedArgumentError)
194
- end
195
-
196
- it "raises an error if the required switch isn't given" do
197
- expect { parse("--bar") }.to raise_error(Thor::RequiredArgumentMissingError)
198
- end
199
-
200
- it "raises an error if the required switch is set to nil" do
201
- expect { parse("--no-foo") }.to raise_error(Thor::RequiredArgumentMissingError)
202
- end
203
-
204
- it "does not raises an error if the required option has a default value" do
205
- options = {:required => true, :type => :string, :default => "baz"}
206
- create :foo => Thor::Option.new("foo", options), :bar => :boolean
207
- expect { parse("--bar") }.not_to raise_error
208
- end
209
- end
210
-
211
- context "when stop_on_unknown is true" do
212
- before do
213
- create({:foo => :string, :verbose => :boolean}, {}, true)
214
- end
215
-
216
- it "stops parsing on first non-option" do
217
- expect(parse(%w[foo --verbose])).to eq({})
218
- expect(remaining).to eq(%w[foo --verbose])
219
- end
220
-
221
- it "stops parsing on unknown option" do
222
- expect(parse(%w[--bar --verbose])).to eq({})
223
- expect(remaining).to eq(%w[--bar --verbose])
224
- end
225
-
226
- it "retains -- after it has stopped parsing" do
227
- expect(parse(%w[--bar -- whatever])).to eq({})
228
- expect(remaining).to eq(%w[--bar -- whatever])
229
- end
230
-
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(%w[foo])
234
- end
235
-
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(%w[baz])
239
- end
240
-
241
- it "still interprets everything after -- as args instead of options" do
242
- expect(parse(%w[-- --verbose])).to eq({})
243
- expect(remaining).to eq(%w[--verbose])
244
- end
245
- end
246
-
247
- describe "with :string type" do
248
- before do
249
- create %w[--foo -f] => :required
250
- end
251
-
252
- it "accepts a switch <value> assignment" do
253
- expect(parse("--foo", "12")["foo"]).to eq("12")
254
- end
255
-
256
- it "accepts a switch=<value> assignment" do
257
- expect(parse("-f=12")["foo"]).to eq("12")
258
- expect(parse("--foo=12")["foo"]).to eq("12")
259
- expect(parse("--foo=bar=baz")["foo"]).to eq("bar=baz")
260
- end
261
-
262
- it "must accept underscores switch=value assignment" do
263
- create :foo_bar => :required
264
- expect(parse("--foo_bar=http://example.com/under_score/")["foo_bar"]).to eq("http://example.com/under_score/")
265
- end
266
-
267
- it "accepts a --no-switch format" do
268
- create "--foo" => "bar"
269
- expect(parse("--no-foo")["foo"]).to be nil
270
- end
271
-
272
- it "does not consume an argument for --no-switch format" do
273
- create "--cheese" => :string
274
- expect(parse("burger", "--no-cheese", "fries")["cheese"]).to be nil
275
- end
276
-
277
- it "accepts a --switch format on non required types" do
278
- create "--foo" => :string
279
- expect(parse("--foo")["foo"]).to eq("foo")
280
- end
281
-
282
- it "accepts a --switch format on non required types with default values" do
283
- create "--baz" => :string, "--foo" => "bar"
284
- expect(parse("--baz", "bang", "--foo")["foo"]).to eq("bar")
285
- end
286
-
287
- it "overwrites earlier values with later values" do
288
- expect(parse("--foo=bar", "--foo", "12")["foo"]).to eq("12")
289
- expect(parse("--foo", "12", "--foo", "13")["foo"]).to eq("13")
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
298
- end
299
-
300
- describe "with :boolean type" do
301
- before do
302
- create "--foo" => false
303
- end
304
-
305
- it "accepts --opt assignment" do
306
- expect(parse("--foo")["foo"]).to eq(true)
307
- expect(parse("--foo", "--bar")["foo"]).to eq(true)
308
- end
309
-
310
- it "uses the default value if no switch is given" do
311
- expect(parse("")["foo"]).to eq(false)
312
- end
313
-
314
- it "accepts --opt=value assignment" do
315
- expect(parse("--foo=true")["foo"]).to eq(true)
316
- expect(parse("--foo=false")["foo"]).to eq(false)
317
- end
318
-
319
- it "accepts --[no-]opt variant, setting false for value" do
320
- expect(parse("--no-foo")["foo"]).to eq(false)
321
- end
322
-
323
- it "accepts --[skip-]opt variant, setting false for value" do
324
- expect(parse("--skip-foo")["foo"]).to eq(false)
325
- end
326
-
327
- it "will prefer 'no-opt' variant over inverting 'opt' if explicitly set" do
328
- create "--no-foo" => true
329
- expect(parse("--no-foo")["no-foo"]).to eq(true)
330
- end
331
-
332
- it "will prefer 'skip-opt' variant over inverting 'opt' if explicitly set" do
333
- create "--skip-foo" => true
334
- expect(parse("--skip-foo")["skip-foo"]).to eq(true)
335
- end
336
-
337
- it "accepts inputs in the human name format" do
338
- create :foo_bar => :boolean
339
- expect(parse("--foo-bar")["foo_bar"]).to eq(true)
340
- expect(parse("--no-foo-bar")["foo_bar"]).to eq(false)
341
- expect(parse("--skip-foo-bar")["foo_bar"]).to eq(false)
342
- end
343
-
344
- it "doesn't eat the next part of the param" do
345
- create :foo => :boolean
346
- expect(parse("--foo", "bar")).to eq("foo" => true)
347
- expect(@opt.remaining).to eq(%w[bar])
348
- end
349
- end
350
-
351
- describe "with :hash type" do
352
- before do
353
- create "--attributes" => :hash
354
- end
355
-
356
- it "accepts a switch=<value> assignment" do
357
- expect(parse("--attributes=name:string", "age:integer")["attributes"]).to eq("name" => "string", "age" => "integer")
358
- end
359
-
360
- it "accepts a switch <value> assignment" do
361
- expect(parse("--attributes", "name:string", "age:integer")["attributes"]).to eq("name" => "string", "age" => "integer")
362
- end
363
-
364
- it "must not mix values with other switches" do
365
- expect(parse("--attributes", "name:string", "age:integer", "--baz", "cool")["attributes"]).to eq("name" => "string", "age" => "integer")
366
- end
367
- end
368
-
369
- describe "with :array type" do
370
- before do
371
- create "--attributes" => :array
372
- end
373
-
374
- it "accepts a switch=<value> assignment" do
375
- expect(parse("--attributes=a", "b", "c")["attributes"]).to eq(%w[a b c])
376
- end
377
-
378
- it "accepts a switch <value> assignment" do
379
- expect(parse("--attributes", "a", "b", "c")["attributes"]).to eq(%w[a b c])
380
- end
381
-
382
- it "must not mix values with other switches" do
383
- expect(parse("--attributes", "a", "b", "c", "--baz", "cool")["attributes"]).to eq(%w[a b c])
384
- end
385
- end
386
-
387
- describe "with :numeric type" do
388
- before do
389
- create "n" => :numeric, "m" => 5
390
- end
391
-
392
- it "accepts a -nXY assignment" do
393
- expect(parse("-n12")["n"]).to eq(12)
394
- end
395
-
396
- it "converts values to numeric types" do
397
- expect(parse("-n", "3", "-m", ".5")).to eq("n" => 3, "m" => 0.5)
398
- end
399
-
400
- it "raises error when value isn't numeric" do
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")
410
- end
411
- end
412
-
413
- end
414
- end