thor 0.14.6 → 0.15.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/.autotest +8 -0
- data/.document +5 -0
- data/.gemtest +0 -0
- data/.gitignore +44 -0
- data/.rspec +2 -0
- data/.travis.yml +9 -0
- data/CHANGELOG.rdoc +4 -4
- data/Gemfile +19 -0
- data/{LICENSE → LICENSE.md} +2 -2
- data/README.md +21 -300
- data/Thorfile +21 -15
- data/lib/thor.rb +56 -11
- data/lib/thor/actions.rb +7 -3
- data/lib/thor/actions/create_link.rb +1 -1
- data/lib/thor/actions/directory.rb +7 -3
- data/lib/thor/actions/empty_directory.rb +24 -5
- data/lib/thor/actions/file_manipulation.rb +40 -2
- data/lib/thor/base.rb +66 -28
- data/lib/thor/error.rb +6 -1
- data/lib/thor/group.rb +20 -8
- data/lib/thor/invocation.rb +4 -2
- data/lib/thor/parser/arguments.rb +6 -2
- data/lib/thor/parser/option.rb +3 -2
- data/lib/thor/parser/options.rb +13 -8
- data/lib/thor/rake_compat.rb +13 -8
- data/lib/thor/runner.rb +16 -4
- data/lib/thor/shell.rb +2 -2
- data/lib/thor/shell/basic.rb +86 -29
- data/lib/thor/shell/color.rb +40 -4
- data/lib/thor/shell/html.rb +28 -26
- data/lib/thor/task.rb +26 -8
- data/lib/thor/util.rb +26 -7
- data/lib/thor/version.rb +1 -1
- data/spec/actions/create_link_spec.rb +81 -0
- data/spec/actions/empty_directory_spec.rb +32 -0
- data/spec/actions/file_manipulation_spec.rb +61 -1
- data/spec/actions_spec.rb +4 -0
- data/spec/base_spec.rb +10 -5
- data/spec/exit_condition_spec.rb +19 -0
- data/spec/fixtures/script.thor +8 -2
- data/spec/group_spec.rb +39 -1
- data/spec/parser/arguments_spec.rb +1 -0
- data/spec/parser/options_spec.rb +12 -2
- data/spec/rake_compat_spec.rb +11 -7
- data/spec/register_spec.rb +43 -0
- data/spec/runner_spec.rb +34 -3
- data/spec/shell/basic_spec.rb +50 -3
- data/spec/shell/color_spec.rb +46 -6
- data/spec/shell/html_spec.rb +10 -5
- data/spec/spec_helper.rb +4 -0
- data/spec/task_spec.rb +26 -16
- data/spec/thor_spec.rb +56 -3
- data/thor.gemspec +26 -0
- metadata +174 -117
data/Thorfile
CHANGED
@@ -1,24 +1,30 @@
|
|
1
|
-
#
|
1
|
+
# encoding: utf-8
|
2
|
+
$:.unshift File.expand_path("../lib", __FILE__)
|
3
|
+
|
4
|
+
require 'bundler'
|
2
5
|
require 'thor/rake_compat'
|
3
6
|
|
4
7
|
class Default < Thor
|
5
8
|
include Thor::RakeCompat
|
9
|
+
Bundler::GemHelper.install_tasks
|
6
10
|
|
7
|
-
|
8
|
-
|
11
|
+
desc "build", "Build thor-#{Thor::VERSION}.gem into the pkg directory"
|
12
|
+
def build
|
13
|
+
Rake::Task["build"].execute
|
14
|
+
end
|
9
15
|
|
10
|
-
|
11
|
-
|
16
|
+
desc "install", "Build and install thor-#{Thor::VERSION}.gem into system gems"
|
17
|
+
def install
|
18
|
+
Rake::Task["install"].execute
|
19
|
+
end
|
20
|
+
|
21
|
+
desc "release", "Create tag v#{Thor::VERSION} and build and push thor-#{Thor::VERSION}.gem to Rubygems"
|
22
|
+
def release
|
23
|
+
Rake::Task["release"].execute
|
24
|
+
end
|
12
25
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
rdoc.main = 'README.md'
|
17
|
-
rdoc.rdoc_dir = 'rdoc'
|
18
|
-
rdoc.title = 'thor'
|
19
|
-
rdoc.rdoc_files.include('README.md', 'LICENSE', 'CHANGELOG.rdoc', 'Thorfile')
|
20
|
-
rdoc.rdoc_files.include('lib/**/*.rb')
|
21
|
-
rdoc.options << '--line-numbers' << '--inline-source'
|
22
|
-
end
|
26
|
+
desc "spec", "Run RSpec code examples"
|
27
|
+
def spec
|
28
|
+
exec "rspec --color --format=documentation spec"
|
23
29
|
end
|
24
30
|
end
|
data/lib/thor.rb
CHANGED
@@ -5,7 +5,7 @@ class Thor
|
|
5
5
|
# Sets the default task when thor is executed without an explicit task to be called.
|
6
6
|
#
|
7
7
|
# ==== Parameters
|
8
|
-
# meth<Symbol>:: name of the
|
8
|
+
# meth<Symbol>:: name of the default task
|
9
9
|
#
|
10
10
|
def default_task(meth=nil)
|
11
11
|
case meth
|
@@ -28,7 +28,7 @@ class Thor
|
|
28
28
|
def register(klass, subcommand_name, usage, description, options={})
|
29
29
|
if klass <= Thor::Group
|
30
30
|
desc usage, description, options
|
31
|
-
define_method(subcommand_name) { invoke
|
31
|
+
define_method(subcommand_name) { |*args| invoke(klass, args) }
|
32
32
|
else
|
33
33
|
desc usage, description, options
|
34
34
|
subcommand subcommand_name, klass
|
@@ -108,6 +108,8 @@ class Thor
|
|
108
108
|
@method_options
|
109
109
|
end
|
110
110
|
|
111
|
+
alias options method_options
|
112
|
+
|
111
113
|
# Adds an option to the set of method options. If :for is given as option,
|
112
114
|
# it allows you to change the options from a previous defined task.
|
113
115
|
#
|
@@ -132,6 +134,7 @@ class Thor
|
|
132
134
|
# :aliases - Aliases for this option.
|
133
135
|
# :type - The type of the argument, can be :string, :hash, :array, :numeric or :boolean.
|
134
136
|
# :banner - String to show on usage notes.
|
137
|
+
# :hide - If you want to hide this option from the help.
|
135
138
|
#
|
136
139
|
def method_option(name, options={})
|
137
140
|
scope = if options[:for]
|
@@ -143,6 +146,8 @@ class Thor
|
|
143
146
|
build_option(name, options, scope)
|
144
147
|
end
|
145
148
|
|
149
|
+
alias option method_option
|
150
|
+
|
146
151
|
# Prints help information for the given task.
|
147
152
|
#
|
148
153
|
# ==== Parameters
|
@@ -160,7 +165,7 @@ class Thor
|
|
160
165
|
class_options_help(shell, nil => task.options.map { |_, o| o })
|
161
166
|
if task.long_description
|
162
167
|
shell.say "Description:"
|
163
|
-
shell.print_wrapped(task.long_description, :
|
168
|
+
shell.print_wrapped(task.long_description, :indent => 2)
|
164
169
|
else
|
165
170
|
shell.say task.description
|
166
171
|
end
|
@@ -179,7 +184,7 @@ class Thor
|
|
179
184
|
list.sort!{ |a,b| a[0] <=> b[0] }
|
180
185
|
|
181
186
|
shell.say "Tasks:"
|
182
|
-
shell.print_table(list, :
|
187
|
+
shell.print_table(list, :indent => 2, :truncate => true)
|
183
188
|
shell.say
|
184
189
|
class_options_help(shell)
|
185
190
|
end
|
@@ -202,7 +207,11 @@ class Thor
|
|
202
207
|
def subcommand(subcommand, subcommand_class)
|
203
208
|
self.subcommands << subcommand.to_s
|
204
209
|
subcommand_class.subcommand_help subcommand
|
205
|
-
|
210
|
+
|
211
|
+
define_method(subcommand) do |*args|
|
212
|
+
args, opts = Thor::Arguments.split(args)
|
213
|
+
invoke subcommand_class, args, opts
|
214
|
+
end
|
206
215
|
end
|
207
216
|
|
208
217
|
# Extend check unknown options to accept a hash of conditions.
|
@@ -259,8 +268,11 @@ class Thor
|
|
259
268
|
opts = given_opts || opts || []
|
260
269
|
config.merge!(:current_task => task, :task_options => task.options)
|
261
270
|
|
271
|
+
instance = new(args, opts, config)
|
272
|
+
yield instance if block_given?
|
273
|
+
args = instance.args
|
262
274
|
trailing = args[Range.new(arguments.size, -1)]
|
263
|
-
|
275
|
+
instance.invoke_task(task, trailing || [])
|
264
276
|
end
|
265
277
|
|
266
278
|
# The banner for this class. You can customize it if you are invoking the
|
@@ -300,7 +312,6 @@ class Thor
|
|
300
312
|
# Retrieve the task name from given args.
|
301
313
|
def retrieve_task_name(args) #:nodoc:
|
302
314
|
meth = args.first.to_s unless args.empty?
|
303
|
-
|
304
315
|
if meth && (map[meth] || meth !~ /^\-/)
|
305
316
|
args.shift
|
306
317
|
else
|
@@ -308,11 +319,45 @@ class Thor
|
|
308
319
|
end
|
309
320
|
end
|
310
321
|
|
311
|
-
#
|
312
|
-
#
|
322
|
+
# receives a (possibly nil) task name and returns a name that is in
|
323
|
+
# the tasks hash. In addition to normalizing aliases, this logic
|
324
|
+
# will determine if a shortened command is an unambiguous prefix of
|
325
|
+
# a task or alias.
|
326
|
+
#
|
327
|
+
# +normalize_task_name+ also converts names like +animal-prison+
|
328
|
+
# into +animal_prison+.
|
313
329
|
def normalize_task_name(meth) #:nodoc:
|
314
|
-
|
315
|
-
|
330
|
+
return default_task.to_s.gsub('-', '_') unless meth
|
331
|
+
|
332
|
+
possibilities = find_task_possibilities(meth)
|
333
|
+
if possibilities.size > 1
|
334
|
+
raise ArgumentError, "Ambiguous task #{meth} matches [#{possibilities.join(', ')}]"
|
335
|
+
elsif possibilities.size < 1
|
336
|
+
meth = meth || default_task
|
337
|
+
elsif map[meth]
|
338
|
+
meth = map[meth]
|
339
|
+
else
|
340
|
+
meth = possibilities.first
|
341
|
+
end
|
342
|
+
|
343
|
+
meth.to_s.gsub('-','_') # treat foo-bar as foo_bar
|
344
|
+
end
|
345
|
+
|
346
|
+
# this is the logic that takes the task name passed in by the user
|
347
|
+
# and determines whether it is an unambiguous prefix of a task or
|
348
|
+
# alias name.
|
349
|
+
def find_task_possibilities(meth)
|
350
|
+
len = meth.to_s.length
|
351
|
+
possibilities = all_tasks.merge(map).keys.select { |n| meth == n[0, len] }.sort
|
352
|
+
unique_possibilities = possibilities.map { |k| map[k] || k }.uniq
|
353
|
+
|
354
|
+
if possibilities.include?(meth)
|
355
|
+
[meth]
|
356
|
+
elsif unique_possibilities.size == 1
|
357
|
+
unique_possibilities
|
358
|
+
else
|
359
|
+
possibilities
|
360
|
+
end
|
316
361
|
end
|
317
362
|
|
318
363
|
def subcommand_help(cmd)
|
data/lib/thor/actions.rb
CHANGED
@@ -55,7 +55,7 @@ class Thor
|
|
55
55
|
:desc => "Run but do not make any changes"
|
56
56
|
|
57
57
|
class_option :quiet, :type => :boolean, :aliases => "-q", :group => :runtime,
|
58
|
-
:desc => "
|
58
|
+
:desc => "Suppress status output"
|
59
59
|
|
60
60
|
class_option :skip, :type => :boolean, :aliases => "-s", :group => :runtime,
|
61
61
|
:desc => "Skip files that already exist"
|
@@ -114,8 +114,12 @@ class Thor
|
|
114
114
|
# the script started).
|
115
115
|
#
|
116
116
|
def relative_to_original_destination_root(path, remove_dot=true)
|
117
|
-
path
|
118
|
-
|
117
|
+
if path =~ /^#{@destination_stack[0]}/
|
118
|
+
path = path.gsub(@destination_stack[0], '.')
|
119
|
+
path = remove_dot ? (path[2..-1] || '') : path
|
120
|
+
end
|
121
|
+
|
122
|
+
path
|
119
123
|
end
|
120
124
|
|
121
125
|
# Holds source paths in instance so they can be manipulated.
|
@@ -41,7 +41,7 @@ class Thor
|
|
41
41
|
invoke_with_conflict_check do
|
42
42
|
FileUtils.mkdir_p(File.dirname(destination))
|
43
43
|
# Create a symlink by default
|
44
|
-
config[:symbolic]
|
44
|
+
config[:symbolic] = true if config[:symbolic].nil?
|
45
45
|
File.unlink(destination) if exists?
|
46
46
|
if config[:symbolic]
|
47
47
|
File.symlink(render, destination)
|
@@ -2,13 +2,13 @@ require 'thor/actions/empty_directory'
|
|
2
2
|
|
3
3
|
class Thor
|
4
4
|
module Actions
|
5
|
-
|
6
5
|
# Copies recursively the files from source directory to root directory.
|
7
6
|
# If any of the files finishes with .tt, it's considered to be a template
|
8
7
|
# and is placed in the destination without the extension .tt. If any
|
9
8
|
# empty directory is found, it's copied and all .empty_directory files are
|
10
|
-
# ignored.
|
11
|
-
#
|
9
|
+
# ignored. If any file name is wrapped within % signs, the text within
|
10
|
+
# the % signs will be executed as a method and replaced with the returned
|
11
|
+
# value. Let's suppose a doc directory with the following files:
|
12
12
|
#
|
13
13
|
# doc/
|
14
14
|
# components/.empty_directory
|
@@ -29,6 +29,10 @@ class Thor
|
|
29
29
|
# rdoc.rb
|
30
30
|
# blog.rb
|
31
31
|
#
|
32
|
+
# <b>Encoded path note:</b> Since Thor internals use Object#respond_to? to check if it can
|
33
|
+
# expand %something%, this `something` should be a public method in the class calling
|
34
|
+
# #directory. If a method is private, Thor stack raises PrivateMethodEncodedError.
|
35
|
+
#
|
32
36
|
# ==== Parameters
|
33
37
|
# source<String>:: the relative path to the source root.
|
34
38
|
# destination<String>:: the relative path to the destination root.
|
@@ -90,16 +90,35 @@ class Thor
|
|
90
90
|
|
91
91
|
# Filenames in the encoded form are converted. If you have a file:
|
92
92
|
#
|
93
|
-
# %
|
93
|
+
# %file_name%.rb
|
94
94
|
#
|
95
|
-
# It
|
95
|
+
# It calls #file_name from the base and replaces %-string with the
|
96
|
+
# return value (should be String) of #file_name:
|
96
97
|
#
|
97
98
|
# user.rb
|
98
99
|
#
|
100
|
+
# The method referenced by %-string SHOULD be public. Otherwise you
|
101
|
+
# get the exception with the corresponding error message.
|
102
|
+
#
|
99
103
|
def convert_encoded_instructions(filename)
|
100
|
-
filename.gsub(/%(.*?)%/) do |
|
101
|
-
|
102
|
-
|
104
|
+
filename.gsub(/%(.*?)%/) do |initial_string|
|
105
|
+
call_public_method($1.strip) or initial_string
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
# Calls `base`'s public method `sym`.
|
110
|
+
# Returns:: result of `base.sym` or `nil` if `sym` wasn't found in
|
111
|
+
# `base`
|
112
|
+
# Raises:: Thor::PrivateMethodEncodedError if `sym` references
|
113
|
+
# a private method.
|
114
|
+
def call_public_method(sym)
|
115
|
+
if base.respond_to?(sym)
|
116
|
+
base.send(sym)
|
117
|
+
elsif base.respond_to?(sym, true)
|
118
|
+
raise Thor::PrivateMethodEncodedError,
|
119
|
+
"Method #{base.class}##{sym} should be public, not private"
|
120
|
+
else
|
121
|
+
nil
|
103
122
|
end
|
104
123
|
end
|
105
124
|
|
@@ -102,7 +102,7 @@ class Thor
|
|
102
102
|
#
|
103
103
|
def template(source, *args, &block)
|
104
104
|
config = args.last.is_a?(Hash) ? args.pop : {}
|
105
|
-
destination = args.first || source
|
105
|
+
destination = args.first || source.sub(/\.tt$/, '')
|
106
106
|
|
107
107
|
source = File.expand_path(find_in_source_paths(source.to_s))
|
108
108
|
context = instance_eval('binding')
|
@@ -187,7 +187,7 @@ class Thor
|
|
187
187
|
#
|
188
188
|
# ==== Examples
|
189
189
|
#
|
190
|
-
# inject_into_class "app/controllers/application_controller.rb", " filter_parameter :password\n"
|
190
|
+
# inject_into_class "app/controllers/application_controller.rb", ApplicationController, " filter_parameter :password\n"
|
191
191
|
#
|
192
192
|
# inject_into_class "app/controllers/application_controller.rb", ApplicationController do
|
193
193
|
# " filter_parameter :password\n"
|
@@ -229,6 +229,44 @@ class Thor
|
|
229
229
|
end
|
230
230
|
end
|
231
231
|
|
232
|
+
# Uncomment all lines matching a given regex. It will leave the space
|
233
|
+
# which existed before the comment hash in tact but will remove any spacing
|
234
|
+
# between the comment hash and the beginning of the line.
|
235
|
+
#
|
236
|
+
# ==== Parameters
|
237
|
+
# path<String>:: path of the file to be changed
|
238
|
+
# flag<Regexp|String>:: the regexp or string used to decide which lines to uncomment
|
239
|
+
# config<Hash>:: give :verbose => false to not log the status.
|
240
|
+
#
|
241
|
+
# ==== Example
|
242
|
+
#
|
243
|
+
# uncomment_lines 'config/initializers/session_store.rb', /active_record/
|
244
|
+
#
|
245
|
+
def uncomment_lines(path, flag, *args)
|
246
|
+
flag = flag.respond_to?(:source) ? flag.source : flag
|
247
|
+
|
248
|
+
gsub_file(path, /^(\s*)#\s*(.*#{flag})/, '\1\2', *args)
|
249
|
+
end
|
250
|
+
|
251
|
+
# Comment all lines matching a given regex. It will leave the space
|
252
|
+
# which existed before the beginning of the line in tact and will insert
|
253
|
+
# a single space after the comment hash.
|
254
|
+
#
|
255
|
+
# ==== Parameters
|
256
|
+
# path<String>:: path of the file to be changed
|
257
|
+
# flag<Regexp|String>:: the regexp or string used to decide which lines to comment
|
258
|
+
# config<Hash>:: give :verbose => false to not log the status.
|
259
|
+
#
|
260
|
+
# ==== Example
|
261
|
+
#
|
262
|
+
# comment_lines 'config/initializers/session_store.rb', /cookie_store/
|
263
|
+
#
|
264
|
+
def comment_lines(path, flag, *args)
|
265
|
+
flag = flag.respond_to?(:source) ? flag.source : flag
|
266
|
+
|
267
|
+
gsub_file(path, /^(\s*)([^#|\n]*#{flag})/, '\1# \2', *args)
|
268
|
+
end
|
269
|
+
|
232
270
|
# Removes a file at the given location.
|
233
271
|
#
|
234
272
|
# ==== Parameters
|
data/lib/thor/base.rb
CHANGED
@@ -19,7 +19,7 @@ class Thor
|
|
19
19
|
action add_file create_file in_root inside run run_ruby_script)
|
20
20
|
|
21
21
|
module Base
|
22
|
-
attr_accessor :options
|
22
|
+
attr_accessor :options, :parent_options, :args
|
23
23
|
|
24
24
|
# It receives arguments in an Array and two hashes, one for options and
|
25
25
|
# other for configuration.
|
@@ -38,22 +38,43 @@ class Thor
|
|
38
38
|
# config<Hash>:: Configuration for this Thor class.
|
39
39
|
#
|
40
40
|
def initialize(args=[], options={}, config={})
|
41
|
-
args = Thor::Arguments.parse(self.class.arguments, args)
|
42
|
-
args.each { |key, value| send("#{key}=", value) }
|
43
|
-
|
44
41
|
parse_options = self.class.class_options
|
45
42
|
|
43
|
+
# The start method splits inbound arguments at the first argument
|
44
|
+
# that looks like an option (starts with - or --). It then calls
|
45
|
+
# new, passing in the two halves of the arguments Array as the
|
46
|
+
# first two parameters.
|
47
|
+
|
46
48
|
if options.is_a?(Array)
|
47
49
|
task_options = config.delete(:task_options) # hook for start
|
48
50
|
parse_options = parse_options.merge(task_options) if task_options
|
49
51
|
array_options, hash_options = options, {}
|
50
52
|
else
|
53
|
+
# Handle the case where the class was explicitly instantiated
|
54
|
+
# with pre-parsed options.
|
51
55
|
array_options, hash_options = [], options
|
52
56
|
end
|
53
57
|
|
58
|
+
# Let Thor::Options parse the options first, so it can remove
|
59
|
+
# declared options from the array. This will leave us with
|
60
|
+
# a list of arguments that weren't declared.
|
54
61
|
opts = Thor::Options.new(parse_options, hash_options)
|
55
62
|
self.options = opts.parse(array_options)
|
63
|
+
|
64
|
+
# If unknown options are disallowed, make sure that none of the
|
65
|
+
# remaining arguments looks like an option.
|
56
66
|
opts.check_unknown! if self.class.check_unknown_options?(config)
|
67
|
+
|
68
|
+
# Add the remaining arguments from the options parser to the
|
69
|
+
# arguments passed in to initialize. Then remove any positional
|
70
|
+
# arguments declared using #argument (this is primarily used
|
71
|
+
# by Thor::Group). Tis will leave us with the remaining
|
72
|
+
# positional arguments.
|
73
|
+
thor_args = Thor::Arguments.new(self.class.arguments)
|
74
|
+
thor_args.parse(args + opts.remaining).each { |k,v| send("#{k}=", v) }
|
75
|
+
args = thor_args.remaining
|
76
|
+
|
77
|
+
@args = args
|
57
78
|
end
|
58
79
|
|
59
80
|
class << self
|
@@ -94,8 +115,6 @@ class Thor
|
|
94
115
|
end
|
95
116
|
|
96
117
|
module ClassMethods
|
97
|
-
attr_accessor :debugging
|
98
|
-
|
99
118
|
def attr_reader(*) #:nodoc:
|
100
119
|
no_tasks { super }
|
101
120
|
end
|
@@ -212,13 +231,14 @@ class Thor
|
|
212
231
|
# options<Hash>:: Described below.
|
213
232
|
#
|
214
233
|
# ==== Options
|
215
|
-
# :desc
|
216
|
-
# :required
|
217
|
-
# :default
|
218
|
-
# :group
|
219
|
-
# :aliases
|
220
|
-
# :type
|
221
|
-
# :banner
|
234
|
+
# :desc:: -- Description for the argument.
|
235
|
+
# :required:: -- If the argument is required or not.
|
236
|
+
# :default:: -- Default value for this argument.
|
237
|
+
# :group:: -- The group for this options. Use by class options to output options in different levels.
|
238
|
+
# :aliases:: -- Aliases for this option. <b>Note:</b> Thor follows a convention of one-dash-one-letter options. Thus aliases like "-something" wouldn't be parsed; use either "\--something" or "-s" instead.
|
239
|
+
# :type:: -- The type of the argument, can be :string, :hash, :array, :numeric or :boolean.
|
240
|
+
# :banner:: -- String to show on usage notes.
|
241
|
+
# :hide:: -- If you want to hide this option from the help.
|
222
242
|
#
|
223
243
|
def class_option(name, options={})
|
224
244
|
build_option(name, options, class_options)
|
@@ -227,7 +247,7 @@ class Thor
|
|
227
247
|
# Removes a previous defined argument. If :undefine is given, undefine
|
228
248
|
# accessors as well.
|
229
249
|
#
|
230
|
-
# ====
|
250
|
+
# ==== Parameters
|
231
251
|
# names<Array>:: Arguments to be removed
|
232
252
|
#
|
233
253
|
# ==== Examples
|
@@ -246,7 +266,7 @@ class Thor
|
|
246
266
|
|
247
267
|
# Removes a previous defined class option.
|
248
268
|
#
|
249
|
-
# ====
|
269
|
+
# ==== Parameters
|
250
270
|
# names<Array>:: Class options to be removed
|
251
271
|
#
|
252
272
|
# ==== Examples
|
@@ -384,17 +404,22 @@ class Thor
|
|
384
404
|
# script.invoke(:task, first_arg, second_arg, third_arg)
|
385
405
|
#
|
386
406
|
def start(given_args=ARGV, config={})
|
387
|
-
self.debugging = given_args.delete("--debug")
|
388
407
|
config[:shell] ||= Thor::Base.shell.new
|
389
408
|
dispatch(nil, given_args.dup, nil, config)
|
390
409
|
rescue Thor::Error => e
|
391
|
-
|
410
|
+
ENV["THOR_DEBUG"] == "1" ? (raise e) : config[:shell].error(e.message)
|
392
411
|
exit(1) if exit_on_failure?
|
412
|
+
rescue Errno::EPIPE
|
413
|
+
# This happens if a thor task is piped to something like `head`,
|
414
|
+
# which closes the pipe when it's done reading. This will also
|
415
|
+
# mean that if the pipe is closed, further unnecessary
|
416
|
+
# computation will not occur.
|
417
|
+
exit(0)
|
393
418
|
end
|
394
419
|
|
395
420
|
# Allows to use private methods from parent in child classes as tasks.
|
396
421
|
#
|
397
|
-
# ====
|
422
|
+
# ==== Parameters
|
398
423
|
# names<Array>:: Method names to be used as tasks
|
399
424
|
#
|
400
425
|
# ==== Examples
|
@@ -408,16 +433,26 @@ class Thor
|
|
408
433
|
end
|
409
434
|
end
|
410
435
|
|
411
|
-
def handle_no_task_error(task) #:nodoc:
|
412
|
-
if
|
436
|
+
def handle_no_task_error(task, has_namespace = $thor_runner) #:nodoc:
|
437
|
+
if has_namespace
|
413
438
|
raise UndefinedTaskError, "Could not find task #{task.inspect} in #{namespace.inspect} namespace."
|
414
439
|
else
|
415
440
|
raise UndefinedTaskError, "Could not find task #{task.inspect}."
|
416
441
|
end
|
417
442
|
end
|
418
443
|
|
419
|
-
def handle_argument_error(task, error) #:nodoc:
|
420
|
-
|
444
|
+
def handle_argument_error(task, error, arity=nil) #:nodoc:
|
445
|
+
msg = "#{basename} #{task.name}"
|
446
|
+
if arity
|
447
|
+
required = arity < 0 ? (-1 - arity) : arity
|
448
|
+
msg << " requires at least #{required} argument"
|
449
|
+
msg << "s" if required > 1
|
450
|
+
else
|
451
|
+
msg = "call #{msg} as"
|
452
|
+
end
|
453
|
+
|
454
|
+
msg << ": #{self.banner(task).inspect}."
|
455
|
+
raise InvocationError, msg
|
421
456
|
end
|
422
457
|
|
423
458
|
protected
|
@@ -450,15 +485,17 @@ class Thor
|
|
450
485
|
padding = options.collect{ |o| o.aliases.size }.max.to_i * 4
|
451
486
|
|
452
487
|
options.each do |option|
|
453
|
-
|
454
|
-
|
488
|
+
unless option.hide
|
489
|
+
item = [ option.usage(padding) ]
|
490
|
+
item.push(option.description ? "# #{option.description}" : "")
|
455
491
|
|
456
|
-
|
457
|
-
|
492
|
+
list << item
|
493
|
+
list << [ "", "# Default: #{option.default}" ] if option.show_default?
|
494
|
+
end
|
458
495
|
end
|
459
496
|
|
460
497
|
shell.say(group_name ? "#{group_name} options:" : "Options:")
|
461
|
-
shell.print_table(list, :
|
498
|
+
shell.print_table(list, :indent => 2)
|
462
499
|
shell.say ""
|
463
500
|
end
|
464
501
|
|
@@ -476,7 +513,7 @@ class Thor
|
|
476
513
|
def build_option(name, options, scope) #:nodoc:
|
477
514
|
scope[name] = Thor::Option.new(name, options[:desc], options[:required],
|
478
515
|
options[:type], options[:default], options[:banner],
|
479
|
-
options[:lazy_default], options[:group], options[:aliases])
|
516
|
+
options[:lazy_default], options[:group], options[:aliases], options[:hide])
|
480
517
|
end
|
481
518
|
|
482
519
|
# Receives a hash of options, parse them and add to the scope. This is a
|
@@ -509,6 +546,7 @@ class Thor
|
|
509
546
|
# and file into baseclass.
|
510
547
|
def inherited(klass)
|
511
548
|
Thor::Base.register_klass_file(klass)
|
549
|
+
klass.instance_variable_set(:@no_tasks, false)
|
512
550
|
end
|
513
551
|
|
514
552
|
# Fire this callback whenever a method is added. Added methods are
|