thor 0.17.0 → 0.18.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 (70) hide show
  1. data/{CHANGELOG.rdoc → CHANGELOG.md} +30 -36
  2. data/README.md +10 -3
  3. data/lib/thor.rb +205 -180
  4. data/lib/thor/actions.rb +5 -5
  5. data/lib/thor/actions/create_link.rb +3 -0
  6. data/lib/thor/actions/directory.rb +2 -0
  7. data/lib/thor/actions/file_manipulation.rb +1 -1
  8. data/lib/thor/base.rb +84 -95
  9. data/lib/thor/{task.rb → command.rb} +17 -13
  10. data/lib/thor/core_ext/io_binary_read.rb +12 -0
  11. data/lib/thor/error.rb +4 -7
  12. data/lib/thor/group.rb +30 -33
  13. data/lib/thor/invocation.rb +28 -26
  14. data/lib/thor/parser/options.rb +3 -1
  15. data/lib/thor/runner.rb +21 -20
  16. data/lib/thor/shell/basic.rb +5 -1
  17. data/lib/thor/shell/color.rb +4 -0
  18. data/lib/thor/shell/html.rb +4 -0
  19. data/lib/thor/util.rb +214 -210
  20. data/lib/thor/version.rb +1 -1
  21. data/spec/actions/create_file_spec.rb +1 -1
  22. data/spec/actions/create_link_spec.rb +15 -1
  23. data/spec/actions/directory_spec.rb +18 -5
  24. data/spec/actions/empty_directory_spec.rb +1 -1
  25. data/spec/actions/file_manipulation_spec.rb +13 -13
  26. data/spec/actions/inject_into_file_spec.rb +1 -1
  27. data/spec/actions_spec.rb +1 -1
  28. data/spec/base_spec.rb +40 -24
  29. data/spec/command_spec.rb +80 -0
  30. data/spec/core_ext/hash_with_indifferent_access_spec.rb +1 -1
  31. data/spec/core_ext/ordered_hash_spec.rb +1 -1
  32. data/spec/exit_condition_spec.rb +3 -3
  33. data/spec/fixtures/{task.thor → command.thor} +0 -0
  34. data/spec/fixtures/doc/%file_name%.rb.tt +1 -0
  35. data/spec/fixtures/doc/COMMENTER +11 -0
  36. data/spec/fixtures/doc/README +3 -0
  37. data/spec/fixtures/doc/block_helper.rb +3 -0
  38. data/spec/fixtures/doc/config.rb +1 -0
  39. data/spec/fixtures/doc/config.yaml.tt +1 -0
  40. data/spec/fixtures/doc/excluding/%file_name%.rb.tt +1 -0
  41. data/spec/fixtures/group.thor +24 -10
  42. data/spec/fixtures/invoke.thor +3 -3
  43. data/spec/fixtures/script.thor +40 -15
  44. data/spec/fixtures/subcommand.thor +17 -0
  45. data/spec/group_spec.rb +13 -13
  46. data/spec/{spec_helper.rb → helper.rb} +11 -7
  47. data/spec/invocation_spec.rb +16 -16
  48. data/spec/parser/argument_spec.rb +4 -4
  49. data/spec/parser/arguments_spec.rb +1 -1
  50. data/spec/parser/option_spec.rb +1 -1
  51. data/spec/parser/options_spec.rb +6 -1
  52. data/spec/rake_compat_spec.rb +1 -1
  53. data/spec/register_spec.rb +12 -12
  54. data/spec/runner_spec.rb +36 -36
  55. data/spec/shell/basic_spec.rb +9 -10
  56. data/spec/shell/color_spec.rb +16 -2
  57. data/spec/shell/html_spec.rb +1 -1
  58. data/spec/shell_spec.rb +1 -1
  59. data/spec/subcommand_spec.rb +30 -0
  60. data/spec/thor_spec.rb +81 -78
  61. data/spec/util_spec.rb +10 -10
  62. data/thor.gemspec +22 -18
  63. metadata +49 -38
  64. data/.gitignore +0 -44
  65. data/.rspec +0 -3
  66. data/.travis.yml +0 -8
  67. data/Gemfile +0 -19
  68. data/bin/rake2thor +0 -86
  69. data/lib/thor/core_ext/file_binary_read.rb +0 -9
  70. data/spec/task_spec.rb +0 -80
