thor 0.14.6 → 0.15.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|