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,17 +0,0 @@
1
- module TestSubcommands
2
-
3
- class Subcommand < Thor
4
- desc "print_opt", "My method"
5
- def print_opt
6
- print options["opt"]
7
- end
8
- end
9
-
10
- class Parent < Thor
11
- class_option "opt"
12
-
13
- desc "sub", "My subcommand"
14
- subcommand "sub", Subcommand
15
- end
16
-
17
- end
@@ -1,222 +0,0 @@
1
- require "helper"
2
-
3
- describe Thor::Group do
4
- describe "command" do
5
- it "allows to use private methods from parent class as commands" do
6
- expect(ChildGroup.start).to eq(%w[bar foo baz])
7
- expect(ChildGroup.new.baz("bar")).to eq("bar")
8
- end
9
- end
10
-
11
- describe "#start" do
12
- it "invokes all the commands under the Thor group" do
13
- expect(MyCounter.start(%w[1 2 --third 3])).to eq([1, 2, 3, nil, nil, nil])
14
- end
15
-
16
- it "uses argument's default value" do
17
- expect(MyCounter.start(%w[1 --third 3])).to eq([1, 2, 3, nil, nil, nil])
18
- end
19
-
20
- it "invokes all the commands in the Thor group and its parents" do
21
- expect(BrokenCounter.start(%w[1 2 --third 3])).to eq([nil, 2, 3, false, 5, nil])
22
- end
23
-
24
- it "raises an error if a required argument is added after a non-required" do
25
- expect do
26
- MyCounter.argument(:foo, :type => :string)
27
- end.to raise_error(ArgumentError, 'You cannot have "foo" as required argument after the non-required argument "second".')
28
- end
29
-
30
- it "raises when an exception happens within the command call" do
31
- expect { BrokenCounter.start(%w[1 2 --fail]) }.to raise_error
32
- end
33
-
34
- it "raises an error when a Thor group command expects arguments" do
35
- expect { WhinyGenerator.start }.to raise_error(ArgumentError, /thor wrong_arity takes 1 argument, but it should not/)
36
- end
37
-
38
- it "invokes help message if any of the shortcuts are given" do
39
- expect(MyCounter).to receive(:help)
40
- MyCounter.start(%w[-h])
41
- end
42
- end
43
-
44
- describe "#desc" do
45
- it "sets the description for a given class" do
46
- expect(MyCounter.desc).to eq("Description:\n This generator runs three commands: one, two and three.\n")
47
- end
48
-
49
- it "can be inherited" do
50
- expect(BrokenCounter.desc).to eq("Description:\n This generator runs three commands: one, two and three.\n")
51
- end
52
-
53
- it "can be nil" do
54
- expect(WhinyGenerator.desc).to be nil
55
- end
56
- end
57
-
58
- describe "#help" do
59
- before do
60
- @content = capture(:stdout) { MyCounter.help(Thor::Base.shell.new) }
61
- end
62
-
63
- it "provides usage information" do
64
- expect(@content).to match(/my_counter N \[N\]/)
65
- end
66
-
67
- it "shows description" do
68
- expect(@content).to match(/Description:/)
69
- expect(@content).to match(/This generator runs three commands: one, two and three./)
70
- end
71
-
72
- it "shows options information" do
73
- expect(@content).to match(/Options/)
74
- expect(@content).to match(/\[\-\-third=THREE\]/)
75
- end
76
- end
77
-
78
- describe "#invoke" do
79
- before do
80
- @content = capture(:stdout) { E.start }
81
- end
82
-
83
- it "allows to invoke a class from the class binding" do
84
- expect(@content).to match(/1\n2\n3\n4\n5\n/)
85
- end
86
-
87
- it "shows invocation information to the user" do
88
- expect(@content).to match(/invoke Defined/)
89
- end
90
-
91
- it "uses padding on status generated by the invoked class" do
92
- expect(@content).to match(/finished counting/)
93
- end
94
-
95
- it "allows invocation to be configured with blocks" do
96
- capture(:stdout) do
97
- expect(F.start).to eq(["Valim, Jose"])
98
- end
99
- end
100
-
101
- it "shows invoked options on help" do
102
- content = capture(:stdout) { E.help(Thor::Base.shell.new) }
103
- expect(content).to match(/Defined options:/)
104
- expect(content).to match(/\[--unused\]/)
105
- expect(content).to match(/# This option has no use/)
106
- end
107
- end
108
-
109
- describe "#invoke_from_option" do
110
- describe "with default type" do
111
- before do
112
- @content = capture(:stdout) { G.start }
113
- end
114
-
115
- it "allows to invoke a class from the class binding by a default option" do
116
- expect(@content).to match(/1\n2\n3\n4\n5\n/)
117
- end
118
-
119
- it "does not invoke if the option is nil" do
120
- expect(capture(:stdout) { G.start(%w[--skip-invoked]) }).not_to match(/invoke/)
121
- end
122
-
123
- it "prints a message if invocation cannot be found" do
124
- content = capture(:stdout) { G.start(%w[--invoked unknown]) }
125
- expect(content).to match(/error unknown \[not found\]/)
126
- end
127
-
128
- it "allows to invoke a class from the class binding by the given option" do
129
- error = nil
130
- content = capture(:stdout) do
131
- error = capture(:stderr) do
132
- G.start(%w[--invoked e])
133
- end
134
- end
135
- expect(content).to match(/invoke e/)
136
- expect(error).to match(/ERROR: "thor two" was called with arguments/)
137
- end
138
-
139
- it "shows invocation information to the user" do
140
- expect(@content).to match(/invoke defined/)
141
- end
142
-
143
- it "uses padding on status generated by the invoked class" do
144
- expect(@content).to match(/finished counting/)
145
- end
146
-
147
- it "shows invoked options on help" do
148
- content = capture(:stdout) { G.help(Thor::Base.shell.new) }
149
- expect(content).to match(/defined options:/)
150
- expect(content).to match(/\[--unused\]/)
151
- expect(content).to match(/# This option has no use/)
152
- end
153
- end
154
-
155
- describe "with boolean type" do
156
- before do
157
- @content = capture(:stdout) { H.start }
158
- end
159
-
160
- it "allows to invoke a class from the class binding by a default option" do
161
- expect(@content).to match(/1\n2\n3\n4\n5\n/)
162
- end
163
-
164
- it "does not invoke if the option is false" do
165
- expect(capture(:stdout) { H.start(%w[--no-defined]) }).not_to match(/invoke/)
166
- end
167
-
168
- it "shows invocation information to the user" do
169
- expect(@content).to match(/invoke defined/)
170
- end
171
-
172
- it "uses padding on status generated by the invoked class" do
173
- expect(@content).to match(/finished counting/)
174
- end
175
-
176
- it "shows invoked options on help" do
177
- content = capture(:stdout) { H.help(Thor::Base.shell.new) }
178
- expect(content).to match(/defined options:/)
179
- expect(content).to match(/\[--unused\]/)
180
- expect(content).to match(/# This option has no use/)
181
- end
182
- end
183
- end
184
-
185
- describe "edge-cases" do
186
- it "can handle boolean options followed by arguments" do
187
- klass = Class.new(Thor::Group) do
188
- desc "say hi to name"
189
- argument :name, :type => :string
190
- class_option :loud, :type => :boolean
191
-
192
- def hi
193
- name.upcase! if options[:loud]
194
- "Hi #{name}"
195
- end
196
- end
197
-
198
- expect(klass.start(%w[jose])).to eq(["Hi jose"])
199
- expect(klass.start(%w[jose --loud])).to eq(["Hi JOSE"])
200
- expect(klass.start(%w[--loud jose])).to eq(["Hi JOSE"])
201
- end
202
-
203
- it "provides extra args as `args`" do
204
- klass = Class.new(Thor::Group) do
205
- desc "say hi to name"
206
- argument :name, :type => :string
207
- class_option :loud, :type => :boolean
208
-
209
- def hi
210
- name.upcase! if options[:loud]
211
- out = "Hi #{name}"
212
- out << ": " << args.join(", ") unless args.empty?
213
- out
214
- end
215
- end
216
-
217
- expect(klass.start(%w[jose])).to eq(["Hi jose"])
218
- expect(klass.start(%w[jose --loud])).to eq(["Hi JOSE"])
219
- expect(klass.start(%w[--loud jose])).to eq(["Hi JOSE"])
220
- end
221
- end
222
- end
@@ -1,80 +0,0 @@
1
- $TESTING = true
2
-
3
- require "simplecov"
4
- require "coveralls"
5
-
6
- SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
7
- SimpleCov::Formatter::HTMLFormatter,
8
- Coveralls::SimpleCov::Formatter
9
- ]
10
-
11
- SimpleCov.start do
12
- add_filter "/spec/"
13
- minimum_coverage(92.21)
14
- end
15
-
16
- $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
17
- require "thor"
18
- require "thor/group"
19
- require "stringio"
20
-
21
- require "rdoc"
22
- require "rspec"
23
- require "diff/lcs" # You need diff/lcs installed to run specs (but not to run Thor).
24
- require "fakeweb" # You need fakeweb installed to run specs (but not to run Thor).
25
-
26
- # Set shell to basic
27
- $0 = "thor"
28
- $thor_runner = true
29
- ARGV.clear
30
- Thor::Base.shell = Thor::Shell::Basic
31
-
32
- # Load fixtures
33
- load File.join(File.dirname(__FILE__), "fixtures", "enum.thor")
34
- load File.join(File.dirname(__FILE__), "fixtures", "group.thor")
35
- load File.join(File.dirname(__FILE__), "fixtures", "invoke.thor")
36
- load File.join(File.dirname(__FILE__), "fixtures", "script.thor")
37
- load File.join(File.dirname(__FILE__), "fixtures", "subcommand.thor")
38
- load File.join(File.dirname(__FILE__), "fixtures", "command.thor")
39
-
40
- RSpec.configure do |config|
41
- config.before do
42
- ARGV.replace []
43
- end
44
-
45
- config.expect_with :rspec do |c|
46
- c.syntax = :expect
47
- end
48
-
49
- def capture(stream)
50
- begin
51
- stream = stream.to_s
52
- eval "$#{stream} = StringIO.new"
53
- yield
54
- result = eval("$#{stream}").string
55
- ensure
56
- eval("$#{stream} = #{stream.upcase}")
57
- end
58
-
59
- result
60
- end
61
-
62
- def source_root
63
- File.join(File.dirname(__FILE__), "fixtures")
64
- end
65
-
66
- def destination_root
67
- File.join(File.dirname(__FILE__), "sandbox")
68
- end
69
-
70
- # This code was adapted from Ruby on Rails, available under MIT-LICENSE
71
- # Copyright (c) 2004-2013 David Heinemeier Hansson
72
- def silence_warnings
73
- old_verbose, $VERBOSE = $VERBOSE, nil
74
- yield
75
- ensure
76
- $VERBOSE = old_verbose
77
- end
78
-
79
- alias silence capture
80
- end
@@ -1,120 +0,0 @@
1
- require "helper"
2
- require "thor/base"
3
-
4
- describe Thor::Invocation do
5
- describe "#invoke" do
6
- it "invokes a command inside another command" do
7
- expect(capture(:stdout) { A.new.invoke(:two) }).to eq("2\n3\n")
8
- end
9
-
10
- it "invokes a command just once" do
11
- expect(capture(:stdout) { A.new.invoke(:one) }).to eq("1\n2\n3\n")
12
- end
13
-
14
- it "invokes a command just once even if they belongs to different classes" do
15
- expect(capture(:stdout) { Defined.new.invoke(:one) }).to eq("1\n2\n3\n4\n5\n")
16
- end
17
-
18
- it "invokes a command with arguments" do
19
- expect(A.new.invoke(:five, [5])).to be true
20
- expect(A.new.invoke(:five, [7])).to be false
21
- end
22
-
23
- it "invokes the default command if none is given to a Thor class" do
24
- content = capture(:stdout) { A.new.invoke("b") }
25
- expect(content).to match(/Commands/)
26
- expect(content).to match(/LAST_NAME/)
27
- end
28
-
29
- it "accepts a class as argument without a command to invoke" do
30
- content = capture(:stdout) { A.new.invoke(B) }
31
- expect(content).to match(/Commands/)
32
- expect(content).to match(/LAST_NAME/)
33
- end
34
-
35
- it "accepts a class as argument with a command to invoke" do
36
- base = A.new([], :last_name => "Valim")
37
- expect(base.invoke(B, :one, %w[Jose])).to eq("Valim, Jose")
38
- end
39
-
40
- it "allows customized options to be given" do
41
- base = A.new([], :last_name => "Wrong")
42
- expect(base.invoke(B, :one, %w[Jose], :last_name => "Valim")).to eq("Valim, Jose")
43
- end
44
-
45
- it "reparses options in the new class" do
46
- expect(A.start(%w[invoker --last-name Valim])).to eq("Valim, Jose")
47
- end
48
-
49
- it "shares initialize options with invoked class" do
50
- expect(A.new([], :foo => :bar).invoke("b:two")).to eq("foo" => :bar)
51
- end
52
-
53
- it "uses default options from invoked class if no matching arguments are given" do
54
- expect(A.new([]).invoke("b:four")).to eq("default")
55
- end
56
-
57
- it "overrides default options if options are passed to the invoker" do
58
- expect(A.new([], :defaulted_value => "not default").invoke("b:four")).to eq("not default")
59
- end
60
-
61
- it "returns the command chain" do
62
- expect(I.new.invoke("two")).to eq([:two])
63
-
64
- if RUBY_VERSION < "1.9.3"
65
- result = J.start(["one", "two" ])
66
- expect(result).to include(:one)
67
- expect(result).to include(:two)
68
- else
69
- expect(J.start(["one", "two" ])).to eq([:one, :two])
70
- end
71
- end
72
-
73
- it "dump configuration values to be used in the invoked class" do
74
- base = A.new
75
- expect(base.invoke("b:three").shell).to eq(base.shell)
76
- end
77
-
78
- it "allow extra configuration values to be given" do
79
- base, shell = A.new, Thor::Base.shell.new
80
- expect(base.invoke("b:three", [], {}, :shell => shell).shell).to eq(shell)
81
- end
82
-
83
- it "invokes a Thor::Group and all of its commands" do
84
- expect(capture(:stdout) { A.new.invoke(:c) }).to eq("1\n2\n3\n")
85
- end
86
-
87
- it "does not invoke a Thor::Group twice" do
88
- base = A.new
89
- silence(:stdout) { base.invoke(:c) }
90
- expect(capture(:stdout) { base.invoke(:c) }).to be_empty
91
- end
92
-
93
- it "does not invoke any of Thor::Group commands twice" do
94
- base = A.new
95
- silence(:stdout) { base.invoke(:c) }
96
- expect(capture(:stdout) { base.invoke("c:one") }).to be_empty
97
- end
98
-
99
- it "raises Thor::UndefinedCommandError if the command can't be found" do
100
- expect do
101
- A.new.invoke("foo:bar")
102
- end.to raise_error(Thor::UndefinedCommandError)
103
- end
104
-
105
- it "raises Thor::UndefinedCommandError if the command can't be found even if all commands were already executed" do
106
- base = C.new
107
- silence(:stdout) { base.invoke_all }
108
-
109
- expect do
110
- base.invoke("foo:bar")
111
- end.to raise_error(Thor::UndefinedCommandError)
112
- end
113
-
114
- it "raises an error if a non Thor class is given" do
115
- expect do
116
- A.new.invoke(Object)
117
- end.to raise_error(RuntimeError, "Expected Thor class, got Object")
118
- end
119
- end
120
- end
@@ -1,28 +0,0 @@
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