thor 0.14.6 → 0.19.4
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.
- checksums.yaml +7 -0
- data/.document +5 -0
- data/{CHANGELOG.rdoc → CHANGELOG.md} +91 -31
- data/CONTRIBUTING.md +15 -0
- data/{LICENSE → LICENSE.md} +2 -2
- data/README.md +36 -296
- data/bin/thor +1 -1
- data/lib/thor/actions/create_file.rb +33 -35
- data/lib/thor/actions/create_link.rb +7 -5
- data/lib/thor/actions/directory.rb +49 -24
- data/lib/thor/actions/empty_directory.rb +68 -67
- data/lib/thor/actions/file_manipulation.rb +85 -28
- data/lib/thor/actions/inject_into_file.rb +26 -32
- data/lib/thor/actions.rb +70 -66
- data/lib/thor/base.rb +314 -237
- data/lib/thor/command.rb +133 -0
- data/lib/thor/core_ext/hash_with_indifferent_access.rb +34 -24
- data/lib/thor/core_ext/io_binary_read.rb +12 -0
- data/lib/thor/core_ext/ordered_hash.rb +94 -65
- data/lib/thor/error.rb +10 -8
- data/lib/thor/group.rb +74 -66
- data/lib/thor/invocation.rb +65 -56
- data/lib/thor/line_editor/basic.rb +35 -0
- data/lib/thor/line_editor/readline.rb +88 -0
- data/lib/thor/line_editor.rb +17 -0
- data/lib/thor/parser/argument.rb +32 -29
- data/lib/thor/parser/arguments.rb +107 -93
- data/lib/thor/parser/option.rb +39 -13
- data/lib/thor/parser/options.rb +144 -97
- data/lib/thor/parser.rb +4 -4
- data/lib/thor/rake_compat.rb +21 -16
- data/lib/thor/runner.rb +166 -153
- data/lib/thor/shell/basic.rb +268 -122
- data/lib/thor/shell/color.rb +84 -43
- data/lib/thor/shell/html.rb +71 -66
- data/lib/thor/shell.rb +30 -37
- data/lib/thor/util.rb +227 -188
- data/lib/thor/version.rb +1 -1
- data/lib/thor.rb +289 -131
- data/thor.gemspec +21 -0
- metadata +50 -189
- data/Thorfile +0 -24
- data/bin/rake2thor +0 -86
- data/lib/thor/core_ext/file_binary_read.rb +0 -9
- data/lib/thor/task.rb +0 -114
- data/spec/actions/create_file_spec.rb +0 -170
- data/spec/actions/directory_spec.rb +0 -136
- data/spec/actions/empty_directory_spec.rb +0 -98
- data/spec/actions/file_manipulation_spec.rb +0 -310
- data/spec/actions/inject_into_file_spec.rb +0 -135
- data/spec/actions_spec.rb +0 -322
- data/spec/base_spec.rb +0 -269
- data/spec/core_ext/hash_with_indifferent_access_spec.rb +0 -43
- data/spec/core_ext/ordered_hash_spec.rb +0 -115
- data/spec/fixtures/application.rb +0 -2
- data/spec/fixtures/bundle/execute.rb +0 -6
- data/spec/fixtures/bundle/main.thor +0 -1
- data/spec/fixtures/doc/%file_name%.rb.tt +0 -1
- data/spec/fixtures/doc/README +0 -3
- data/spec/fixtures/doc/block_helper.rb +0 -3
- data/spec/fixtures/doc/components/.empty_directory +0 -0
- data/spec/fixtures/doc/config.rb +0 -1
- data/spec/fixtures/group.thor +0 -114
- data/spec/fixtures/invoke.thor +0 -112
- data/spec/fixtures/path with spaces +0 -0
- data/spec/fixtures/script.thor +0 -184
- data/spec/fixtures/task.thor +0 -10
- data/spec/group_spec.rb +0 -178
- data/spec/invocation_spec.rb +0 -100
- data/spec/parser/argument_spec.rb +0 -47
- data/spec/parser/arguments_spec.rb +0 -64
- data/spec/parser/option_spec.rb +0 -202
- data/spec/parser/options_spec.rb +0 -319
- data/spec/rake_compat_spec.rb +0 -68
- data/spec/register_spec.rb +0 -92
- data/spec/runner_spec.rb +0 -210
- data/spec/shell/basic_spec.rb +0 -223
- data/spec/shell/color_spec.rb +0 -41
- data/spec/shell/html_spec.rb +0 -27
- data/spec/shell_spec.rb +0 -47
- data/spec/spec_helper.rb +0 -54
- data/spec/task_spec.rb +0 -69
- data/spec/thor_spec.rb +0 -334
- data/spec/util_spec.rb +0 -163
data/lib/thor/command.rb
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
class Thor
|
|
2
|
+
class Command < Struct.new(:name, :description, :long_description, :usage, :options, :disable_class_options)
|
|
3
|
+
FILE_REGEXP = /^#{Regexp.escape(File.dirname(__FILE__))}/
|
|
4
|
+
|
|
5
|
+
def initialize(name, description, long_description, usage, options = nil, disable_class_options = false)
|
|
6
|
+
super(name.to_s, description, long_description, usage, options || {}, disable_class_options)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def initialize_copy(other) #:nodoc:
|
|
10
|
+
super(other)
|
|
11
|
+
self.options = other.options.dup if other.options
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def hidden?
|
|
15
|
+
false
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# By default, a command invokes a method in the thor class. You can change this
|
|
19
|
+
# implementation to create custom commands.
|
|
20
|
+
def run(instance, args = [])
|
|
21
|
+
arity = nil
|
|
22
|
+
|
|
23
|
+
if private_method?(instance)
|
|
24
|
+
instance.class.handle_no_command_error(name)
|
|
25
|
+
elsif public_method?(instance)
|
|
26
|
+
arity = instance.method(name).arity
|
|
27
|
+
instance.__send__(name, *args)
|
|
28
|
+
elsif local_method?(instance, :method_missing)
|
|
29
|
+
instance.__send__(:method_missing, name.to_sym, *args)
|
|
30
|
+
else
|
|
31
|
+
instance.class.handle_no_command_error(name)
|
|
32
|
+
end
|
|
33
|
+
rescue ArgumentError => e
|
|
34
|
+
handle_argument_error?(instance, e, caller) ? instance.class.handle_argument_error(self, e, args, arity) : (raise e)
|
|
35
|
+
rescue NoMethodError => e
|
|
36
|
+
handle_no_method_error?(instance, e, caller) ? instance.class.handle_no_command_error(name) : (raise e)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Returns the formatted usage by injecting given required arguments
|
|
40
|
+
# and required options into the given usage.
|
|
41
|
+
def formatted_usage(klass, namespace = true, subcommand = false)
|
|
42
|
+
if namespace
|
|
43
|
+
namespace = klass.namespace
|
|
44
|
+
formatted = "#{namespace.gsub(/^(default)/, '')}:"
|
|
45
|
+
end
|
|
46
|
+
formatted = "#{klass.namespace.split(':').last} " if subcommand
|
|
47
|
+
|
|
48
|
+
formatted ||= ""
|
|
49
|
+
|
|
50
|
+
# Add usage with required arguments
|
|
51
|
+
formatted << if klass && !klass.arguments.empty?
|
|
52
|
+
usage.to_s.gsub(/^#{name}/) do |match|
|
|
53
|
+
match << " " << klass.arguments.map(&:usage).compact.join(" ")
|
|
54
|
+
end
|
|
55
|
+
else
|
|
56
|
+
usage.to_s
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Add required options
|
|
60
|
+
formatted << " #{required_options}"
|
|
61
|
+
|
|
62
|
+
# Strip and go!
|
|
63
|
+
formatted.strip
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
protected
|
|
67
|
+
|
|
68
|
+
def not_debugging?(instance)
|
|
69
|
+
!(instance.class.respond_to?(:debugging) && instance.class.debugging)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def required_options
|
|
73
|
+
@required_options ||= options.map { |_, o| o.usage if o.required? }.compact.sort.join(" ")
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Given a target, checks if this class name is a public method.
|
|
77
|
+
def public_method?(instance) #:nodoc:
|
|
78
|
+
!(instance.public_methods & [name.to_s, name.to_sym]).empty?
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def private_method?(instance)
|
|
82
|
+
!(instance.private_methods & [name.to_s, name.to_sym]).empty?
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def local_method?(instance, name)
|
|
86
|
+
methods = instance.public_methods(false) + instance.private_methods(false) + instance.protected_methods(false)
|
|
87
|
+
!(methods & [name.to_s, name.to_sym]).empty?
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def sans_backtrace(backtrace, caller) #:nodoc:
|
|
91
|
+
saned = backtrace.reject { |frame| frame =~ FILE_REGEXP || (frame =~ /\.java:/ && RUBY_PLATFORM =~ /java/) || (frame =~ %r{^kernel/} && RUBY_ENGINE =~ /rbx/) }
|
|
92
|
+
saned - caller
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def handle_argument_error?(instance, error, caller)
|
|
96
|
+
not_debugging?(instance) && (error.message =~ /wrong number of arguments/ || error.message =~ /given \d*, expected \d*/) && begin
|
|
97
|
+
saned = sans_backtrace(error.backtrace, caller)
|
|
98
|
+
# Ruby 1.9 always include the called method in the backtrace
|
|
99
|
+
saned.empty? || (saned.size == 1 && RUBY_VERSION >= "1.9")
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def handle_no_method_error?(instance, error, caller)
|
|
104
|
+
not_debugging?(instance) &&
|
|
105
|
+
error.message =~ /^undefined method `#{name}' for #{Regexp.escape(instance.to_s)}$/
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
Task = Command
|
|
109
|
+
|
|
110
|
+
# A command that is hidden in help messages but still invocable.
|
|
111
|
+
class HiddenCommand < Command
|
|
112
|
+
def hidden?
|
|
113
|
+
true
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
HiddenTask = HiddenCommand
|
|
117
|
+
|
|
118
|
+
# A dynamic command that handles method missing scenarios.
|
|
119
|
+
class DynamicCommand < Command
|
|
120
|
+
def initialize(name, options = nil)
|
|
121
|
+
super(name.to_s, "A dynamically-generated command", name.to_s, name.to_s, options)
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def run(instance, args = [])
|
|
125
|
+
if (instance.methods & [name.to_s, name.to_sym]).empty?
|
|
126
|
+
super
|
|
127
|
+
else
|
|
128
|
+
instance.class.handle_no_command_error(name)
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
DynamicTask = DynamicCommand
|
|
133
|
+
end
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
class Thor
|
|
2
2
|
module CoreExt #:nodoc:
|
|
3
|
-
|
|
4
3
|
# A hash with indifferent access and magic predicates.
|
|
5
4
|
#
|
|
6
5
|
# hash = Thor::CoreExt::HashWithIndifferentAccess.new 'foo' => 'bar', 'baz' => 'bee', 'force' => true
|
|
@@ -10,8 +9,7 @@ class Thor
|
|
|
10
9
|
# hash.foo? #=> true
|
|
11
10
|
#
|
|
12
11
|
class HashWithIndifferentAccess < ::Hash #:nodoc:
|
|
13
|
-
|
|
14
|
-
def initialize(hash={})
|
|
12
|
+
def initialize(hash = {})
|
|
15
13
|
super()
|
|
16
14
|
hash.each do |key, value|
|
|
17
15
|
self[convert_key(key)] = value
|
|
@@ -30,8 +28,16 @@ class Thor
|
|
|
30
28
|
super(convert_key(key))
|
|
31
29
|
end
|
|
32
30
|
|
|
31
|
+
def fetch(key, *args)
|
|
32
|
+
super(convert_key(key), *args)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def key?(key)
|
|
36
|
+
super(convert_key(key))
|
|
37
|
+
end
|
|
38
|
+
|
|
33
39
|
def values_at(*indices)
|
|
34
|
-
indices.
|
|
40
|
+
indices.map { |key| self[convert_key(key)] }
|
|
35
41
|
end
|
|
36
42
|
|
|
37
43
|
def merge(other)
|
|
@@ -45,31 +51,35 @@ class Thor
|
|
|
45
51
|
self
|
|
46
52
|
end
|
|
47
53
|
|
|
48
|
-
|
|
54
|
+
# Convert to a Hash with String keys.
|
|
55
|
+
def to_hash
|
|
56
|
+
Hash.new(default).merge!(self)
|
|
57
|
+
end
|
|
49
58
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
59
|
+
protected
|
|
60
|
+
|
|
61
|
+
def convert_key(key)
|
|
62
|
+
key.is_a?(Symbol) ? key.to_s : key
|
|
63
|
+
end
|
|
53
64
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
else
|
|
66
|
-
self[$1] == args.first
|
|
67
|
-
end
|
|
65
|
+
# Magic predicates. For instance:
|
|
66
|
+
#
|
|
67
|
+
# options.force? # => !!options['force']
|
|
68
|
+
# options.shebang # => "/usr/lib/local/ruby"
|
|
69
|
+
# options.test_framework?(:rspec) # => options[:test_framework] == :rspec
|
|
70
|
+
#
|
|
71
|
+
def method_missing(method, *args)
|
|
72
|
+
method = method.to_s
|
|
73
|
+
if method =~ /^(\w+)\?$/
|
|
74
|
+
if args.empty?
|
|
75
|
+
!!self[$1]
|
|
68
76
|
else
|
|
69
|
-
self[
|
|
77
|
+
self[$1] == args.first
|
|
70
78
|
end
|
|
79
|
+
else
|
|
80
|
+
self[method]
|
|
71
81
|
end
|
|
72
|
-
|
|
82
|
+
end
|
|
73
83
|
end
|
|
74
84
|
end
|
|
75
85
|
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
class IO #:nodoc:
|
|
2
|
+
class << self
|
|
3
|
+
unless method_defined? :binread
|
|
4
|
+
def binread(file, *args)
|
|
5
|
+
raise ArgumentError, "wrong number of arguments (#{1 + args.size} for 1..3)" unless args.size < 3
|
|
6
|
+
File.open(file, "rb") do |f|
|
|
7
|
+
f.read(*args)
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -1,100 +1,129 @@
|
|
|
1
1
|
class Thor
|
|
2
|
-
module CoreExt
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
# This class is based on the Ruby 1.9 ordered hashes.
|
|
9
|
-
#
|
|
10
|
-
# It keeps the semantics and most of the efficiency of normal hashes
|
|
11
|
-
# while also keeping track of the order in which elements were set.
|
|
12
|
-
#
|
|
13
|
-
class OrderedHash #:nodoc:
|
|
14
|
-
include Enumerable
|
|
15
|
-
|
|
16
|
-
Node = Struct.new(:key, :value, :next, :prev)
|
|
17
|
-
|
|
18
|
-
def initialize
|
|
19
|
-
@hash = {}
|
|
2
|
+
module CoreExt
|
|
3
|
+
class OrderedHash < ::Hash
|
|
4
|
+
if RUBY_VERSION < "1.9"
|
|
5
|
+
def initialize(*args, &block)
|
|
6
|
+
super
|
|
7
|
+
@keys = []
|
|
20
8
|
end
|
|
21
9
|
|
|
22
|
-
def
|
|
23
|
-
|
|
10
|
+
def initialize_copy(other)
|
|
11
|
+
super
|
|
12
|
+
# make a deep copy of keys
|
|
13
|
+
@keys = other.keys
|
|
24
14
|
end
|
|
25
15
|
|
|
26
16
|
def []=(key, value)
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
else
|
|
30
|
-
node = Node.new(key, value)
|
|
31
|
-
|
|
32
|
-
if @first.nil?
|
|
33
|
-
@first = @last = node
|
|
34
|
-
else
|
|
35
|
-
node.prev = @last
|
|
36
|
-
@last.next = node
|
|
37
|
-
@last = node
|
|
38
|
-
end
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
@hash[key] = node
|
|
42
|
-
value
|
|
17
|
+
@keys << key unless key?(key)
|
|
18
|
+
super
|
|
43
19
|
end
|
|
44
20
|
|
|
45
21
|
def delete(key)
|
|
46
|
-
if
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
22
|
+
if key? key
|
|
23
|
+
index = @keys.index(key)
|
|
24
|
+
@keys.delete_at index
|
|
25
|
+
end
|
|
26
|
+
super
|
|
27
|
+
end
|
|
52
28
|
|
|
53
|
-
|
|
54
|
-
|
|
29
|
+
def delete_if
|
|
30
|
+
super
|
|
31
|
+
sync_keys!
|
|
32
|
+
self
|
|
33
|
+
end
|
|
55
34
|
|
|
56
|
-
|
|
57
|
-
end
|
|
35
|
+
alias_method :reject!, :delete_if
|
|
58
36
|
|
|
59
|
-
|
|
60
|
-
|
|
37
|
+
def reject(&block)
|
|
38
|
+
dup.reject!(&block)
|
|
61
39
|
end
|
|
62
40
|
|
|
63
41
|
def keys
|
|
64
|
-
|
|
42
|
+
@keys.dup
|
|
65
43
|
end
|
|
66
44
|
|
|
67
45
|
def values
|
|
68
|
-
|
|
46
|
+
@keys.map { |key| self[key] }
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def to_hash
|
|
50
|
+
self
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def to_a
|
|
54
|
+
@keys.map { |key| [key, self[key]] }
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def each_key
|
|
58
|
+
return to_enum(:each_key) unless block_given?
|
|
59
|
+
@keys.each { |key| yield(key) }
|
|
60
|
+
self
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def each_value
|
|
64
|
+
return to_enum(:each_value) unless block_given?
|
|
65
|
+
@keys.each { |key| yield(self[key]) }
|
|
66
|
+
self
|
|
69
67
|
end
|
|
70
68
|
|
|
71
69
|
def each
|
|
72
|
-
return unless
|
|
73
|
-
|
|
74
|
-
node = @first
|
|
75
|
-
yield [node.key, node.value] while node = node.next
|
|
70
|
+
return to_enum(:each) unless block_given?
|
|
71
|
+
@keys.each { |key| yield([key, self[key]]) }
|
|
76
72
|
self
|
|
77
73
|
end
|
|
78
74
|
|
|
79
|
-
def
|
|
80
|
-
|
|
75
|
+
def each_pair
|
|
76
|
+
return to_enum(:each_pair) unless block_given?
|
|
77
|
+
@keys.each { |key| yield(key, self[key]) }
|
|
78
|
+
self
|
|
79
|
+
end
|
|
81
80
|
|
|
82
|
-
|
|
83
|
-
hash[key] = value
|
|
84
|
-
end
|
|
81
|
+
alias_method :select, :find_all
|
|
85
82
|
|
|
86
|
-
|
|
87
|
-
|
|
83
|
+
def clear
|
|
84
|
+
super
|
|
85
|
+
@keys.clear
|
|
86
|
+
self
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def shift
|
|
90
|
+
k = @keys.first
|
|
91
|
+
v = delete(k)
|
|
92
|
+
[k, v]
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def merge!(other_hash)
|
|
96
|
+
if block_given?
|
|
97
|
+
other_hash.each { |k, v| self[k] = key?(k) ? yield(k, self[k], v) : v }
|
|
98
|
+
else
|
|
99
|
+
other_hash.each { |k, v| self[k] = v }
|
|
88
100
|
end
|
|
101
|
+
self
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
alias_method :update, :merge!
|
|
105
|
+
|
|
106
|
+
def merge(other_hash, &block)
|
|
107
|
+
dup.merge!(other_hash, &block)
|
|
108
|
+
end
|
|
89
109
|
|
|
90
|
-
|
|
110
|
+
# When replacing with another hash, the initial order of our keys must come from the other hash -ordered or not.
|
|
111
|
+
def replace(other)
|
|
112
|
+
super
|
|
113
|
+
@keys = other.keys
|
|
114
|
+
self
|
|
91
115
|
end
|
|
92
116
|
|
|
93
|
-
def
|
|
94
|
-
|
|
117
|
+
def inspect
|
|
118
|
+
"#<#{self.class} #{super}>"
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
private
|
|
122
|
+
|
|
123
|
+
def sync_keys!
|
|
124
|
+
@keys.delete_if { |k| !key?(k) }
|
|
95
125
|
end
|
|
96
126
|
end
|
|
97
127
|
end
|
|
98
|
-
|
|
99
128
|
end
|
|
100
129
|
end
|
data/lib/thor/error.rb
CHANGED
|
@@ -1,21 +1,23 @@
|
|
|
1
1
|
class Thor
|
|
2
2
|
# Thor::Error is raised when it's caused by wrong usage of thor classes. Those
|
|
3
|
-
# errors have their backtrace
|
|
3
|
+
# errors have their backtrace suppressed and are nicely shown to the user.
|
|
4
4
|
#
|
|
5
5
|
# Errors that are caused by the developer, like declaring a method which
|
|
6
|
-
# overwrites a thor keyword,
|
|
6
|
+
# overwrites a thor keyword, SHOULD NOT raise a Thor::Error. This way, we
|
|
7
7
|
# ensure that developer errors are shown with full backtrace.
|
|
8
|
-
#
|
|
9
8
|
class Error < StandardError
|
|
10
9
|
end
|
|
11
10
|
|
|
12
|
-
# Raised when a
|
|
13
|
-
|
|
14
|
-
class UndefinedTaskError < Error
|
|
11
|
+
# Raised when a command was not found.
|
|
12
|
+
class UndefinedCommandError < Error
|
|
15
13
|
end
|
|
14
|
+
UndefinedTaskError = UndefinedCommandError
|
|
16
15
|
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
class AmbiguousCommandError < Error
|
|
17
|
+
end
|
|
18
|
+
AmbiguousTaskError = AmbiguousCommandError
|
|
19
|
+
|
|
20
|
+
# Raised when a command was found, but not invoked properly.
|
|
19
21
|
class InvocationError < Error
|
|
20
22
|
end
|
|
21
23
|
|