@@ -0,0 +1,3 @@
1
+ <% world do -%>
2
+ Hello
3
+ <% end -%>
@@ -0,0 +1 @@
1
+ class <%= @klass %>; end
@@ -0,0 +1 @@
1
+ --- Hi from yaml
@@ -0,0 +1 @@
1
+ BAR = <%= "BAR" %>
@@ -9,16 +9,18 @@ class MyCounter < Thor::Group
9
9
  source_root File.expand_path(File.dirname(__FILE__))
10
10
  source_paths << File.expand_path("broken", File.dirname(__FILE__))
11
11
 
12
- argument :first, :type => :numeric
13
- argument :second, :type => :numeric, :default => 2
12
+ argument :first, :type => :numeric
13
+ argument :second, :type => :numeric, :default => 2
14
14
 
15
- class_option :third, :type => :numeric, :desc => "The third argument", :default => 3,
16
- :banner => "THREE", :aliases => "-t"
17
- class_option :fourth, :type => :numeric, :desc => "The fourth argument"
15
+ class_option :third, :type => :numeric, :desc => "The third argument", :default => 3,
16
+ :banner => "THREE", :aliases => "-t"
17
+ class_option :fourth, :type => :numeric, :desc => "The fourth argument"
18
+ class_option :simple, :type => :numeric, :aliases => 'z'
19
+ class_option :symbolic, :type => :numeric, :aliases => [:y, :r]
18
20
 
19
21
  desc <<-FOO
20
22
  Description:
21
- This generator runs three tasks: one, two and three.
23
+ This generator runs three commands: one, two and three.
22
24
  FOO
23
25
 
24
26
  def one
@@ -33,12 +35,24 @@ FOO
33
35
  options[:third]
34
36
  end
35
37
 
38
+ def four
39
+ options[:fourth]
40
+ end
41
+
42
+ def five
43
+ options[:simple]
44
+ end
45
+
46
+ def six
47
+ options[:symbolic]
48
+ end
49
+
36
50
  def self.inherited(base)
37
51
  super
38
52
  base.source_paths.unshift(File.expand_path(File.join(File.dirname(__FILE__), "doc")))
39
53
  end
40
54
 
41
- no_tasks do
55
+ no_commands do
42
56
  def world(&block)
43
57
  result = capture(&block)
44
58
  concat(result.strip + " world!")
@@ -87,8 +101,8 @@ class WhinyGenerator < Thor::Group
87
101
  end
88
102
  end
89
103
 
90
- class TaskConflict < Thor::Group
91
- desc "A group with the same name as a default task"
104
+ class CommandConflict < Thor::Group
105
+ desc "A group with the same name as a default command"
92
106
  def group
93
107
  puts "group"
94
108
  end
@@ -110,5 +124,5 @@ class ChildGroup < ParentGroup
110
124
  "bar"
111
125
  end
112
126
 
113
- public_task :foo, :baz
127
+ public_command :foo, :baz
114
128
  end
@@ -30,7 +30,7 @@ class A < Thor
30
30
  number == 5
31
31
  end
32
32
 
33
- desc "invoker", "invoke a b task"
33
+ desc "invoker", "invoke a b command"
34
34
  def invoker(*args)
35
35
  invoke :b, :one, ["Jose"]
36
36
  end
@@ -96,8 +96,8 @@ class E < Thor::Group
96
96
  end
97
97
 
98
98
  class F < Thor::Group
