thor 0.18.1 → 0.19.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.
- checksums.yaml +7 -0
- data/README.md +13 -7
- data/Thorfile +4 -5
- data/bin/thor +1 -1
- data/lib/thor.rb +78 -67
- data/lib/thor/actions.rb +57 -56
- data/lib/thor/actions/create_file.rb +33 -35
- data/lib/thor/actions/create_link.rb +2 -3
- data/lib/thor/actions/directory.rb +37 -38
- data/lib/thor/actions/empty_directory.rb +67 -69
- data/lib/thor/actions/file_manipulation.rb +17 -15
- data/lib/thor/actions/inject_into_file.rb +27 -29
- data/lib/thor/base.rb +193 -189
- data/lib/thor/command.rb +20 -23
- data/lib/thor/core_ext/hash_with_indifferent_access.rb +21 -24
- data/lib/thor/core_ext/io_binary_read.rb +2 -4
- data/lib/thor/core_ext/ordered_hash.rb +9 -11
- data/lib/thor/error.rb +5 -1
- data/lib/thor/group.rb +53 -54
- data/lib/thor/invocation.rb +44 -38
- data/lib/thor/line_editor.rb +17 -0
- data/lib/thor/line_editor/basic.rb +35 -0
- data/lib/thor/line_editor/readline.rb +88 -0
- data/lib/thor/parser.rb +4 -4
- data/lib/thor/parser/argument.rb +28 -29
- data/lib/thor/parser/arguments.rb +102 -98
- data/lib/thor/parser/option.rb +26 -22
- data/lib/thor/parser/options.rb +86 -86
- data/lib/thor/rake_compat.rb +9 -10
- data/lib/thor/runner.rb +141 -141
- data/lib/thor/shell.rb +27 -34
- data/lib/thor/shell/basic.rb +91 -63
- data/lib/thor/shell/color.rb +44 -43
- data/lib/thor/shell/html.rb +59 -60
- data/lib/thor/util.rb +24 -27
- data/lib/thor/version.rb +1 -1
- data/spec/actions/create_file_spec.rb +25 -27
- data/spec/actions/create_link_spec.rb +19 -18
- data/spec/actions/directory_spec.rb +31 -31
- data/spec/actions/empty_directory_spec.rb +18 -18
- data/spec/actions/file_manipulation_spec.rb +38 -28
- data/spec/actions/inject_into_file_spec.rb +13 -13
- data/spec/actions_spec.rb +43 -43
- data/spec/base_spec.rb +45 -38
- data/spec/command_spec.rb +13 -14
- data/spec/core_ext/hash_with_indifferent_access_spec.rb +19 -19
- data/spec/core_ext/ordered_hash_spec.rb +6 -6
- data/spec/exit_condition_spec.rb +4 -4
- data/spec/fixtures/invoke.thor +19 -0
- data/spec/fixtures/script.thor +1 -1
- data/spec/group_spec.rb +30 -24
- data/spec/helper.rb +28 -15
- data/spec/invocation_spec.rb +39 -19
- data/spec/line_editor/basic_spec.rb +28 -0
- data/spec/line_editor/readline_spec.rb +69 -0
- data/spec/line_editor_spec.rb +43 -0
- data/spec/parser/argument_spec.rb +12 -12
- data/spec/parser/arguments_spec.rb +11 -11
- data/spec/parser/option_spec.rb +33 -25
- data/spec/parser/options_spec.rb +66 -52
- data/spec/quality_spec.rb +75 -0
- data/spec/rake_compat_spec.rb +10 -10
- data/spec/register_spec.rb +60 -30
- data/spec/runner_spec.rb +67 -62
- data/spec/sandbox/application.rb +2 -0
- data/spec/sandbox/app{1}/README +3 -0
- data/spec/sandbox/bundle/execute.rb +6 -0
- data/spec/sandbox/bundle/main.thor +1 -0
- data/spec/sandbox/command.thor +10 -0
- data/spec/sandbox/doc/%file_name%.rb.tt +1 -0
- data/spec/sandbox/doc/COMMENTER +11 -0
- data/spec/sandbox/doc/README +3 -0
- data/spec/sandbox/doc/block_helper.rb +3 -0
- data/spec/sandbox/doc/config.rb +1 -0
- data/spec/sandbox/doc/config.yaml.tt +1 -0
- data/spec/sandbox/doc/excluding/%file_name%.rb.tt +1 -0
- data/spec/sandbox/enum.thor +10 -0
- data/spec/sandbox/group.thor +128 -0
- data/spec/sandbox/invoke.thor +131 -0
- data/spec/sandbox/path with spaces b/data/spec/sandbox/path with → spaces +0 -0
- data/spec/sandbox/preserve/script.sh +3 -0
- data/spec/sandbox/script.thor +220 -0
- data/spec/sandbox/subcommand.thor +17 -0
- data/spec/shell/basic_spec.rb +107 -86
- data/spec/shell/color_spec.rb +32 -8
- data/spec/shell/html_spec.rb +3 -4
- data/spec/shell_spec.rb +7 -7
- data/spec/subcommand_spec.rb +20 -2
- data/spec/thor_spec.rb +111 -97
- data/spec/util_spec.rb +30 -30
- data/thor.gemspec +14 -14
- metadata +69 -25
data/lib/thor/shell.rb
CHANGED
@@ -1,33 +1,32 @@
|
|
1
|
-
require
|
1
|
+
require "rbconfig"
|
2
2
|
|
3
3
|
class Thor
|
4
4
|
module Base
|
5
|
-
|
6
|
-
|
7
|
-
#
|
8
|
-
def self.shell
|
9
|
-
@shell ||= if ENV['THOR_SHELL'] && ENV['THOR_SHELL'].size > 0
|
10
|
-
Thor::Shell.const_get(ENV['THOR_SHELL'])
|
11
|
-
elsif ((RbConfig::CONFIG['host_os'] =~ /mswin|mingw/) && !(ENV['ANSICON']))
|
12
|
-
Thor::Shell::Basic
|
13
|
-
else
|
14
|
-
Thor::Shell::Color
|
15
|
-
end
|
16
|
-
end
|
5
|
+
class << self
|
6
|
+
attr_writer :shell
|
17
7
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
8
|
+
# Returns the shell used in all Thor classes. If you are in a Unix platform
|
9
|
+
# it will use a colored log, otherwise it will use a basic one without color.
|
10
|
+
#
|
11
|
+
def shell
|
12
|
+
@shell ||= if ENV["THOR_SHELL"] && ENV["THOR_SHELL"].size > 0
|
13
|
+
Thor::Shell.const_get(ENV["THOR_SHELL"])
|
14
|
+
elsif RbConfig::CONFIG["host_os"] =~ /mswin|mingw/ && !ENV["ANSICON"]
|
15
|
+
Thor::Shell::Basic
|
16
|
+
else
|
17
|
+
Thor::Shell::Color
|
18
|
+
end
|
19
|
+
end
|
22
20
|
end
|
23
21
|
end
|
24
22
|
|
25
23
|
module Shell
|
26
24
|
SHELL_DELEGATED_METHODS = [:ask, :error, :set_color, :yes?, :no?, :say, :say_status, :print_in_columns, :print_table, :print_wrapped, :file_collision, :terminal_width]
|
25
|
+
attr_writer :shell
|
27
26
|
|
28
|
-
autoload :Basic,
|
29
|
-
autoload :Color,
|
30
|
-
autoload :HTML,
|
27
|
+
autoload :Basic, "thor/shell/basic"
|
28
|
+
autoload :Color, "thor/shell/color"
|
29
|
+
autoload :HTML, "thor/shell/html"
|
31
30
|
|
32
31
|
# Add shell to initialize config values.
|
33
32
|
#
|
@@ -42,10 +41,10 @@ class Thor
|
|
42
41
|
#
|
43
42
|
# MyScript.new [1.0], { :foo => :bar }, :shell => Thor::Shell::Basic.new
|
44
43
|
#
|
45
|
-
def initialize(args=[], options={}, config={})
|
44
|
+
def initialize(args = [], options = {}, config = {})
|
46
45
|
super
|
47
46
|
self.shell = config[:shell]
|
48
|
-
|
47
|
+
shell.base ||= self if shell.respond_to?(:base)
|
49
48
|
end
|
50
49
|
|
51
50
|
# Holds the shell for the given Thor instance. If no shell is given,
|
@@ -54,11 +53,6 @@ class Thor
|
|
54
53
|
@shell ||= Thor::Base.shell.new
|
55
54
|
end
|
56
55
|
|
57
|
-
# Sets the shell for this thor class.
|
58
|
-
def shell=(shell)
|
59
|
-
@shell = shell
|
60
|
-
end
|
61
|
-
|
62
56
|
# Common methods that are delegated to the shell.
|
63
57
|
SHELL_DELEGATED_METHODS.each do |method|
|
64
58
|
module_eval <<-METHOD, __FILE__, __LINE__
|
@@ -76,13 +70,12 @@ class Thor
|
|
76
70
|
shell.padding -= 1
|
77
71
|
end
|
78
72
|
|
79
|
-
|
80
|
-
|
81
|
-
# Allow shell to be shared between invocations.
|
82
|
-
#
|
83
|
-
def _shared_configuration #:nodoc:
|
84
|
-
super.merge!(:shell => self.shell)
|
85
|
-
end
|
73
|
+
protected
|
86
74
|
|
75
|
+
# Allow shell to be shared between invocations.
|
76
|
+
#
|
77
|
+
def _shared_configuration #:nodoc:
|
78
|
+
super.merge!(:shell => shell)
|
79
|
+
end
|
87
80
|
end
|
88
81
|
end
|
data/lib/thor/shell/basic.rb
CHANGED
@@ -1,15 +1,16 @@
|
|
1
|
-
require
|
1
|
+
require "tempfile"
|
2
|
+
require "io/console" if RUBY_VERSION > "1.9.2"
|
2
3
|
|
3
4
|
class Thor
|
4
5
|
module Shell
|
5
|
-
class Basic
|
6
|
+
class Basic # rubocop:disable ClassLength
|
6
7
|
attr_accessor :base
|
7
8
|
attr_reader :padding
|
8
9
|
|
9
10
|
# Initialize base, mute and padding to nil.
|
10
11
|
#
|
11
12
|
def initialize #:nodoc:
|
12
|
-
@base, @mute, @padding = nil, false, 0
|
13
|
+
@base, @mute, @padding, @always_force = nil, false, 0, false
|
13
14
|
end
|
14
15
|
|
15
16
|
# Mute everything that's inside given block
|
@@ -23,7 +24,7 @@ class Thor
|
|
23
24
|
|
24
25
|
# Check if base is muted
|
25
26
|
#
|
26
|
-
def mute?
|
27
|
+
def mute? # rubocop:disable TrivialAccessors
|
27
28
|
@mute
|
28
29
|
end
|
29
30
|
|
@@ -40,15 +41,32 @@ class Thor
|
|
40
41
|
# they will be shown a message stating that one of those answers
|
41
42
|
# must be given and re-asked the question.
|
42
43
|
#
|
44
|
+
# If asking for sensitive information, the :echo option can be set
|
45
|
+
# to false to mask user input from $stdin.
|
46
|
+
#
|
47
|
+
# If the required input is a path, then set the path option to
|
48
|
+
# true. This will enable tab completion for file paths relative
|
49
|
+
# to the current working directory on systems that support
|
50
|
+
# Readline.
|
51
|
+
#
|
43
52
|
# ==== Example
|
44
53
|
# ask("What is your name?")
|
45
54
|
#
|
46
55
|
# ask("What is your favorite Neopolitan flavor?", :limited_to => ["strawberry", "chocolate", "vanilla"])
|
47
56
|
#
|
57
|
+
# ask("What is your password?", :echo => false)
|
58
|
+
#
|
59
|
+
# ask("Where should the file be saved?", :path => true)
|
60
|
+
#
|
48
61
|
def ask(statement, *args)
|
49
62
|
options = args.last.is_a?(Hash) ? args.pop : {}
|
63
|
+
color = args.first
|
50
64
|
|
51
|
-
|
65
|
+
if options[:limited_to]
|
66
|
+
ask_filtered(statement, color, options)
|
67
|
+
else
|
68
|
+
ask_simply(statement, color, options)
|
69
|
+
end
|
52
70
|
end
|
53
71
|
|
54
72
|
# Say (print) something to the user. If the sentence ends with a whitespace
|
@@ -58,18 +76,11 @@ class Thor
|
|
58
76
|
# ==== Example
|
59
77
|
# say("I know you knew that.")
|
60
78
|
#
|
61
|
-
def say(message="", color=nil, force_new_line=(message.to_s !~ /( |\t)\Z/))
|
62
|
-
|
79
|
+
def say(message = "", color = nil, force_new_line = (message.to_s !~ /( |\t)\Z/))
|
80
|
+
buffer = prepare_message(message, *color)
|
81
|
+
buffer << "\n" if force_new_line && !message.end_with?("\n")
|
63
82
|
|
64
|
-
|
65
|
-
|
66
|
-
spaces = " " * padding
|
67
|
-
|
68
|
-
if force_new_line
|
69
|
-
stdout.puts(spaces + message)
|
70
|
-
else
|
71
|
-
stdout.print(spaces + message)
|
72
|
-
end
|
83
|
+
stdout.print(buffer)
|
73
84
|
stdout.flush
|
74
85
|
end
|
75
86
|
|
@@ -78,7 +89,7 @@ class Thor
|
|
78
89
|
# in log_status, avoiding the message from being shown. If a Symbol is
|
79
90
|
# given in log_status, it's used as the color.
|
80
91
|
#
|
81
|
-
def say_status(status, message, log_status=true)
|
92
|
+
def say_status(status, message, log_status = true)
|
82
93
|
return if quiet? || log_status == false
|
83
94
|
spaces = " " * (padding + 1)
|
84
95
|
color = log_status.is_a?(Symbol) ? log_status : :green
|
@@ -86,22 +97,25 @@ class Thor
|
|
86
97
|
status = status.to_s.rjust(12)
|
87
98
|
status = set_color status, color, true if color
|
88
99
|
|
89
|
-
|
100
|
+
buffer = "#{status}#{spaces}#{message}"
|
101
|
+
buffer << "\n" unless buffer.end_with?("\n")
|
102
|
+
|
103
|
+
stdout.print(buffer)
|
90
104
|
stdout.flush
|
91
105
|
end
|
92
106
|
|
93
107
|
# Make a question the to user and returns true if the user replies "y" or
|
94
108
|
# "yes".
|
95
109
|
#
|
96
|
-
def yes?(statement, color=nil)
|
97
|
-
!!(ask(statement, color) =~ is?(:yes))
|
110
|
+
def yes?(statement, color = nil)
|
111
|
+
!!(ask(statement, color, :add_to_history => false) =~ is?(:yes))
|
98
112
|
end
|
99
113
|
|
100
114
|
# Make a question the to user and returns true if the user replies "n" or
|
101
115
|
# "no".
|
102
116
|
#
|
103
|
-
def no?(statement, color=nil)
|
104
|
-
|
117
|
+
def no?(statement, color = nil)
|
118
|
+
!!(ask(statement, color, :add_to_history => false) =~ is?(:no))
|
105
119
|
end
|
106
120
|
|
107
121
|
# Prints values in columns
|
@@ -111,7 +125,7 @@ class Thor
|
|
111
125
|
#
|
112
126
|
def print_in_columns(array)
|
113
127
|
return if array.empty?
|
114
|
-
colwidth = (array.map{|el| el.to_s.size}.max || 0) + 2
|
128
|
+
colwidth = (array.map { |el| el.to_s.size }.max || 0) + 2
|
115
129
|
array.each_with_index do |value, index|
|
116
130
|
# Don't output trailing spaces when printing the last column
|
117
131
|
if ((((index + 1) % (terminal_width / colwidth))).zero? && !index.zero?) || index + 1 == array.length
|
@@ -131,7 +145,7 @@ class Thor
|
|
131
145
|
# indent<Integer>:: Indent the first column by indent value.
|
132
146
|
# colwidth<Integer>:: Force the first column to colwidth spaces wide.
|
133
147
|
#
|
134
|
-
def print_table(array, options={})
|
148
|
+
def print_table(array, options = {}) # rubocop:disable MethodLength
|
135
149
|
return if array.empty?
|
136
150
|
|
137
151
|
formats, indent, colwidth = [], options[:indent].to_i, options[:colwidth]
|
@@ -140,12 +154,12 @@ class Thor
|
|
140
154
|
formats << "%-#{colwidth + 2}s" if colwidth
|
141
155
|
start = colwidth ? 1 : 0
|
142
156
|
|
143
|
-
colcount = array.max{|a,b| a.size <=> b.size }.size
|
157
|
+
colcount = array.max { |a, b| a.size <=> b.size }.size
|
144
158
|
|
145
159
|
maximas = []
|
146
160
|
|
147
161
|
start.upto(colcount - 1) do |index|
|
148
|
-
maxima = array.map {|row| row[index] ? row[index].to_s.size : 0 }.max
|
162
|
+
maxima = array.map { |row| row[index] ? row[index].to_s.size : 0 }.max
|
149
163
|
maximas << maxima
|
150
164
|
if index == colcount - 1
|
151
165
|
# Don't output 2 trailing spaces when printing the last column
|
@@ -191,15 +205,13 @@ class Thor
|
|
191
205
|
# ==== Options
|
192
206
|
# indent<Integer>:: Indent each line of the printed paragraph by indent value.
|
193
207
|
#
|
194
|
-
def print_wrapped(message, options={})
|
208
|
+
def print_wrapped(message, options = {})
|
195
209
|
indent = options[:indent] || 0
|
196
210
|
width = terminal_width - indent
|
197
211
|
paras = message.split("\n\n")
|
198
212
|
|
199
213
|
paras.map! do |unwrapped|
|
200
|
-
unwrapped.strip.gsub(/\n/, " ").squeeze(" ").
|
201
|
-
gsub(/.{1,#{width}}(?:\s|\Z)/){($& + 5.chr).
|
202
|
-
gsub(/\n\005/,"\n").gsub(/\005/,"\n")}
|
214
|
+
unwrapped.strip.gsub(/\n/, " ").squeeze(" ").gsub(/.{1,#{width}}(?:\s|\Z)/) { ($& + 5.chr).gsub(/\n\005/, "\n").gsub(/\005/, "\n") }
|
203
215
|
end
|
204
216
|
|
205
217
|
paras.each do |para|
|
@@ -218,12 +230,15 @@ class Thor
|
|
218
230
|
# destination<String>:: the destination file to solve conflicts
|
219
231
|
# block<Proc>:: an optional block that returns the value to be used in diff
|
220
232
|
#
|
221
|
-
def file_collision(destination)
|
233
|
+
def file_collision(destination) # rubocop:disable MethodLength
|
222
234
|
return true if @always_force
|
223
235
|
options = block_given? ? "[Ynaqdh]" : "[Ynaqh]"
|
224
236
|
|
225
|
-
|
226
|
-
answer = ask
|
237
|
+
loop do
|
238
|
+
answer = ask(
|
239
|
+
%[Overwrite #{destination}? (enter "h" for help) #{options}],
|
240
|
+
:add_to_history => false
|
241
|
+
)
|
227
242
|
|
228
243
|
case answer
|
229
244
|
when is?(:yes), is?(:force), ""
|
@@ -233,11 +248,11 @@ class Thor
|
|
233
248
|
when is?(:always)
|
234
249
|
return @always_force = true
|
235
250
|
when is?(:quit)
|
236
|
-
say
|
237
|
-
|
251
|
+
say "Aborting..."
|
252
|
+
fail SystemExit
|
238
253
|
when is?(:diff)
|
239
254
|
show_diff(destination, yield) if block_given?
|
240
|
-
say
|
255
|
+
say "Retrying..."
|
241
256
|
else
|
242
257
|
say file_collision_help
|
243
258
|
end
|
@@ -247,12 +262,12 @@ class Thor
|
|
247
262
|
# This code was copied from Rake, available under MIT-LICENSE
|
248
263
|
# Copyright (c) 2003, 2004 Jim Weirich
|
249
264
|
def terminal_width
|
250
|
-
if ENV[
|
251
|
-
result = ENV[
|
265
|
+
if ENV["THOR_COLUMNS"]
|
266
|
+
result = ENV["THOR_COLUMNS"].to_i
|
252
267
|
else
|
253
268
|
result = unix? ? dynamic_width : 80
|
254
269
|
end
|
255
|
-
|
270
|
+
result < 10 ? 80 : result
|
256
271
|
rescue
|
257
272
|
80
|
258
273
|
end
|
@@ -275,6 +290,11 @@ class Thor
|
|
275
290
|
|
276
291
|
protected
|
277
292
|
|
293
|
+
def prepare_message(message, *color)
|
294
|
+
spaces = " " * padding
|
295
|
+
spaces + set_color(message.to_s, *color)
|
296
|
+
end
|
297
|
+
|
278
298
|
def can_display_colors?
|
279
299
|
false
|
280
300
|
end
|
@@ -288,10 +308,6 @@ class Thor
|
|
288
308
|
$stdout
|
289
309
|
end
|
290
310
|
|
291
|
-
def stdin
|
292
|
-
$stdin
|
293
|
-
end
|
294
|
-
|
295
311
|
def stderr
|
296
312
|
$stderr
|
297
313
|
end
|
@@ -302,23 +318,23 @@ class Thor
|
|
302
318
|
if value.size == 1
|
303
319
|
/\A#{value}\z/i
|
304
320
|
else
|
305
|
-
/\A(#{value}|#{value[0,1]})\z/i
|
321
|
+
/\A(#{value}|#{value[0, 1]})\z/i
|
306
322
|
end
|
307
323
|
end
|
308
324
|
|
309
325
|
def file_collision_help #:nodoc:
|
310
|
-
|
311
|
-
Y - yes, overwrite
|
312
|
-
n - no, do not overwrite
|
313
|
-
a - all, overwrite this and all others
|
314
|
-
q - quit, abort
|
315
|
-
d - diff, show the differences between the old and the new
|
316
|
-
h - help, show this help
|
317
|
-
HELP
|
326
|
+
<<-HELP
|
327
|
+
Y - yes, overwrite
|
328
|
+
n - no, do not overwrite
|
329
|
+
a - all, overwrite this and all others
|
330
|
+
q - quit, abort
|
331
|
+
d - diff, show the differences between the old and the new
|
332
|
+
h - help, show this help
|
333
|
+
HELP
|
318
334
|
end
|
319
335
|
|
320
336
|
def show_diff(destination, content) #:nodoc:
|
321
|
-
diff_cmd = ENV[
|
337
|
+
diff_cmd = ENV["THOR_DIFF"] || ENV["RAILS_DIFF"] || "diff -u"
|
322
338
|
|
323
339
|
Tempfile.open(File.basename(destination), File.dirname(destination)) do |temp|
|
324
340
|
temp.write content
|
@@ -337,11 +353,11 @@ HELP
|
|
337
353
|
end
|
338
354
|
|
339
355
|
def dynamic_width_stty
|
340
|
-
%x
|
356
|
+
%x(stty size 2>/dev/null).split[1].to_i
|
341
357
|
end
|
342
358
|
|
343
359
|
def dynamic_width_tput
|
344
|
-
%x
|
360
|
+
%x(tput cols 2>/dev/null).to_i
|
345
361
|
end
|
346
362
|
|
347
363
|
def unix?
|
@@ -354,7 +370,7 @@ HELP
|
|
354
370
|
if chars.length <= width
|
355
371
|
chars.join
|
356
372
|
else
|
357
|
-
( chars[0, width-3].join
|
373
|
+
( chars[0, width - 3].join) + "..."
|
358
374
|
end
|
359
375
|
end
|
360
376
|
end
|
@@ -372,22 +388,34 @@ HELP
|
|
372
388
|
end
|
373
389
|
end
|
374
390
|
|
375
|
-
def ask_simply(statement, color
|
376
|
-
|
377
|
-
|
391
|
+
def ask_simply(statement, color, options)
|
392
|
+
default = options[:default]
|
393
|
+
message = [statement, ("(#{default})" if default), nil].uniq.join(" ")
|
394
|
+
message = prepare_message(message, color)
|
395
|
+
result = Thor::LineEditor.readline(message, options)
|
396
|
+
|
397
|
+
return unless result
|
398
|
+
|
399
|
+
result.strip!
|
400
|
+
|
401
|
+
if default && result == ""
|
402
|
+
default
|
403
|
+
else
|
404
|
+
result
|
405
|
+
end
|
378
406
|
end
|
379
407
|
|
380
|
-
def ask_filtered(statement,
|
408
|
+
def ask_filtered(statement, color, options)
|
409
|
+
answer_set = options[:limited_to]
|
381
410
|
correct_answer = nil
|
382
411
|
until correct_answer
|
383
|
-
|
412
|
+
answers = answer_set.join(", ")
|
413
|
+
answer = ask_simply("#{statement} [#{answers}]", color, options)
|
384
414
|
correct_answer = answer_set.include?(answer) ? answer : nil
|
385
|
-
answers = answer_set.map(&:inspect).join(", ")
|
386
415
|
say("Your response must be one of: [#{answers}]. Please try again.") unless correct_answer
|
387
416
|
end
|
388
417
|
correct_answer
|
389
418
|
end
|
390
|
-
|
391
419
|
end
|
392
420
|
end
|
393
421
|
end
|
data/lib/thor/shell/color.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require "thor/shell/basic"
|
2
2
|
|
3
3
|
class Thor
|
4
4
|
module Shell
|
@@ -77,7 +77,9 @@ class Thor
|
|
77
77
|
# :on_cyan
|
78
78
|
# :on_white
|
79
79
|
def set_color(string, *colors)
|
80
|
-
if colors.
|
80
|
+
if colors.compact.empty? || !can_display_colors?
|
81
|
+
string
|
82
|
+
elsif colors.all? { |color| color.is_a?(Symbol) || color.is_a?(String) }
|
81
83
|
ansi_colors = colors.map { |color| lookup_color(color) }
|
82
84
|
"#{ansi_colors.join}#{string}#{CLEAR}"
|
83
85
|
else
|
@@ -92,57 +94,56 @@ class Thor
|
|
92
94
|
end
|
93
95
|
end
|
94
96
|
|
95
|
-
|
97
|
+
protected
|
96
98
|
|
97
|
-
|
98
|
-
|
99
|
-
|
99
|
+
def can_display_colors?
|
100
|
+
stdout.tty?
|
101
|
+
end
|
100
102
|
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
103
|
+
# Overwrite show_diff to show diff with colors if Diff::LCS is
|
104
|
+
# available.
|
105
|
+
#
|
106
|
+
def show_diff(destination, content) #:nodoc:
|
107
|
+
if diff_lcs_loaded? && ENV["THOR_DIFF"].nil? && ENV["RAILS_DIFF"].nil?
|
108
|
+
actual = File.binread(destination).to_s.split("\n")
|
109
|
+
content = content.to_s.split("\n")
|
108
110
|
|
109
|
-
|
110
|
-
|
111
|
-
end
|
112
|
-
else
|
113
|
-
super
|
111
|
+
Diff::LCS.sdiff(actual, content).each do |diff|
|
112
|
+
output_diff_line(diff)
|
114
113
|
end
|
114
|
+
else
|
115
|
+
super
|
115
116
|
end
|
117
|
+
end
|
116
118
|
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
end
|
119
|
+
def output_diff_line(diff) #:nodoc:
|
120
|
+
case diff.action
|
121
|
+
when "-"
|
122
|
+
say "- #{diff.old_element.chomp}", :red, true
|
123
|
+
when "+"
|
124
|
+
say "+ #{diff.new_element.chomp}", :green, true
|
125
|
+
when "!"
|
126
|
+
say "- #{diff.old_element.chomp}", :red, true
|
127
|
+
say "+ #{diff.new_element.chomp}", :green, true
|
128
|
+
else
|
129
|
+
say " #{diff.old_element.chomp}", nil, true
|
129
130
|
end
|
131
|
+
end
|
130
132
|
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
133
|
+
# Check if Diff::LCS is loaded. If it is, use it to create pretty output
|
134
|
+
# for diff.
|
135
|
+
#
|
136
|
+
def diff_lcs_loaded? #:nodoc:
|
137
|
+
return true if defined?(Diff::LCS)
|
138
|
+
return @diff_lcs_loaded unless @diff_lcs_loaded.nil?
|
137
139
|
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
end
|
140
|
+
@diff_lcs_loaded = begin
|
141
|
+
require "diff/lcs"
|
142
|
+
true
|
143
|
+
rescue LoadError
|
144
|
+
false
|
144
145
|
end
|
145
|
-
|
146
|
+
end
|
146
147
|
end
|
147
148
|
end
|
148
149
|
end
|