thor 0.20.3 → 1.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -7
- data/lib/thor/actions/create_file.rb +1 -1
- data/lib/thor/actions/create_link.rb +3 -2
- data/lib/thor/actions/directory.rb +7 -17
- data/lib/thor/actions/file_manipulation.rb +14 -12
- data/lib/thor/actions/inject_into_file.rb +20 -10
- data/lib/thor/actions.rb +24 -15
- data/lib/thor/base.rb +59 -38
- data/lib/thor/command.rb +21 -14
- data/lib/thor/core_ext/hash_with_indifferent_access.rb +6 -0
- data/lib/thor/error.rb +23 -22
- data/lib/thor/group.rb +1 -1
- data/lib/thor/invocation.rb +1 -0
- data/lib/thor/line_editor/basic.rb +1 -1
- data/lib/thor/line_editor/readline.rb +6 -6
- data/lib/thor/line_editor.rb +2 -2
- data/lib/thor/nested_context.rb +29 -0
- data/lib/thor/parser/arguments.rb +7 -3
- data/lib/thor/parser/option.rb +20 -7
- data/lib/thor/parser/options.rb +33 -4
- data/lib/thor/parser.rb +4 -4
- data/lib/thor/rake_compat.rb +1 -0
- data/lib/thor/runner.rb +5 -4
- data/lib/thor/shell/basic.rb +37 -7
- data/lib/thor/shell/color.rb +10 -2
- data/lib/thor/shell/html.rb +3 -3
- data/lib/thor/shell.rb +4 -4
- data/lib/thor/util.rb +17 -1
- data/lib/thor/version.rb +1 -1
- data/lib/thor.rb +16 -9
- data/thor.gemspec +10 -2
- metadata +20 -11
- data/CHANGELOG.md +0 -204
- data/lib/thor/core_ext/io_binary_read.rb +0 -12
- data/lib/thor/core_ext/ordered_hash.rb +0 -129
data/lib/thor/error.rb
CHANGED
@@ -1,22 +1,18 @@
|
|
1
1
|
class Thor
|
2
|
-
Correctable =
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
DidYouMean::Correctable
|
18
|
-
rescue LoadError, NameError
|
19
|
-
end
|
2
|
+
Correctable = if defined?(DidYouMean::SpellChecker) && defined?(DidYouMean::Correctable) # rubocop:disable Naming/ConstantName
|
3
|
+
# In order to support versions of Ruby that don't have keyword
|
4
|
+
# arguments, we need our own spell checker class that doesn't take key
|
5
|
+
# words. Even though this code wouldn't be hit because of the check
|
6
|
+
# above, it's still necessary because the interpreter would otherwise be
|
7
|
+
# unable to parse the file.
|
8
|
+
class NoKwargSpellChecker < DidYouMean::SpellChecker # :nodoc:
|
9
|
+
def initialize(dictionary)
|
10
|
+
@dictionary = dictionary
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
DidYouMean::Correctable
|
15
|
+
end
|
20
16
|
|
21
17
|
# Thor::Error is raised when it's caused by wrong usage of thor classes. Those
|
22
18
|
# errors have their backtrace suppressed and are nicely shown to the user.
|
@@ -106,9 +102,14 @@ class Thor
|
|
106
102
|
end
|
107
103
|
|
108
104
|
if Correctable
|
109
|
-
DidYouMean
|
110
|
-
|
111
|
-
|
112
|
-
|
105
|
+
if DidYouMean.respond_to?(:correct_error)
|
106
|
+
DidYouMean.correct_error(Thor::UndefinedCommandError, UndefinedCommandError::SpellChecker)
|
107
|
+
DidYouMean.correct_error(Thor::UnknownArgumentError, UnknownArgumentError::SpellChecker)
|
108
|
+
else
|
109
|
+
DidYouMean::SPELL_CHECKERS.merge!(
|
110
|
+
'Thor::UndefinedCommandError' => UndefinedCommandError::SpellChecker,
|
111
|
+
'Thor::UnknownArgumentError' => UnknownArgumentError::SpellChecker
|
112
|
+
)
|
113
|
+
end
|
113
114
|
end
|
114
115
|
end
|
data/lib/thor/group.rb
CHANGED
data/lib/thor/invocation.rb
CHANGED
@@ -1,19 +1,19 @@
|
|
1
|
-
begin
|
2
|
-
require "readline"
|
3
|
-
rescue LoadError
|
4
|
-
end
|
5
|
-
|
6
1
|
class Thor
|
7
2
|
module LineEditor
|
8
3
|
class Readline < Basic
|
9
4
|
def self.available?
|
5
|
+
begin
|
6
|
+
require "readline"
|
7
|
+
rescue LoadError
|
8
|
+
end
|
9
|
+
|
10
10
|
Object.const_defined?(:Readline)
|
11
11
|
end
|
12
12
|
|
13
13
|
def readline
|
14
14
|
if echo?
|
15
15
|
::Readline.completion_append_character = nil
|
16
|
-
#
|
16
|
+
# rb-readline does not allow Readline.completion_proc= to receive nil.
|
17
17
|
if complete = completion_proc
|
18
18
|
::Readline.completion_proc = complete
|
19
19
|
end
|
data/lib/thor/line_editor.rb
CHANGED
@@ -0,0 +1,29 @@
|
|
1
|
+
class Thor
|
2
|
+
class NestedContext
|
3
|
+
def initialize
|
4
|
+
@depth = 0
|
5
|
+
end
|
6
|
+
|
7
|
+
def enter
|
8
|
+
push
|
9
|
+
|
10
|
+
yield
|
11
|
+
ensure
|
12
|
+
pop
|
13
|
+
end
|
14
|
+
|
15
|
+
def entered?
|
16
|
+
@depth > 0
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def push
|
22
|
+
@depth += 1
|
23
|
+
end
|
24
|
+
|
25
|
+
def pop
|
26
|
+
@depth -= 1
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -9,7 +9,7 @@ class Thor
|
|
9
9
|
arguments = []
|
10
10
|
|
11
11
|
args.each do |item|
|
12
|
-
break if item =~ /^-/
|
12
|
+
break if item.is_a?(String) && item =~ /^-/
|
13
13
|
arguments << item
|
14
14
|
end
|
15
15
|
|
@@ -30,7 +30,11 @@ class Thor
|
|
30
30
|
|
31
31
|
arguments.each do |argument|
|
32
32
|
if !argument.default.nil?
|
33
|
-
|
33
|
+
begin
|
34
|
+
@assigns[argument.human_name] = argument.default.dup
|
35
|
+
rescue TypeError # Compatibility shim for un-dup-able Fixnum in Ruby < 2.4
|
36
|
+
@assigns[argument.human_name] = argument.default
|
37
|
+
end
|
34
38
|
elsif argument.required?
|
35
39
|
@non_assigned_required << argument
|
36
40
|
end
|
@@ -82,7 +86,7 @@ class Thor
|
|
82
86
|
end
|
83
87
|
|
84
88
|
def current_is_value?
|
85
|
-
peek && peek.to_s !~
|
89
|
+
peek && peek.to_s !~ /^-{1,2}\S+/
|
86
90
|
end
|
87
91
|
|
88
92
|
# Runs through the argument array getting strings that contains ":" and
|
data/lib/thor/parser/option.rb
CHANGED
@@ -1,17 +1,18 @@
|
|
1
1
|
class Thor
|
2
2
|
class Option < Argument #:nodoc:
|
3
|
-
attr_reader :aliases, :group, :lazy_default, :hide
|
3
|
+
attr_reader :aliases, :group, :lazy_default, :hide, :repeatable
|
4
4
|
|
5
5
|
VALID_TYPES = [:boolean, :numeric, :hash, :array, :string]
|
6
6
|
|
7
7
|
def initialize(name, options = {})
|
8
8
|
@check_default_type = options[:check_default_type]
|
9
9
|
options[:required] = false unless options.key?(:required)
|
10
|
+
@repeatable = options.fetch(:repeatable, false)
|
10
11
|
super
|
11
|
-
@lazy_default
|
12
|
-
@group
|
13
|
-
@aliases
|
14
|
-
@hide
|
12
|
+
@lazy_default = options[:lazy_default]
|
13
|
+
@group = options[:group].to_s.capitalize if options[:group]
|
14
|
+
@aliases = Array(options[:aliases])
|
15
|
+
@hide = options[:hide]
|
15
16
|
end
|
16
17
|
|
17
18
|
# This parse quick options given as method_options. It makes several
|
@@ -111,7 +112,7 @@ class Thor
|
|
111
112
|
|
112
113
|
def validate!
|
113
114
|
raise ArgumentError, "An option cannot be boolean and required." if boolean? && required?
|
114
|
-
validate_default_type!
|
115
|
+
validate_default_type!
|
115
116
|
end
|
116
117
|
|
117
118
|
def validate_default_type!
|
@@ -128,7 +129,19 @@ class Thor
|
|
128
129
|
@default.class.name.downcase.to_sym
|
129
130
|
end
|
130
131
|
|
131
|
-
|
132
|
+
expected_type = (@repeatable && @type != :hash) ? :array : @type
|
133
|
+
|
134
|
+
if default_type != expected_type
|
135
|
+
err = "Expected #{expected_type} default value for '#{switch_name}'; got #{@default.inspect} (#{default_type})"
|
136
|
+
|
137
|
+
if @check_default_type
|
138
|
+
raise ArgumentError, err
|
139
|
+
elsif @check_default_type == nil
|
140
|
+
Thor.deprecation_warning "#{err}.\n" +
|
141
|
+
'This will be rejected in the future unless you explicitly pass the options `check_default_type: false`' +
|
142
|
+
' or call `allow_incompatible_default_type!` in your code'
|
143
|
+
end
|
144
|
+
end
|
132
145
|
end
|
133
146
|
|
134
147
|
def dasherized?
|
data/lib/thor/parser/options.rb
CHANGED
@@ -45,6 +45,7 @@ class Thor
|
|
45
45
|
@switches = {}
|
46
46
|
@extra = []
|
47
47
|
@stopped_parsing_after_extra_index = nil
|
48
|
+
@is_treated_as_value = false
|
48
49
|
|
49
50
|
options.each do |option|
|
50
51
|
@switches[option.switch_name] = option
|
@@ -74,8 +75,19 @@ class Thor
|
|
74
75
|
end
|
75
76
|
end
|
76
77
|
|
78
|
+
def shift
|
79
|
+
@is_treated_as_value = false
|
80
|
+
super
|
81
|
+
end
|
82
|
+
|
83
|
+
def unshift(arg, is_value: false)
|
84
|
+
@is_treated_as_value = is_value
|
85
|
+
super(arg)
|
86
|
+
end
|
87
|
+
|
77
88
|
def parse(args) # rubocop:disable MethodLength
|
78
89
|
@pile = args.dup
|
90
|
+
@is_treated_as_value = false
|
79
91
|
@parsing_options = true
|
80
92
|
|
81
93
|
while peek
|
@@ -88,7 +100,10 @@ class Thor
|
|
88
100
|
when SHORT_SQ_RE
|
89
101
|
unshift($1.split("").map { |f| "-#{f}" })
|
90
102
|
next
|
91
|
-
when EQ_RE
|
103
|
+
when EQ_RE
|
104
|
+
unshift($2, is_value: true)
|
105
|
+
switch = $1
|
106
|
+
when SHORT_NUM
|
92
107
|
unshift($2)
|
93
108
|
switch = $1
|
94
109
|
when LONG_RE, SHORT_RE
|
@@ -97,7 +112,8 @@ class Thor
|
|
97
112
|
|
98
113
|
switch = normalize_switch(switch)
|
99
114
|
option = switch_option(switch)
|
100
|
-
|
115
|
+
result = parse_peek(switch, option)
|
116
|
+
assign_result!(option, result)
|
101
117
|
elsif @stop_on_unknown
|
102
118
|
@parsing_options = false
|
103
119
|
@extra << shifted
|
@@ -132,11 +148,22 @@ class Thor
|
|
132
148
|
|
133
149
|
protected
|
134
150
|
|
151
|
+
def assign_result!(option, result)
|
152
|
+
if option.repeatable && option.type == :hash
|
153
|
+
(@assigns[option.human_name] ||= {}).merge!(result)
|
154
|
+
elsif option.repeatable
|
155
|
+
(@assigns[option.human_name] ||= []) << result
|
156
|
+
else
|
157
|
+
@assigns[option.human_name] = result
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
135
161
|
# Check if the current value in peek is a registered switch.
|
136
162
|
#
|
137
163
|
# Two booleans are returned. The first is true if the current value
|
138
164
|
# starts with a hyphen; the second is true if it is a registered switch.
|
139
165
|
def current_is_switch?
|
166
|
+
return [false, false] if @is_treated_as_value
|
140
167
|
case peek
|
141
168
|
when LONG_RE, SHORT_RE, EQ_RE, SHORT_NUM
|
142
169
|
[true, switch?($1)]
|
@@ -148,6 +175,7 @@ class Thor
|
|
148
175
|
end
|
149
176
|
|
150
177
|
def current_is_switch_formatted?
|
178
|
+
return false if @is_treated_as_value
|
151
179
|
case peek
|
152
180
|
when LONG_RE, SHORT_RE, EQ_RE, SHORT_NUM, SHORT_SQ_RE
|
153
181
|
true
|
@@ -157,11 +185,12 @@ class Thor
|
|
157
185
|
end
|
158
186
|
|
159
187
|
def current_is_value?
|
188
|
+
return true if @is_treated_as_value
|
160
189
|
peek && (!parsing_options? || super)
|
161
190
|
end
|
162
191
|
|
163
192
|
def switch?(arg)
|
164
|
-
switch_option(normalize_switch(arg))
|
193
|
+
!switch_option(normalize_switch(arg)).nil?
|
165
194
|
end
|
166
195
|
|
167
196
|
def switch_option(arg)
|
@@ -194,7 +223,7 @@ class Thor
|
|
194
223
|
shift
|
195
224
|
false
|
196
225
|
else
|
197
|
-
!no_or_skip?(switch)
|
226
|
+
@switches.key?(switch) || !no_or_skip?(switch)
|
198
227
|
end
|
199
228
|
else
|
200
229
|
@switches.key?(switch) || !no_or_skip?(switch)
|
data/lib/thor/parser.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
1
|
+
require_relative "parser/argument"
|
2
|
+
require_relative "parser/arguments"
|
3
|
+
require_relative "parser/option"
|
4
|
+
require_relative "parser/options"
|
data/lib/thor/rake_compat.rb
CHANGED
@@ -25,6 +25,7 @@ class Thor
|
|
25
25
|
end
|
26
26
|
|
27
27
|
def self.included(base)
|
28
|
+
super(base)
|
28
29
|
# Hack. Make rakefile point to invoker, so rdoc task is generated properly.
|
29
30
|
rakefile = File.basename(caller[0].match(/(.*):\d+/)[1])
|
30
31
|
Rake.application.instance_variable_set(:@rakefile, rakefile)
|
data/lib/thor/runner.rb
CHANGED
@@ -1,12 +1,13 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require "thor/core_ext/io_binary_read"
|
1
|
+
require_relative "../thor"
|
2
|
+
require_relative "group"
|
4
3
|
|
5
4
|
require "yaml"
|
6
5
|
require "digest/md5"
|
7
6
|
require "pathname"
|
8
7
|
|
9
8
|
class Thor::Runner < Thor #:nodoc: # rubocop:disable ClassLength
|
9
|
+
autoload :OpenURI, "open-uri"
|
10
|
+
|
10
11
|
map "-T" => :list, "-i" => :install, "-u" => :update, "-v" => :version
|
11
12
|
|
12
13
|
def self.banner(command, all = false, subcommand = false)
|
@@ -111,7 +112,7 @@ class Thor::Runner < Thor #:nodoc: # rubocop:disable ClassLength
|
|
111
112
|
|
112
113
|
desc "version", "Show Thor version"
|
113
114
|
def version
|
114
|
-
|
115
|
+
require_relative "version"
|
115
116
|
say "Thor #{Thor::VERSION}"
|
116
117
|
end
|
117
118
|
|
data/lib/thor/shell/basic.rb
CHANGED
@@ -94,6 +94,8 @@ class Thor
|
|
94
94
|
# say("I know you knew that.")
|
95
95
|
#
|
96
96
|
def say(message = "", color = nil, force_new_line = (message.to_s !~ /( |\t)\Z/))
|
97
|
+
return if quiet?
|
98
|
+
|
97
99
|
buffer = prepare_message(message, *color)
|
98
100
|
buffer << "\n" if force_new_line && !message.to_s.end_with?("\n")
|
99
101
|
|
@@ -101,6 +103,23 @@ class Thor
|
|
101
103
|
stdout.flush
|
102
104
|
end
|
103
105
|
|
106
|
+
# Say (print) an error to the user. If the sentence ends with a whitespace
|
107
|
+
# or tab character, a new line is not appended (print + flush). Otherwise
|
108
|
+
# are passed straight to puts (behavior got from Highline).
|
109
|
+
#
|
110
|
+
# ==== Example
|
111
|
+
# say_error("error: something went wrong")
|
112
|
+
#
|
113
|
+
def say_error(message = "", color = nil, force_new_line = (message.to_s !~ /( |\t)\Z/))
|
114
|
+
return if quiet?
|
115
|
+
|
116
|
+
buffer = prepare_message(message, *color)
|
117
|
+
buffer << "\n" if force_new_line && !message.to_s.end_with?("\n")
|
118
|
+
|
119
|
+
stderr.print(buffer)
|
120
|
+
stderr.flush
|
121
|
+
end
|
122
|
+
|
104
123
|
# Say a status with the given color and appends the message. Since this
|
105
124
|
# method is used frequently by actions, it allows nil or false to be given
|
106
125
|
# in log_status, avoiding the message from being shown. If a Symbol is
|
@@ -109,13 +128,14 @@ class Thor
|
|
109
128
|
def say_status(status, message, log_status = true)
|
110
129
|
return if quiet? || log_status == false
|
111
130
|
spaces = " " * (padding + 1)
|
112
|
-
color = log_status.is_a?(Symbol) ? log_status : :green
|
113
|
-
|
114
131
|
status = status.to_s.rjust(12)
|
132
|
+
margin = " " * status.length + spaces
|
133
|
+
|
134
|
+
color = log_status.is_a?(Symbol) ? log_status : :green
|
115
135
|
status = set_color status, color, true if color
|
116
136
|
|
117
|
-
|
118
|
-
buffer = "#{
|
137
|
+
message = message.to_s.chomp.gsub(/(?<!\A)^/, margin)
|
138
|
+
buffer = "#{status}#{spaces}#{message}\n"
|
119
139
|
|
120
140
|
stdout.print(buffer)
|
121
141
|
stdout.flush
|
@@ -230,8 +250,9 @@ class Thor
|
|
230
250
|
paras = message.split("\n\n")
|
231
251
|
|
232
252
|
paras.map! do |unwrapped|
|
233
|
-
|
234
|
-
|
253
|
+
words = unwrapped.split(" ")
|
254
|
+
counter = words.first.length
|
255
|
+
words.inject do |memo, word|
|
235
256
|
word = word.gsub(/\n\005/, "\n").gsub(/\005/, "\n")
|
236
257
|
counter = 0 if word.include? "\n"
|
237
258
|
if (counter + word.length + 1) < width
|
@@ -451,16 +472,25 @@ class Thor
|
|
451
472
|
|
452
473
|
def ask_filtered(statement, color, options)
|
453
474
|
answer_set = options[:limited_to]
|
475
|
+
case_insensitive = options.fetch(:case_insensitive, false)
|
454
476
|
correct_answer = nil
|
455
477
|
until correct_answer
|
456
478
|
answers = answer_set.join(", ")
|
457
479
|
answer = ask_simply("#{statement} [#{answers}]", color, options)
|
458
|
-
correct_answer = answer_set
|
480
|
+
correct_answer = answer_match(answer_set, answer, case_insensitive)
|
459
481
|
say("Your response must be one of: [#{answers}]. Please try again.") unless correct_answer
|
460
482
|
end
|
461
483
|
correct_answer
|
462
484
|
end
|
463
485
|
|
486
|
+
def answer_match(possibilities, answer, case_insensitive)
|
487
|
+
if case_insensitive
|
488
|
+
possibilities.detect{ |possibility| possibility.downcase == answer.downcase }
|
489
|
+
else
|
490
|
+
possibilities.detect{ |possibility| possibility == answer }
|
491
|
+
end
|
492
|
+
end
|
493
|
+
|
464
494
|
def merge(destination, content) #:nodoc:
|
465
495
|
require "tempfile"
|
466
496
|
Tempfile.open([File.basename(destination), File.extname(destination)], File.dirname(destination)) do |temp|
|
data/lib/thor/shell/color.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
require_relative "basic"
|
2
2
|
|
3
3
|
class Thor
|
4
4
|
module Shell
|
@@ -97,7 +97,15 @@ class Thor
|
|
97
97
|
protected
|
98
98
|
|
99
99
|
def can_display_colors?
|
100
|
-
|
100
|
+
are_colors_supported? && !are_colors_disabled?
|
101
|
+
end
|
102
|
+
|
103
|
+
def are_colors_supported?
|
104
|
+
stdout.tty? && ENV["TERM"] != "dumb"
|
105
|
+
end
|
106
|
+
|
107
|
+
def are_colors_disabled?
|
108
|
+
!ENV['NO_COLOR'].nil?
|
101
109
|
end
|
102
110
|
|
103
111
|
# Overwrite show_diff to show diff with colors if Diff::LCS is
|
data/lib/thor/shell/html.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
require_relative "basic"
|
2
2
|
|
3
3
|
class Thor
|
4
4
|
module Shell
|
@@ -51,13 +51,13 @@ class Thor
|
|
51
51
|
def set_color(string, *colors)
|
52
52
|
if colors.all? { |color| color.is_a?(Symbol) || color.is_a?(String) }
|
53
53
|
html_colors = colors.map { |color| lookup_color(color) }
|
54
|
-
"<span style=\"#{html_colors.join('; ')};\">#{string}</span>"
|
54
|
+
"<span style=\"#{html_colors.join('; ')};\">#{Thor::Util.escape_html(string)}</span>"
|
55
55
|
else
|
56
56
|
color, bold = colors
|
57
57
|
html_color = self.class.const_get(color.to_s.upcase) if color.is_a?(Symbol)
|
58
58
|
styles = [html_color]
|
59
59
|
styles << BOLD if bold
|
60
|
-
"<span style=\"#{styles.join('; ')};\">#{string}</span>"
|
60
|
+
"<span style=\"#{styles.join('; ')};\">#{Thor::Util.escape_html(string)}</span>"
|
61
61
|
end
|
62
62
|
end
|
63
63
|
|
data/lib/thor/shell.rb
CHANGED
@@ -21,12 +21,12 @@ class Thor
|
|
21
21
|
end
|
22
22
|
|
23
23
|
module Shell
|
24
|
-
SHELL_DELEGATED_METHODS = [:ask, :error, :set_color, :yes?, :no?, :say, :say_status, :print_in_columns, :print_table, :print_wrapped, :file_collision, :terminal_width]
|
24
|
+
SHELL_DELEGATED_METHODS = [:ask, :error, :set_color, :yes?, :no?, :say, :say_error, :say_status, :print_in_columns, :print_table, :print_wrapped, :file_collision, :terminal_width]
|
25
25
|
attr_writer :shell
|
26
26
|
|
27
|
-
autoload :Basic, "
|
28
|
-
autoload :Color, "
|
29
|
-
autoload :HTML, "
|
27
|
+
autoload :Basic, File.expand_path("shell/basic", __dir__)
|
28
|
+
autoload :Color, File.expand_path("shell/color", __dir__)
|
29
|
+
autoload :HTML, File.expand_path("shell/html", __dir__)
|
30
30
|
|
31
31
|
# Add shell to initialize config values.
|
32
32
|
#
|
data/lib/thor/util.rb
CHANGED
@@ -211,7 +211,7 @@ class Thor
|
|
211
211
|
#
|
212
212
|
def globs_for(path)
|
213
213
|
path = escape_globs(path)
|
214
|
-
["#{path}/Thorfile", "#{path}/*.thor", "#{path}/tasks/*.thor", "#{path}/lib/tasks
|
214
|
+
["#{path}/Thorfile", "#{path}/*.thor", "#{path}/tasks/*.thor", "#{path}/lib/tasks/**/*.thor"]
|
215
215
|
end
|
216
216
|
|
217
217
|
# Return the path to the ruby interpreter taking into account multiple
|
@@ -263,6 +263,22 @@ class Thor
|
|
263
263
|
def escape_globs(path)
|
264
264
|
path.to_s.gsub(/[*?{}\[\]]/, '\\\\\\&')
|
265
265
|
end
|
266
|
+
|
267
|
+
# Returns a string that has had any HTML characters escaped.
|
268
|
+
#
|
269
|
+
# ==== Examples
|
270
|
+
#
|
271
|
+
# Thor::Util.escape_html('<div>') # => "<div>"
|
272
|
+
#
|
273
|
+
# ==== Parameters
|
274
|
+
# String
|
275
|
+
#
|
276
|
+
# ==== Returns
|
277
|
+
# String
|
278
|
+
#
|
279
|
+
def escape_html(string)
|
280
|
+
CGI.escapeHTML(string)
|
281
|
+
end
|
266
282
|
end
|
267
283
|
end
|
268
284
|
end
|
data/lib/thor/version.rb
CHANGED
data/lib/thor.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
|
-
|
2
|
-
require "thor/base"
|
1
|
+
require_relative "thor/base"
|
3
2
|
|
4
3
|
class Thor
|
4
|
+
$thor_runner ||= false
|
5
5
|
class << self
|
6
6
|
# Allows for custom "Command" package naming.
|
7
7
|
#
|
@@ -90,9 +90,14 @@ class Thor
|
|
90
90
|
# ==== Parameters
|
91
91
|
# Hash[String|Array => Symbol]:: Maps the string or the strings in the array to the given command.
|
92
92
|
#
|
93
|
-
def map(mappings = nil)
|
93
|
+
def map(mappings = nil, **kw)
|
94
94
|
@map ||= from_superclass(:map, {})
|
95
95
|
|
96
|
+
if mappings && !kw.empty?
|
97
|
+
mappings = kw.merge!(mappings)
|
98
|
+
else
|
99
|
+
mappings ||= kw
|
100
|
+
end
|
96
101
|
if mappings
|
97
102
|
mappings.each do |key, value|
|
98
103
|
if key.respond_to?(:each)
|
@@ -170,7 +175,7 @@ class Thor
|
|
170
175
|
handle_no_command_error(meth) unless command
|
171
176
|
|
172
177
|
shell.say "Usage:"
|
173
|
-
shell.say " #{banner(command)}"
|
178
|
+
shell.say " #{banner(command).split("\n").join("\n ")}"
|
174
179
|
shell.say
|
175
180
|
class_options_help(shell, nil => command.options.values)
|
176
181
|
if command.long_description
|
@@ -318,7 +323,7 @@ class Thor
|
|
318
323
|
# ==== Parameters
|
319
324
|
# Symbol ...:: A list of commands that should be affected.
|
320
325
|
def stop_on_unknown_option!(*command_names)
|
321
|
-
stop_on_unknown_option
|
326
|
+
@stop_on_unknown_option = stop_on_unknown_option | command_names
|
322
327
|
end
|
323
328
|
|
324
329
|
def stop_on_unknown_option?(command) #:nodoc:
|
@@ -332,7 +337,7 @@ class Thor
|
|
332
337
|
# ==== Parameters
|
333
338
|
# Symbol ...:: A list of commands that should be affected.
|
334
339
|
def disable_required_check!(*command_names)
|
335
|
-
disable_required_check
|
340
|
+
@disable_required_check = disable_required_check | command_names
|
336
341
|
end
|
337
342
|
|
338
343
|
def disable_required_check?(command) #:nodoc:
|
@@ -342,12 +347,12 @@ class Thor
|
|
342
347
|
protected
|
343
348
|
|
344
349
|
def stop_on_unknown_option #:nodoc:
|
345
|
-
@stop_on_unknown_option ||=
|
350
|
+
@stop_on_unknown_option ||= []
|
346
351
|
end
|
347
352
|
|
348
353
|
# help command has the required check disabled by default.
|
349
354
|
def disable_required_check #:nodoc:
|
350
|
-
@disable_required_check ||=
|
355
|
+
@disable_required_check ||= [:help]
|
351
356
|
end
|
352
357
|
|
353
358
|
# The method responsible for dispatching given the args.
|
@@ -393,7 +398,9 @@ class Thor
|
|
393
398
|
# the namespace should be displayed as arguments.
|
394
399
|
#
|
395
400
|
def banner(command, namespace = nil, subcommand = false)
|
396
|
-
|
401
|
+
command.formatted_usage(self, $thor_runner, subcommand).split("\n").map do |formatted_usage|
|
402
|
+
"#{basename} #{formatted_usage}"
|
403
|
+
end.join("\n")
|
397
404
|
end
|
398
405
|
|
399
406
|
def baseclass #:nodoc:
|