99
- invoke "b:one" do |instance, klass, task|
100
- instance.invoke klass, task, [ "Jose" ], :last_name => "Valim"
99
+ invoke "b:one" do |instance, klass, command|
100
+ instance.invoke klass, command, [ "Jose" ], :last_name => "Valim"
101
101
  end
102
102
  end
103
103
 
@@ -5,8 +5,12 @@ class MyScript < Thor
5
5
  attr_writer :another_attribute
6
6
  attr_reader :another_attribute
7
7
 
8
+ private
9
+ attr_reader :private_attribute
10
+
11
+ public
8
12
  group :script
9
- default_task :example_default_task
13
+ default_command :example_default_command
10
14
 
11
15
  map "-T" => :animal, ["-f", "--foo"] => :foo
12
16
 
@@ -19,8 +23,8 @@ class MyScript < Thor
19
23
 
20
24
  desc "animal TYPE", "horse around"
21
25
 
22
- no_tasks do
23
- def this_is_not_a_task
26
+ no_commands do
27
+ def this_is_not_a_command
24
28
  end
25
29
  end
26
30
 
@@ -47,10 +51,10 @@ END
47
51
  [bar, options]
48
52
  end
49
53
 
50
- desc "example_default_task", "example!"
54
+ desc "example_default_command", "example!"
51
55
  method_options :with => :string
52
- def example_default_task
53
- options.empty? ? "default task" : options
56
+ def example_default_command
57
+ options.empty? ? "default command" : options
54
58
  end
55
59
 
56
60
  desc "call_myself_with_wrong_arity", "get the right error"
@@ -58,7 +62,7 @@ END
58
62
  call_myself_with_wrong_arity(4)
59
63
  end
60
64
 
61
- desc "call_unexistent_method", "Call unexistent method inside a task"
65
+ desc "call_unexistent_method", "Call unexistent method inside a command"
62
66
  def call_unexistent_method
63
67
  boom!
64
68
  end
@@ -73,7 +77,7 @@ END
73
77
  def long_description
74
78
  end
75
79
 
76
- desc "name-with-dashes", "Ensure normalization of task names"
80
+ desc "name-with-dashes", "Ensure normalization of command names"
77
81
  def name_with_dashes
78
82
  end
79
83
 
@@ -93,7 +97,7 @@ END
93
97
  end
94
98
  end
95
99
 
96
- desc "send", "send as a task name"
100
+ desc "send", "send as a command name"
97
101
  def send
98
102
  true
99
103
  end
@@ -114,7 +118,7 @@ END
114
118
  end
115
119
 
116
120
  class MyChildScript < MyScript
117
- remove_task :bar
121
+ remove_command :bar
118
122
 
119
123
  method_options :force => :boolean, :param => :numeric
120
124
  def initialize(*args)
@@ -138,7 +142,7 @@ class MyChildScript < MyScript
138
142
  def boom
139
143
  end
140
144
 
141
- remove_task :boom, :undefine => true
145
+ remove_command :boom, :undefine => true
142
146
  end
143
147
 
144
148
  class Barn < Thor
@@ -156,14 +160,17 @@ class Barn < Thor
156
160
  def paint(color='red')
157
161
  puts "#{options[:coats]} coats of #{color} paint"
158
162
  end
163
+ end
159
164
 
165
+ class PackageNameScript < Thor
166
+ package_name "Baboon"
160
167
  end
161
168
 
162
169
  module Scripts
163
170
  class MyScript < MyChildScript
164
171
  argument :accessor, :type => :string
165
172
  class_options :force => :boolean
166
- method_option :new_option, :type => :string, :for => :example_default_task
173
+ method_option :new_option, :type => :string, :for => :example_default_command
167
174
 
168
175
  def zoo
169
176
  self.accessor
@@ -179,9 +186,9 @@ module Scripts
179
186
  puts "moo"
180
187
  end
181
188
 
