thor 0.16.0 → 0.17.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.
- data/.rspec +1 -0
- data/.travis.yml +2 -1
- data/CHANGELOG.rdoc +8 -0
- data/Gemfile +12 -8
- data/lib/thor.rb +79 -10
- data/lib/thor/actions.rb +13 -13
- data/lib/thor/actions/directory.rb +29 -10
- data/lib/thor/actions/file_manipulation.rb +8 -2
- data/lib/thor/base.rb +24 -11
- data/lib/thor/core_ext/hash_with_indifferent_access.rb +5 -0
- data/lib/thor/group.rb +5 -5
- data/lib/thor/parser/options.rb +63 -25
- data/lib/thor/rake_compat.rb +3 -2
- data/lib/thor/runner.rb +1 -1
- data/lib/thor/shell/basic.rb +16 -16
- data/lib/thor/shell/color.rb +9 -9
- data/lib/thor/shell/html.rb +9 -9
- data/lib/thor/task.rb +2 -2
- data/lib/thor/version.rb +1 -1
- data/spec/actions/create_file_spec.rb +30 -30
- data/spec/actions/create_link_spec.rb +12 -12
- data/spec/actions/directory_spec.rb +34 -27
- data/spec/actions/empty_directory_spec.rb +16 -16
- data/spec/actions/file_manipulation_spec.rb +62 -50
- data/spec/actions/inject_into_file_spec.rb +18 -18
- data/spec/actions_spec.rb +56 -56
- data/spec/base_spec.rb +69 -69
- data/spec/core_ext/hash_with_indifferent_access_spec.rb +19 -14
- data/spec/core_ext/ordered_hash_spec.rb +29 -29
- data/spec/exit_condition_spec.rb +3 -3
- data/spec/fixtures/preserve/script.sh +3 -0
- data/spec/fixtures/script.thor +5 -0
- data/spec/group_spec.rb +55 -55
- data/spec/invocation_spec.rb +26 -26
- data/spec/parser/argument_spec.rb +12 -12
- data/spec/parser/arguments_spec.rb +12 -12
- data/spec/parser/option_spec.rb +47 -47
- data/spec/parser/options_spec.rb +137 -72
- data/spec/rake_compat_spec.rb +11 -11
- data/spec/register_spec.rb +70 -8
- data/spec/runner_spec.rb +38 -38
- data/spec/shell/basic_spec.rb +49 -37
- data/spec/shell/color_spec.rb +13 -13
- data/spec/shell/html_spec.rb +3 -3
- data/spec/shell_spec.rb +7 -7
- data/spec/spec_helper.rb +4 -0
- data/spec/task_spec.rb +11 -11
- data/spec/thor_spec.rb +161 -91
- data/spec/util_spec.rb +42 -42
- data/thor.gemspec +1 -7
- metadata +8 -118
- data/lib/thor/core_ext/dir_escape.rb +0 -0
data/spec/shell/color_spec.rb
CHANGED
@@ -11,7 +11,7 @@ describe Thor::Shell::Color do
|
|
11
11
|
shell.say "Wow! Now we have colors!", :green
|
12
12
|
end
|
13
13
|
|
14
|
-
out.chomp.
|
14
|
+
expect(out.chomp).to eq("\e[32mWow! Now we have colors!\e[0m")
|
15
15
|
end
|
16
16
|
|
17
17
|
it "does not use a new line even with colors" do
|
@@ -19,7 +19,7 @@ describe Thor::Shell::Color do
|
|
19
19
|
shell.say "Wow! Now we have colors! ", :green
|
20
20
|
end
|
21
21
|
|
22
|
-
out.chomp.
|
22
|
+
expect(out.chomp).to eq("\e[32mWow! Now we have colors! \e[0m")
|
23
23
|
end
|
24
24
|
|
25
25
|
it "handles an Array of colors" do
|
@@ -27,7 +27,7 @@ describe Thor::Shell::Color do
|
|
27
27
|
shell.say "Wow! Now we have colors *and* background colors", [:green, :on_red, :bold]
|
28
28
|
end
|
29
29
|
|
30
|
-
out.chomp.
|
30
|
+
expect(out.chomp).to eq("\e[32m\e[41m\e[1mWow! Now we have colors *and* background colors\e[0m")
|
31
31
|
end
|
32
32
|
end
|
33
33
|
|
@@ -37,30 +37,30 @@ describe Thor::Shell::Color do
|
|
37
37
|
shell.say_status :conflict, "README", :red
|
38
38
|
end
|
39
39
|
|
40
|
-
out.chomp.
|
40
|
+
expect(out.chomp).to eq("\e[1m\e[31m conflict\e[0m README")
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
44
44
|
describe "#set_color" do
|
45
45
|
it "colors a string with a foreground color" do
|
46
46
|
red = shell.set_color "hi!", :red
|
47
|
-
red.
|
47
|
+
expect(red).to eq("\e[31mhi!\e[0m")
|
48
48
|
end
|
49
49
|
|
50
50
|
it "colors a string with a background color" do
|
51
51
|
on_red = shell.set_color "hi!", :white, :on_red
|
52
|
-
on_red.
|
52
|
+
expect(on_red).to eq("\e[37m\e[41mhi!\e[0m")
|
53
53
|
end
|
54
54
|
|
55
55
|
it "colors a string with a bold color" do
|
56
56
|
bold = shell.set_color "hi!", :white, true
|
57
|
-
bold.
|
57
|
+
expect(bold).to eq("\e[1m\e[37mhi!\e[0m")
|
58
58
|
|
59
59
|
bold = shell.set_color "hi!", :white, :bold
|
60
|
-
bold.
|
60
|
+
expect(bold).to eq("\e[37m\e[1mhi!\e[0m")
|
61
61
|
|
62
62
|
bold = shell.set_color "hi!", :white, :on_red, :bold
|
63
|
-
bold.
|
63
|
+
expect(bold).to eq("\e[37m\e[41m\e[1mhi!\e[0m")
|
64
64
|
end
|
65
65
|
end
|
66
66
|
|
@@ -71,10 +71,10 @@ describe Thor::Shell::Color do
|
|
71
71
|
$stdin.should_receive(:gets).and_return('d')
|
72
72
|
$stdin.should_receive(:gets).and_return('n')
|
73
73
|
|
74
|
-
output = capture(:stdout){ shell.file_collision('spec/fixtures/doc/README'){ "README\nEND\n" } }
|
75
|
-
output.
|
76
|
-
output.
|
77
|
-
output.
|
74
|
+
output = capture(:stdout) { shell.file_collision('spec/fixtures/doc/README'){ "README\nEND\n" } }
|
75
|
+
expect(output).to match(/\e\[31m\- __start__\e\[0m/)
|
76
|
+
expect(output).to match(/^ README/)
|
77
|
+
expect(output).to match(/\e\[32m\+ END\e\[0m/)
|
78
78
|
end
|
79
79
|
end
|
80
80
|
end
|
data/spec/shell/html_spec.rb
CHANGED
@@ -8,17 +8,17 @@ describe Thor::Shell::HTML do
|
|
8
8
|
describe "#say" do
|
9
9
|
it "set the color if specified" do
|
10
10
|
out = capture(:stdout) { shell.say "Wow! Now we have colors!", :green }
|
11
|
-
out.chomp.
|
11
|
+
expect(out.chomp).to eq('<span style="color: green;">Wow! Now we have colors!</span>')
|
12
12
|
end
|
13
13
|
|
14
14
|
it "sets bold if specified" do
|
15
15
|
out = capture(:stdout) { shell.say "Wow! Now we have colors *and* bold!", [:green, :bold] }
|
16
|
-
out.chomp.
|
16
|
+
expect(out.chomp).to eq('<span style="color: green; font-weight: bold;">Wow! Now we have colors *and* bold!</span>')
|
17
17
|
end
|
18
18
|
|
19
19
|
it "does not use a new line even with colors" do
|
20
20
|
out = capture(:stdout) { shell.say "Wow! Now we have colors! ", :green }
|
21
|
-
out.chomp.
|
21
|
+
expect(out.chomp).to eq('<span style="color: green;">Wow! Now we have colors! </span>')
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
data/spec/shell_spec.rb
CHANGED
@@ -8,30 +8,30 @@ describe Thor::Shell do
|
|
8
8
|
describe "#initialize" do
|
9
9
|
it "sets shell value" do
|
10
10
|
base = MyCounter.new [1, 2], { }, :shell => shell
|
11
|
-
base.shell.
|
11
|
+
expect(base.shell).to eq(shell)
|
12
12
|
end
|
13
13
|
|
14
14
|
it "sets the base value on the shell if an accessor is available" do
|
15
15
|
base = MyCounter.new [1, 2], { }, :shell => shell
|
16
|
-
shell.base.
|
16
|
+
expect(shell.base).to eq(base)
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
20
|
describe "#shell" do
|
21
21
|
it "returns the shell in use" do
|
22
|
-
MyCounter.new([1,2]).shell.
|
22
|
+
expect(MyCounter.new([1,2]).shell).to be_kind_of(Thor::Base.shell)
|
23
23
|
end
|
24
24
|
|
25
25
|
it "uses $THOR_SHELL" do
|
26
26
|
class Thor::Shell::TestShell < Thor::Shell::Basic; end
|
27
27
|
|
28
|
-
Thor::Base.shell.
|
28
|
+
expect(Thor::Base.shell).to eq(shell.class)
|
29
29
|
ENV['THOR_SHELL'] = 'TestShell'
|
30
30
|
Thor::Base.shell = nil
|
31
|
-
Thor::Base.shell.
|
31
|
+
expect(Thor::Base.shell).to eq(Thor::Shell::TestShell)
|
32
32
|
ENV['THOR_SHELL'] = ''
|
33
33
|
Thor::Base.shell = shell.class
|
34
|
-
Thor::Base.shell.
|
34
|
+
expect(Thor::Base.shell).to eq(shell.class)
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
@@ -39,7 +39,7 @@ describe Thor::Shell do
|
|
39
39
|
it "uses padding for inside block outputs" do
|
40
40
|
base = MyCounter.new([1,2])
|
41
41
|
base.with_padding do
|
42
|
-
capture(:stdout){ base.say_status :padding, "cool" }.strip.
|
42
|
+
expect(capture(:stdout) { base.say_status :padding, "cool" }.strip).to eq("padding cool")
|
43
43
|
end
|
44
44
|
end
|
45
45
|
end
|
data/spec/spec_helper.rb
CHANGED
data/spec/task_spec.rb
CHANGED
@@ -12,32 +12,32 @@ describe Thor::Task do
|
|
12
12
|
describe "#formatted_usage" do
|
13
13
|
it "includes namespace within usage" do
|
14
14
|
object = Struct.new(:namespace, :arguments).new("foo", [])
|
15
|
-
task(:bar => :required).formatted_usage(object).
|
15
|
+
expect(task(:bar => :required).formatted_usage(object)).to eq("foo:can_has --bar=BAR")
|
16
16
|
end
|
17
17
|
|
18
18
|
it "includes subcommand name within subcommand usage" do
|
19
19
|
object = Struct.new(:namespace, :arguments).new("main:foo", [])
|
20
|
-
task(:bar => :required).formatted_usage(object, false, true).
|
20
|
+
expect(task(:bar => :required).formatted_usage(object, false, true)).to eq("foo can_has --bar=BAR")
|
21
21
|
end
|
22
22
|
|
23
23
|
it "removes default from namespace" do
|
24
24
|
object = Struct.new(:namespace, :arguments).new("default:foo", [])
|
25
|
-
task(:bar => :required).formatted_usage(object).
|
25
|
+
expect(task(:bar => :required).formatted_usage(object)).to eq(":foo:can_has --bar=BAR")
|
26
26
|
end
|
27
27
|
|
28
28
|
it "injects arguments into usage" do
|
29
29
|
options = {:required => true, :type => :string}
|
30
30
|
object = Struct.new(:namespace, :arguments).new("foo", [Thor::Argument.new(:bar, options)])
|
31
|
-
task(:foo => :required).formatted_usage(object).
|
31
|
+
expect(task(:foo => :required).formatted_usage(object)).to eq("foo:can_has BAR --foo=FOO")
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
35
35
|
describe "#dynamic" do
|
36
36
|
it "creates a dynamic task with the given name" do
|
37
|
-
Thor::DynamicTask.new('task').name.
|
38
|
-
Thor::DynamicTask.new('task').description.
|
39
|
-
Thor::DynamicTask.new('task').usage.
|
40
|
-
Thor::DynamicTask.new('task').options.
|
37
|
+
expect(Thor::DynamicTask.new('task').name).to eq('task')
|
38
|
+
expect(Thor::DynamicTask.new('task').description).to eq('A dynamically-generated task')
|
39
|
+
expect(Thor::DynamicTask.new('task').usage).to eq('task')
|
40
|
+
expect(Thor::DynamicTask.new('task').options).to eq({})
|
41
41
|
end
|
42
42
|
|
43
43
|
it "does not invoke an existing method" do
|
@@ -51,7 +51,7 @@ describe Thor::Task do
|
|
51
51
|
it "dup options hash" do
|
52
52
|
task = Thor::Task.new("can_has", nil, nil, nil, :foo => true, :bar => :required)
|
53
53
|
task.dup.options.delete(:foo)
|
54
|
-
task.options[:foo].
|
54
|
+
expect(task.options[:foo]).to be
|
55
55
|
end
|
56
56
|
end
|
57
57
|
|
@@ -59,7 +59,7 @@ describe Thor::Task do
|
|
59
59
|
it "runs a task by calling a method in the given instance" do
|
60
60
|
mock = mock()
|
61
61
|
mock.should_receive(:can_has).and_return {|*args| args }
|
62
|
-
task.run(mock, [1, 2, 3]).
|
62
|
+
expect(task.run(mock, [1, 2, 3])).to eq([1, 2, 3])
|
63
63
|
end
|
64
64
|
|
65
65
|
it "raises an error if the method to be invoked is private" do
|
@@ -74,7 +74,7 @@ describe Thor::Task do
|
|
74
74
|
end
|
75
75
|
end
|
76
76
|
|
77
|
-
task.run(klass.new).
|
77
|
+
expect(task.run(klass.new)).to eq("can_has")
|
78
78
|
end
|
79
79
|
end
|
80
80
|
end
|
data/spec/thor_spec.rb
CHANGED
@@ -5,67 +5,67 @@ describe Thor do
|
|
5
5
|
it "sets options to the next method to be invoked" do
|
6
6
|
args = ["foo", "bar", "--force"]
|
7
7
|
arg, options = MyScript.start(args)
|
8
|
-
options.
|
8
|
+
expect(options).to eq({ "force" => true })
|
9
9
|
end
|
10
10
|
|
11
11
|
describe ":lazy_default" do
|
12
12
|
it "is absent when option is not specified" do
|
13
13
|
arg, options = MyScript.start(["with_optional"])
|
14
|
-
options.
|
14
|
+
expect(options).to eq({})
|
15
15
|
end
|
16
16
|
|
17
17
|
it "sets a default that can be overridden for strings" do
|
18
18
|
arg, options = MyScript.start(["with_optional", "--lazy"])
|
19
|
-
options.
|
19
|
+
expect(options).to eq({ "lazy" => "yes" })
|
20
20
|
|
21
21
|
arg, options = MyScript.start(["with_optional", "--lazy", "yesyes!"])
|
22
|
-
options.
|
22
|
+
expect(options).to eq({ "lazy" => "yesyes!" })
|
23
23
|
end
|
24
24
|
|
25
25
|
it "sets a default that can be overridden for numerics" do
|
26
26
|
arg, options = MyScript.start(["with_optional", "--lazy-numeric"])
|
27
|
-
options.
|
27
|
+
expect(options).to eq({ "lazy_numeric" => 42 })
|
28
28
|
|
29
29
|
arg, options = MyScript.start(["with_optional", "--lazy-numeric", 20000])
|
30
|
-
options.
|
30
|
+
expect(options).to eq({ "lazy_numeric" => 20000 })
|
31
31
|
end
|
32
32
|
|
33
33
|
it "sets a default that can be overridden for arrays" do
|
34
34
|
arg, options = MyScript.start(["with_optional", "--lazy-array"])
|
35
|
-
options.
|
35
|
+
expect(options).to eq({ "lazy_array" => %w[eat at joes] })
|
36
36
|
|
37
37
|
arg, options = MyScript.start(["with_optional", "--lazy-array", "hello", "there"])
|
38
|
-
options.
|
38
|
+
expect(options).to eq({ "lazy_array" => %w[hello there] })
|
39
39
|
end
|
40
40
|
|
41
41
|
it "sets a default that can be overridden for hashes" do
|
42
42
|
arg, options = MyScript.start(["with_optional", "--lazy-hash"])
|
43
|
-
options.
|
43
|
+
expect(options).to eq({ "lazy_hash" => {'swedish' => 'meatballs'} })
|
44
44
|
|
45
45
|
arg, options = MyScript.start(["with_optional", "--lazy-hash", "polish:sausage"])
|
46
|
-
options.
|
46
|
+
expect(options).to eq({ "lazy_hash" => {'polish' => 'sausage'} })
|
47
47
|
end
|
48
48
|
end
|
49
49
|
|
50
50
|
describe "when :for is supplied" do
|
51
51
|
it "updates an already defined task" do
|
52
52
|
args, options = MyChildScript.start(["animal", "horse", "--other=fish"])
|
53
|
-
options[:other].
|
53
|
+
expect(options[:other]).to eq("fish")
|
54
54
|
end
|
55
55
|
|
56
56
|
describe "and the target is on the parent class" do
|
57
57
|
it "updates an already defined task" do
|
58
58
|
args = ["example_default_task", "my_param", "--new-option=verified"]
|
59
59
|
options = Scripts::MyScript.start(args)
|
60
|
-
options[:new_option].
|
60
|
+
expect(options[:new_option]).to eq("verified")
|
61
61
|
end
|
62
62
|
|
63
63
|
it "adds a task to the tasks list if the updated task is on the parent class" do
|
64
|
-
Scripts::MyScript.tasks["example_default_task"].
|
64
|
+
expect(Scripts::MyScript.tasks["example_default_task"]).to be
|
65
65
|
end
|
66
66
|
|
67
67
|
it "clones the parent task" do
|
68
|
-
Scripts::MyScript.tasks["example_default_task"].
|
68
|
+
expect(Scripts::MyScript.tasks["example_default_task"]).not_to eq(MyChildScript.tasks["example_default_task"])
|
69
69
|
end
|
70
70
|
end
|
71
71
|
end
|
@@ -73,48 +73,114 @@ describe Thor do
|
|
73
73
|
|
74
74
|
describe "#default_task" do
|
75
75
|
it "sets a default task" do
|
76
|
-
MyScript.default_task.
|
76
|
+
expect(MyScript.default_task).to eq("example_default_task")
|
77
77
|
end
|
78
78
|
|
79
79
|
it "invokes the default task if no command is specified" do
|
80
|
-
MyScript.start([]).
|
80
|
+
expect(MyScript.start([])).to eq("default task")
|
81
81
|
end
|
82
82
|
|
83
83
|
it "invokes the default task if no command is specified even if switches are given" do
|
84
|
-
MyScript.start(["--with", "option"]).
|
84
|
+
expect(MyScript.start(["--with", "option"])).to eq({"with"=>"option"})
|
85
85
|
end
|
86
86
|
|
87
87
|
it "inherits the default task from parent" do
|
88
|
-
MyChildScript.default_task.
|
88
|
+
expect(MyChildScript.default_task).to eq("example_default_task")
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
describe "#stop_on_unknown_option!" do
|
93
|
+
my_script = Class.new(Thor) do
|
94
|
+
class_option "verbose", :type => :boolean
|
95
|
+
class_option "mode", :type => :string
|
96
|
+
|
97
|
+
stop_on_unknown_option! :exec
|
98
|
+
|
99
|
+
desc "exec", "Run a command"
|
100
|
+
def exec(*args)
|
101
|
+
return options, args
|
102
|
+
end
|
103
|
+
|
104
|
+
desc "boring", "An ordinary task"
|
105
|
+
def boring(*args)
|
106
|
+
return options, args
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
it "passes remaining args to task when it encounters a non-option" do
|
111
|
+
expect(my_script.start(%w[exec command --verbose])).to eq [{}, ["command", "--verbose"]]
|
112
|
+
end
|
113
|
+
|
114
|
+
it "passes remaining args to task when it encounters an unknown option" do
|
115
|
+
expect(my_script.start(%w[exec --foo command --bar])).to eq [{}, ["--foo", "command", "--bar"]]
|
116
|
+
end
|
117
|
+
|
118
|
+
it "still accepts options that are given before non-options" do
|
119
|
+
expect(my_script.start(%w[exec --verbose command --foo])).to eq [{"verbose" => true}, ["command", "--foo"]]
|
120
|
+
end
|
121
|
+
|
122
|
+
it "still accepts options that require a value" do
|
123
|
+
expect(my_script.start(%w[exec --mode rashly command])).to eq [{"mode" => "rashly"}, ["command"]]
|
124
|
+
end
|
125
|
+
|
126
|
+
it "still passes everything after -- to task" do
|
127
|
+
expect(my_script.start(%w[exec -- --verbose])).to eq [{}, ["--verbose"]]
|
128
|
+
end
|
129
|
+
|
130
|
+
it "does not affect ordinary tasks" do
|
131
|
+
expect(my_script.start(%w[boring command --verbose])).to eq [{"verbose" => true}, ["command"]]
|
132
|
+
end
|
133
|
+
|
134
|
+
context "when provided with multiple task names" do
|
135
|
+
klass = Class.new(Thor) do
|
136
|
+
stop_on_unknown_option! :foo, :bar
|
137
|
+
end
|
138
|
+
it "affects all specified tasks" do
|
139
|
+
expect(klass.stop_on_unknown_option?(mock :name => "foo")).to be_true
|
140
|
+
expect(klass.stop_on_unknown_option?(mock :name => "bar")).to be_true
|
141
|
+
expect(klass.stop_on_unknown_option?(mock :name => "baz")).to be_false
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
context "when invoked several times" do
|
146
|
+
klass = Class.new(Thor) do
|
147
|
+
stop_on_unknown_option! :foo
|
148
|
+
stop_on_unknown_option! :bar
|
149
|
+
end
|
150
|
+
it "affects all specified tasks" do
|
151
|
+
expect(klass.stop_on_unknown_option?(mock :name => "foo")).to be_true
|
152
|
+
expect(klass.stop_on_unknown_option?(mock :name => "bar")).to be_true
|
153
|
+
expect(klass.stop_on_unknown_option?(mock :name => "baz")).to be_false
|
154
|
+
end
|
89
155
|
end
|
90
156
|
end
|
91
157
|
|
92
158
|
describe "#map" do
|
93
159
|
it "calls the alias of a method if one is provided" do
|
94
|
-
MyScript.start(["-T", "fish"]).
|
160
|
+
expect(MyScript.start(["-T", "fish"])).to eq(["fish"])
|
95
161
|
end
|
96
162
|
|
97
163
|
it "calls the alias of a method if several are provided via .map" do
|
98
|
-
MyScript.start(["-f", "fish"]).
|
99
|
-
MyScript.start(["--foo", "fish"]).
|
164
|
+
expect(MyScript.start(["-f", "fish"])).to eq(["fish", {}])
|
165
|
+
expect(MyScript.start(["--foo", "fish"])).to eq(["fish", {}])
|
100
166
|
end
|
101
167
|
|
102
168
|
it "inherits all mappings from parent" do
|
103
|
-
MyChildScript.default_task.
|
169
|
+
expect(MyChildScript.default_task).to eq("example_default_task")
|
104
170
|
end
|
105
171
|
end
|
106
172
|
|
107
173
|
describe "#desc" do
|
108
174
|
it "provides description for a task" do
|
109
175
|
content = capture(:stdout) { MyScript.start(["help"]) }
|
110
|
-
content.
|
176
|
+
expect(content).to match(/thor my_script:zoo\s+# zoo around/m)
|
111
177
|
end
|
112
178
|
|
113
179
|
it "provides no namespace if $thor_runner is false" do
|
114
180
|
begin
|
115
181
|
$thor_runner = false
|
116
182
|
content = capture(:stdout) { MyScript.start(["help"]) }
|
117
|
-
content.
|
183
|
+
expect(content).to match(/thor zoo\s+# zoo around/m)
|
118
184
|
ensure
|
119
185
|
$thor_runner = true
|
120
186
|
end
|
@@ -122,17 +188,17 @@ describe Thor do
|
|
122
188
|
|
123
189
|
describe "when :for is supplied" do
|
124
190
|
it "overwrites a previous defined task" do
|
125
|
-
capture(:stdout) { MyChildScript.start(["help"]) }.
|
191
|
+
expect(capture(:stdout) { MyChildScript.start(["help"]) }).to match(/animal KIND \s+# fish around/m)
|
126
192
|
end
|
127
193
|
end
|
128
194
|
|
129
195
|
describe "when :hide is supplied" do
|
130
196
|
it "does not show the task in help" do
|
131
|
-
capture(:stdout) { MyScript.start(["help"]) }.
|
197
|
+
expect(capture(:stdout) { MyScript.start(["help"]) }).not_to match(/this is hidden/m)
|
132
198
|
end
|
133
199
|
|
134
200
|
it "but the task is still invokcable not show the task in help" do
|
135
|
-
MyScript.start(["hidden", "yesyes"]).
|
201
|
+
expect(MyScript.start(["hidden", "yesyes"])).to eq(["yesyes"])
|
136
202
|
end
|
137
203
|
end
|
138
204
|
end
|
@@ -140,83 +206,83 @@ describe Thor do
|
|
140
206
|
describe "#method_options" do
|
141
207
|
it "sets default options if called before an initializer" do
|
142
208
|
options = MyChildScript.class_options
|
143
|
-
options[:force].type.
|
144
|
-
options[:param].type.
|
209
|
+
expect(options[:force].type).to eq(:boolean)
|
210
|
+
expect(options[:param].type).to eq(:numeric)
|
145
211
|
end
|
146
212
|
|
147
213
|
it "overwrites default options if called on the method scope" do
|
148
214
|
args = ["zoo", "--force", "--param", "feathers"]
|
149
215
|
options = MyChildScript.start(args)
|
150
|
-
options.
|
216
|
+
expect(options).to eq({ "force" => true, "param" => "feathers" })
|
151
217
|
end
|
152
218
|
|
153
219
|
it "allows default options to be merged with method options" do
|
154
220
|
args = ["animal", "bird", "--force", "--param", "1.0", "--other", "tweets"]
|
155
221
|
arg, options = MyChildScript.start(args)
|
156
|
-
arg.
|
157
|
-
options.
|
222
|
+
expect(arg).to eq('bird')
|
223
|
+
expect(options).to eq({ "force"=>true, "param"=>1.0, "other"=>"tweets" })
|
158
224
|
end
|
159
225
|
end
|
160
226
|
|
161
227
|
describe "#start" do
|
162
228
|
it "calls a no-param method when no params are passed" do
|
163
|
-
MyScript.start(["zoo"]).
|
229
|
+
expect(MyScript.start(["zoo"])).to eq(true)
|
164
230
|
end
|
165
231
|
|
166
232
|
it "calls a single-param method when a single param is passed" do
|
167
|
-
MyScript.start(["animal", "fish"]).
|
233
|
+
expect(MyScript.start(["animal", "fish"])).to eq(["fish"])
|
168
234
|
end
|
169
235
|
|
170
236
|
it "does not set options in attributes" do
|
171
|
-
MyScript.start(["with_optional", "--all"]).
|
237
|
+
expect(MyScript.start(["with_optional", "--all"])).to eq([nil, { "all" => true }, []])
|
172
238
|
end
|
173
239
|
|
174
240
|
it "raises an error if a required param is not provided" do
|
175
|
-
capture(:stderr) { MyScript.start(["animal"]) }.strip.
|
241
|
+
expect(capture(:stderr) { MyScript.start(["animal"]) }.strip).to eq('thor animal requires at least 1 argument: "thor my_script:animal TYPE".')
|
176
242
|
end
|
177
243
|
|
178
244
|
it "raises an error if the invoked task does not exist" do
|
179
|
-
capture(:stderr) { Amazing.start(["animal"]) }.strip.
|
245
|
+
expect(capture(:stderr) { Amazing.start(["animal"]) }.strip).to eq('Could not find task "animal" in "amazing" namespace.')
|
180
246
|
end
|
181
247
|
|
182
248
|
it "calls method_missing if an unknown method is passed in" do
|
183
|
-
MyScript.start(["unk", "hello"]).
|
249
|
+
expect(MyScript.start(["unk", "hello"])).to eq([:unk, ["hello"]])
|
184
250
|
end
|
185
251
|
|
186
252
|
it "does not call a private method no matter what" do
|
187
|
-
capture(:stderr) { MyScript.start(["what"]) }.strip.
|
253
|
+
expect(capture(:stderr) { MyScript.start(["what"]) }.strip).to eq('Could not find task "what" in "my_script" namespace.')
|
188
254
|
end
|
189
255
|
|
190
256
|
it "uses task default options" do
|
191
257
|
options = MyChildScript.start(["animal", "fish"]).last
|
192
|
-
options.
|
258
|
+
expect(options).to eq({ "other" => "method default" })
|
193
259
|
end
|
194
260
|
|
195
261
|
it "raises when an exception happens within the task call" do
|
196
|
-
|
262
|
+
expect{ MyScript.start(["call_myself_with_wrong_arity"]) }.to raise_error(ArgumentError)
|
197
263
|
end
|
198
264
|
|
199
265
|
context "when the user enters an unambiguous substring of a command" do
|
200
|
-
it "
|
201
|
-
MyScript.start(["z"]).
|
266
|
+
it "invokes a command" do
|
267
|
+
expect(MyScript.start(["z"])).to eq(MyScript.start(["zoo"]))
|
202
268
|
end
|
203
269
|
|
204
|
-
it "
|
205
|
-
MyScript.start(["hi"]).
|
270
|
+
it "invokes a command, even when there's an alias the resolves to the same command" do
|
271
|
+
expect(MyScript.start(["hi"])).to eq(MyScript.start(["hidden"]))
|
206
272
|
end
|
207
273
|
|
208
|
-
it "
|
209
|
-
MyScript.start(["animal_pri"]).
|
274
|
+
it "invokes an alias" do
|
275
|
+
expect(MyScript.start(["animal_pri"])).to eq(MyScript.start(["zoo"]))
|
210
276
|
end
|
211
277
|
end
|
212
278
|
|
213
279
|
context "when the user enters an ambiguous substring of a command" do
|
214
|
-
it "
|
215
|
-
|
280
|
+
it "raises an exception that explains the ambiguity" do
|
281
|
+
expect{ MyScript.start(["call"]) }.to raise_error(ArgumentError, 'Ambiguous task call matches [call_myself_with_wrong_arity, call_unexistent_method]')
|
216
282
|
end
|
217
283
|
|
218
|
-
it "
|
219
|
-
|
284
|
+
it "raises an exception when there is an alias" do
|
285
|
+
expect{ MyScript.start(["f"]) }.to raise_error(ArgumentError, 'Ambiguous task f matches [foo, fu]')
|
220
286
|
end
|
221
287
|
end
|
222
288
|
|
@@ -224,20 +290,20 @@ describe Thor do
|
|
224
290
|
|
225
291
|
describe "#subcommand" do
|
226
292
|
it "maps a given subcommand to another Thor subclass" do
|
227
|
-
barn_help = capture(:stdout){ Scripts::MyDefaults.start(["barn"]) }
|
228
|
-
barn_help.
|
293
|
+
barn_help = capture(:stdout) { Scripts::MyDefaults.start(["barn"]) }
|
294
|
+
expect(barn_help).to include("barn help [COMMAND] # Describe subcommands or one specific subcommand")
|
229
295
|
end
|
230
296
|
|
231
297
|
it "passes commands to subcommand classes" do
|
232
|
-
capture(:stdout){ Scripts::MyDefaults.start(["barn", "open"]) }.strip.
|
298
|
+
expect(capture(:stdout) { Scripts::MyDefaults.start(["barn", "open"]) }.strip).to eq("Open sesame!")
|
233
299
|
end
|
234
300
|
|
235
301
|
it "passes arguments to subcommand classes" do
|
236
|
-
capture(:stdout){ Scripts::MyDefaults.start(["barn", "open", "shotgun"]) }.strip.
|
302
|
+
expect(capture(:stdout) { Scripts::MyDefaults.start(["barn", "open", "shotgun"]) }.strip).to eq("That's going to leave a mark.")
|
237
303
|
end
|
238
304
|
|
239
305
|
it "ignores unknown options (the subcommand class will handle them)" do
|
240
|
-
capture(:stdout){ Scripts::MyDefaults.start(["barn", "paint", "blue", "--coats", "4"])}.strip.
|
306
|
+
expect(capture(:stdout) { Scripts::MyDefaults.start(["barn", "paint", "blue", "--coats", "4"])}.strip).to eq("4 coats of blue paint")
|
241
307
|
end
|
242
308
|
end
|
243
309
|
|
@@ -248,47 +314,47 @@ describe Thor do
|
|
248
314
|
|
249
315
|
describe "on general" do
|
250
316
|
before do
|
251
|
-
@content = capture(:stdout){ MyScript.help(shell) }
|
317
|
+
@content = capture(:stdout) { MyScript.help(shell) }
|
252
318
|
end
|
253
319
|
|
254
320
|
it "provides useful help info for the help method itself" do
|
255
|
-
@content.
|
321
|
+
expect(@content).to match(/help \[TASK\]\s+# Describe available tasks/)
|
256
322
|
end
|
257
323
|
|
258
324
|
it "provides useful help info for a method with params" do
|
259
|
-
@content.
|
325
|
+
expect(@content).to match(/animal TYPE\s+# horse around/)
|
260
326
|
end
|
261
327
|
|
262
328
|
it "uses the maximum terminal size to show tasks" do
|
263
329
|
@shell.should_receive(:terminal_width).and_return(80)
|
264
|
-
content = capture(:stdout){ MyScript.help(shell) }
|
265
|
-
content.
|
330
|
+
content = capture(:stdout) { MyScript.help(shell) }
|
331
|
+
expect(content).to match(/aaa\.\.\.$/)
|
266
332
|
end
|
267
333
|
|
268
334
|
it "provides description for tasks from classes in the same namespace" do
|
269
|
-
@content.
|
335
|
+
expect(@content).to match(/baz\s+# do some bazing/)
|
270
336
|
end
|
271
337
|
|
272
338
|
it "shows superclass tasks" do
|
273
|
-
content = capture(:stdout){ MyChildScript.help(shell) }
|
274
|
-
content.
|
339
|
+
content = capture(:stdout) { MyChildScript.help(shell) }
|
340
|
+
expect(content).to match(/foo BAR \s+# do some fooing/)
|
275
341
|
end
|
276
342
|
|
277
343
|
it "shows class options information" do
|
278
|
-
content = capture(:stdout){ MyChildScript.help(shell) }
|
279
|
-
content.
|
280
|
-
content.
|
344
|
+
content = capture(:stdout) { MyChildScript.help(shell) }
|
345
|
+
expect(content).to match(/Options\:/)
|
346
|
+
expect(content).to match(/\[\-\-param=N\]/)
|
281
347
|
end
|
282
348
|
|
283
349
|
it "injects class arguments into default usage" do
|
284
|
-
content = capture(:stdout){ Scripts::MyScript.help(shell) }
|
285
|
-
content.
|
350
|
+
content = capture(:stdout) { Scripts::MyScript.help(shell) }
|
351
|
+
expect(content).to match(/zoo ACCESSOR \-\-param\=PARAM/)
|
286
352
|
end
|
287
353
|
end
|
288
354
|
|
289
355
|
describe "for a specific task" do
|
290
356
|
it "provides full help info when talking about a specific task" do
|
291
|
-
capture(:stdout) { MyScript.task_help(shell, "foo") }.
|
357
|
+
expect(capture(:stdout) { MyScript.task_help(shell, "foo") }).to eq(<<-END)
|
292
358
|
Usage:
|
293
359
|
thor my_script:foo BAR
|
294
360
|
|
@@ -302,17 +368,17 @@ END
|
|
302
368
|
end
|
303
369
|
|
304
370
|
it "raises an error if the task can't be found" do
|
305
|
-
|
371
|
+
expect {
|
306
372
|
MyScript.task_help(shell, "unknown")
|
307
|
-
}.
|
373
|
+
}.to raise_error(Thor::UndefinedTaskError, 'Could not find task "unknown" in "my_script" namespace.')
|
308
374
|
end
|
309
375
|
|
310
376
|
it "normalizes names before claiming they don't exist" do
|
311
|
-
capture(:stdout) { MyScript.task_help(shell, "name-with-dashes") }.
|
377
|
+
expect(capture(:stdout) { MyScript.task_help(shell, "name-with-dashes") }).to match(/thor my_script:name-with-dashes/)
|
312
378
|
end
|
313
379
|
|
314
380
|
it "uses the long description if it exists" do
|
315
|
-
capture(:stdout) { MyScript.task_help(shell, "long_description") }.
|
381
|
+
expect(capture(:stdout) { MyScript.task_help(shell, "long_description") }).to eq(<<-HELP)
|
316
382
|
Usage:
|
317
383
|
thor my_script:long_description
|
318
384
|
|
@@ -324,36 +390,36 @@ HELP
|
|
324
390
|
end
|
325
391
|
|
326
392
|
it "doesn't assign the long description to the next task without one" do
|
327
|
-
capture(:stdout)
|
393
|
+
expect(capture(:stdout) {
|
328
394
|
MyScript.task_help(shell, "name_with_dashes")
|
329
|
-
|
395
|
+
}).not_to match(/so very long/i)
|
330
396
|
end
|
331
397
|
end
|
332
398
|
|
333
399
|
describe "instance method" do
|
334
400
|
it "calls the class method" do
|
335
|
-
capture(:stdout){ MyScript.start(["help"]) }.
|
401
|
+
expect(capture(:stdout) { MyScript.start(["help"]) }).to match(/Tasks:/)
|
336
402
|
end
|
337
403
|
|
338
404
|
it "calls the class method" do
|
339
|
-
capture(:stdout){ MyScript.start(["help", "foo"]) }.
|
405
|
+
expect(capture(:stdout) { MyScript.start(["help", "foo"]) }).to match(/Usage:/)
|
340
406
|
end
|
341
407
|
end
|
342
408
|
end
|
343
409
|
|
344
410
|
describe "when creating tasks" do
|
345
411
|
it "prints a warning if a public method is created without description or usage" do
|
346
|
-
capture(:stdout) {
|
412
|
+
expect(capture(:stdout) {
|
347
413
|
klass = Class.new(Thor)
|
348
414
|
klass.class_eval "def hello_from_thor; end"
|
349
|
-
}.
|
415
|
+
}).to match(/\[WARNING\] Attempted to create task "hello_from_thor" without usage or description/)
|
350
416
|
end
|
351
417
|
|
352
418
|
it "does not print if overwriting a previous task" do
|
353
|
-
capture(:stdout) {
|
419
|
+
expect(capture(:stdout) {
|
354
420
|
klass = Class.new(Thor)
|
355
421
|
klass.class_eval "def help; end"
|
356
|
-
}.
|
422
|
+
}).to be_empty
|
357
423
|
end
|
358
424
|
end
|
359
425
|
|
@@ -368,9 +434,9 @@ HELP
|
|
368
434
|
end
|
369
435
|
end
|
370
436
|
|
371
|
-
klass.start(["hi", "jose"]).
|
372
|
-
klass.start(["hi", "jose", "--loud"]).
|
373
|
-
klass.start(["hi", "--loud", "jose"]).
|
437
|
+
expect(klass.start(["hi", "jose"])).to eq("Hi jose")
|
438
|
+
expect(klass.start(["hi", "jose", "--loud"])).to eq("Hi JOSE")
|
439
|
+
expect(klass.start(["hi", "--loud", "jose"])).to eq("Hi JOSE")
|
374
440
|
end
|
375
441
|
|
376
442
|
it "passes through unknown options" do
|
@@ -381,8 +447,8 @@ HELP
|
|
381
447
|
end
|
382
448
|
end
|
383
449
|
|
384
|
-
klass.start(["unknown", "foo", "--bar", "baz", "bat", "--bam"]).
|
385
|
-
klass.start(["unknown", "--bar", "baz"]).
|
450
|
+
expect(klass.start(["unknown", "foo", "--bar", "baz", "bat", "--bam"])).to eq(["foo", "--bar", "baz", "bat", "--bam"])
|
451
|
+
expect(klass.start(["unknown", "--bar", "baz"])).to eq(["--bar", "baz"])
|
386
452
|
end
|
387
453
|
|
388
454
|
it "does not pass through unknown options with strict args" do
|
@@ -395,8 +461,8 @@ HELP
|
|
395
461
|
end
|
396
462
|
end
|
397
463
|
|
398
|
-
klass.start(["unknown", "--bar", "baz"]).
|
399
|
-
klass.start(["unknown", "foo", "--bar", "baz"]).
|
464
|
+
expect(klass.start(["unknown", "--bar", "baz"])).to eq([])
|
465
|
+
expect(klass.start(["unknown", "foo", "--bar", "baz"])).to eq(["foo"])
|
400
466
|
end
|
401
467
|
|
402
468
|
it "strict args works in the inheritance chain" do
|
@@ -411,8 +477,12 @@ HELP
|
|
411
477
|
end
|
412
478
|
end
|
413
479
|
|
414
|
-
klass.start(["unknown", "--bar", "baz"]).
|
415
|
-
klass.start(["unknown", "foo", "--bar", "baz"]).
|
480
|
+
expect(klass.start(["unknown", "--bar", "baz"])).to eq([])
|
481
|
+
expect(klass.start(["unknown", "foo", "--bar", "baz"])).to eq(["foo"])
|
482
|
+
end
|
483
|
+
|
484
|
+
it "send as a task name" do
|
485
|
+
expect(MyScript.start(["send"])).to eq(true)
|
416
486
|
end
|
417
487
|
end
|
418
488
|
end
|