182
- desc "task_conflict", "only gets called when prepended with a colon"
183
- def task_conflict
184
- puts "task"
189
+ desc "command_conflict", "only gets called when prepended with a colon"
190
+ def command_conflict
191
+ puts "command"
185
192
  end
186
193
 
187
194
  desc "barn", "commands to manage the barn"
@@ -191,5 +198,23 @@ module Scripts
191
198
  class ChildDefault < Thor
192
199
  namespace "default:child"
193
200
  end
201
+
202
+ class Arities < Thor
203
+ desc "zero_args", "takes zero args"
204
+ def zero_args
205
+ end
206
+
207
+ desc "one_arg ARG", "takes one arg"
208
+ def one_arg(arg)
209
+ end
210
+
211
+ desc "two_args ARG1 ARG2", "takes two args"
212
+ def two_args(arg1, arg2)
213
+ end
214
+
215
+ desc "optional_arg [ARG]", "takes an optional arg"
216
+ def optional_arg(arg='default')
217
+ end
218
+ end
194
219
  end
195
220
 
@@ -0,0 +1,17 @@
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,24 +1,24 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
1
+ require 'helper'
2
2
 
3
3
  describe Thor::Group do
4
- describe "task" do
5
- it "allows to use private methods from parent class as tasks" do
4
+ describe "command" do
5
+ it "allows to use private methods from parent class as commands" do
6
6
  expect(ChildGroup.start).to eq(["bar", "foo", "baz"])
7
7
  expect(ChildGroup.new.baz("bar")).to eq("bar")
8
8
  end
9
9
  end
10
10
 
11
11
  describe "#start" do
12
- it "invokes all the tasks under the Thor group" do
13
- expect(MyCounter.start(["1", "2", "--third", "3"])).to eq([ 1, 2, 3 ])
12
+ it "invokes all the commands under the Thor group" do
13
+ expect(MyCounter.start(["1", "2", "--third", "3"])).to eq([ 1, 2, 3, nil, nil, nil ])
14
14
  end
15
15
 
16
16
  it "uses argument default value" do
17
- expect(MyCounter.start(["1", "--third", "3"])).to eq([ 1, 2, 3 ])
17
+ expect(MyCounter.start(["1", "--third", "3"])).to eq([ 1, 2, 3, nil, nil, nil ])
18
18
  end
19
19
 
20
- it "invokes all the tasks in the Thor group and his parents" do
21
- expect(BrokenCounter.start(["1", "2", "--third", "3"])).to eq([ nil, 2, 3, false, 5 ])
20
+ it "invokes all the commands in the Thor group and its parents" do
21
+ expect(BrokenCounter.start(["1", "2", "--third", "3"])).to eq([ nil, 2, 3, false, 5, nil ])
22
22
  end
23
23
 
24
24
  it "raises an error if a required argument is added after a non-required" do
@@ -27,11 +27,11 @@ describe Thor::Group do
27
27
  }.to raise_error(ArgumentError, 'You cannot have "foo" as required argument after the non-required argument "second".')
28
28
  end
29
29
 
30
- it "raises when an exception happens within the task call" do
30
+ it "raises when an exception happens within the command call" do
31
31
  expect{ BrokenCounter.start(["1", "2", "--fail"]) }.to raise_error
32
32
  end
33
33
 
34
- it "raises an error when a Thor group task expects arguments" do
34
+ it "raises an error when a Thor group command expects arguments" do
35
35
  expect{ WhinyGenerator.start }.to raise_error(ArgumentError, /thor wrong_arity takes 1 argument, but it should not/)
36
36
  end
37
37
 
@@ -43,11 +43,11 @@ describe Thor::Group do
43
43
 
44
44
  describe "#desc" do
45
45
  it "sets the description for a given class" do
46
- expect(MyCounter.desc).to eq("Description:\n This generator runs three tasks: one, two and three.\n")
46
+ expect(MyCounter.desc).to eq("Description:\n This generator runs three commands: one, two and three.\n")
47
47
  end
48
48
 
49
49
  it "can be inherited" do
50
- expect(BrokenCounter.desc).to eq("Description:\n This generator runs three tasks: one, two and three.\n")
50
+ expect(BrokenCounter.desc).to eq("Description:\n This generator runs three commands: one, two and three.\n")
51
51
  end
52
52
 
53
53
  it "can be nil" do
@@ -66,7 +66,7 @@ describe Thor::Group do
66
66
 
67
67
  it "shows description" do
68
68
  expect(@content).to match(/Description:/)
69
- expect(@content).to match(/This generator runs three tasks: one, two and three./)
69
+ expect(@content).to match(/This generator runs three commands: one, two and three./)
70
70
  end
71
71
 
72
72
  it "shows options information" do
@@ -1,10 +1,13 @@
1
1
  $TESTING=true
2
2
 
3
3
  require 'simplecov'
4
- SimpleCov.start do
5
- add_group 'Libraries', 'lib'
6
- add_group 'Specs', 'spec'
7
- end
4
+ require 'coveralls'
5
+
6
+ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
7
+ SimpleCov::Formatter::HTMLFormatter,
8
+ Coveralls::SimpleCov::Formatter
9
+ ]
10
+ SimpleCov.start
8
11
 
9
12
  $:.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
10
13
  require 'thor'
@@ -23,11 +26,12 @@ ARGV.clear
23
26
  Thor::Base.shell = Thor::Shell::Basic
24
27
 
25
28
  # Load fixtures
26
- load File.join(File.dirname(__FILE__), "fixtures", "task.thor")
29
+ load File.join(File.dirname(__FILE__), "fixtures", "enum.thor")
27
30
  load File.join(File.dirname(__FILE__), "fixtures", "group.thor")
28
- load File.join(File.dirname(__FILE__), "fixtures", "script.thor")
29
31
  load File.join(File.dirname(__FILE__), "fixtures", "invoke.thor")
30
- load File.join(File.dirname(__FILE__), "fixtures", "enum.thor")
32
+ load File.join(File.dirname(__FILE__), "fixtures", "script.thor")
33
+ load File.join(File.dirname(__FILE__), "fixtures", "subcommand.thor")
34
+ load File.join(File.dirname(__FILE__), "fixtures", "command.thor")
31
35
 
32
36
  RSpec.configure do |config|
33
37
  config.before do
@@ -1,38 +1,38 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
1
+ require 'helper'
2
2
  require 'thor/base'
3
3
 
4
4
  describe Thor::Invocation do
5
5
  describe "#invoke" do
6
- it "invokes a task inside another task" do
6
+ it "invokes a command inside another command" do
7
7
  expect(capture(:stdout) { A.new.invoke(:two) }).to eq("2\n3\n")
8
8
  end
9
9
 
10
- it "invokes a task just once" do
10
+ it "invokes a command just once" do
11
11
  expect(capture(:stdout) { A.new.invoke(:one) }).to eq("1\n2\n3\n")
12
12
  end
13
13
 
14
- it "invokes a task just once even if they belongs to different classes" do
14
+ it "invokes a command just once even if they belongs to different classes" do
15
15
  expect(capture(:stdout) { Defined.new.invoke(:one) }).to eq("1\n2\n3\n4\n5\n")
16
16
  end
17
17
 
18
- it "invokes a task with arguments" do
18
+ it "invokes a command with arguments" do
19
19
  expect(A.new.invoke(:five, [5])).to be_true
20
20
  expect(A.new.invoke(:five, [7])).to be_false
21
21
  end
22
22
 
23
- it "invokes the default task if none is given to a Thor class" do
23
+ it "invokes the default command if none is given to a Thor class" do
24
24
  content = capture(:stdout) { A.new.invoke("b") }
25
- expect(content).to match(/Tasks/)
25
+ expect(content).to match(/Commands/)
26
26
  expect(content).to match(/LAST_NAME/)
27
27
  end
28
28
 
29
- it "accepts a class as argument without a task to invoke" do
29
+ it "accepts a class as argument without a command to invoke" do
30
30
  content = capture(:stdout) { A.new.invoke(B) }
31
- expect(content).to match(/Tasks/)
31
+ expect(content).to match(/Commands/)
32
32
  expect(content).to match(/LAST_NAME/)
33
33
  end
34
34
 
35
- it "accepts a class as argument with a task to invoke" do
35
+ it "accepts a class as argument with a command to invoke" do
36
36
  base = A.new([], :last_name => "Valim")
37
37
  expect(base.invoke(B, :one, ["Jose"])).to eq("Valim, Jose")
38
38
  end
@@ -60,7 +60,7 @@ describe Thor::Invocation do
60
60
  expect(base.invoke("b:three", [], {}, :shell => shell).shell).to eq(shell)
61
61
  end
62
62
 
63
- it "invokes a Thor::Group and all of its tasks" do
63
+ it "invokes a Thor::Group and all of its commands" do
64
64
  expect(capture(:stdout) { A.new.invoke(:c) }).to eq("1\n2\n3\n")
65
65
  end
66
66
 
@@ -70,25 +70,25 @@ describe Thor::Invocation do
70
70
  expect(capture(:stdout) { base.invoke(:c) }).to be_empty
71
71
  end
72
72
 
73
- it "does not invoke any of Thor::Group tasks twice" do
73
+ it "does not invoke any of Thor::Group commands twice" do
74
74
  base = A.new
75
75
  silence(:stdout){ base.invoke(:c) }
76
76
  expect(capture(:stdout) { base.invoke("c:one") }).to be_empty
77
77
  end
78
78
 
79
- it "raises Thor::UndefinedTaskError if the task can't be found" do
79
+ it "raises Thor::UndefinedcommandError if the command can't be found" do
80
80
  expect {
81
81
  A.new.invoke("foo:bar")
82
- }.to raise_error(Thor::UndefinedTaskError)
82
+ }.to raise_error(Thor::UndefinedCommandError)
83
83
  end
84
84
 
85
- it "raises Thor::UndefinedTaskError if the task can't be found even if all tasks where already executed" do
85
+ it "raises Thor::UndefinedcommandError if the command can't be found even if all commands were already executed" do
86
86
  base = C.new
87
87
  silence(:stdout){ base.invoke_all }
88
88
 
89
89
  expect {
90
90
  base.invoke("foo:bar")
91
- }.to raise_error(Thor::UndefinedTaskError)
91
+ }.to raise_error(Thor::UndefinedCommandError)
92
92
  end
93
93
 
94
94
  it "raises an error if a non Thor class is given" do
@@ -1,4 +1,4 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
1
+ require 'helper'
2
2
  require 'thor/parser'
3
3
 
4
4
  describe Thor::Argument do
@@ -16,19 +16,19 @@ describe Thor::Argument do
16
16
 
17
17
  it "raises an error if type is unknown" do
18
18
  expect {
19
- argument(:task, :type => :unknown)
19
+ argument(:command, :type => :unknown)
20
20
  }.to raise_error(ArgumentError, "Type :unknown is not valid for arguments.")
21
21
  end
22
22
 
23
23
  it "raises an error if argument is required and have default values" do
24
24
  expect {
25
- argument(:task, :type => :string, :default => "bar", :required => true)
25
+ argument(:command, :type => :string, :default => "bar", :required => true)
26
26
  }.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
30
  expect {
31
- argument(:task, :type => :string, :enum => "bar")
31
+ argument(:command, :type => :string, :enum => "bar")
32
32
  }.to raise_error(ArgumentError, "An argument cannot have an enum other than an array.")
33
33
  end
34
34
  end