thor 0.20.3 → 1.3.2
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 +4 -4
- data/README.md +3 -9
- data/lib/thor/actions/create_file.rb +4 -3
- data/lib/thor/actions/create_link.rb +3 -2
- data/lib/thor/actions/directory.rb +8 -18
- data/lib/thor/actions/empty_directory.rb +1 -1
- data/lib/thor/actions/file_manipulation.rb +22 -24
- data/lib/thor/actions/inject_into_file.rb +34 -13
- data/lib/thor/actions.rb +39 -30
- data/lib/thor/base.rb +196 -49
- data/lib/thor/command.rb +34 -18
- data/lib/thor/core_ext/hash_with_indifferent_access.rb +10 -0
- data/lib/thor/error.rb +14 -22
- data/lib/thor/group.rb +13 -2
- data/lib/thor/invocation.rb +2 -1
- 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/argument.rb +17 -1
- data/lib/thor/parser/arguments.rb +35 -15
- data/lib/thor/parser/option.rb +45 -13
- data/lib/thor/parser/options.rb +79 -11
- data/lib/thor/parser.rb +4 -4
- data/lib/thor/rake_compat.rb +3 -2
- data/lib/thor/runner.rb +43 -32
- data/lib/thor/shell/basic.rb +68 -162
- data/lib/thor/shell/color.rb +9 -43
- data/lib/thor/shell/column_printer.rb +29 -0
- data/lib/thor/shell/html.rb +7 -49
- data/lib/thor/shell/lcs_diff.rb +49 -0
- data/lib/thor/shell/table_printer.rb +118 -0
- data/lib/thor/shell/terminal.rb +42 -0
- data/lib/thor/shell/wrapped_printer.rb +38 -0
- data/lib/thor/shell.rb +5 -5
- data/lib/thor/util.rb +25 -8
- data/lib/thor/version.rb +1 -1
- data/lib/thor.rb +182 -17
- data/thor.gemspec +22 -10
- metadata +25 -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/shell/basic.rb
CHANGED
@@ -1,8 +1,10 @@
|
|
1
|
+
require_relative "column_printer"
|
2
|
+
require_relative "table_printer"
|
3
|
+
require_relative "wrapped_printer"
|
4
|
+
|
1
5
|
class Thor
|
2
6
|
module Shell
|
3
7
|
class Basic
|
4
|
-
DEFAULT_TERMINAL_WIDTH = 80
|
5
|
-
|
6
8
|
attr_accessor :base
|
7
9
|
attr_reader :padding
|
8
10
|
|
@@ -65,15 +67,15 @@ class Thor
|
|
65
67
|
# Readline.
|
66
68
|
#
|
67
69
|
# ==== Example
|
68
|
-
#
|
70
|
+
# ask("What is your name?")
|
69
71
|
#
|
70
|
-
#
|
72
|
+
# ask("What is the planet furthest from the sun?", :default => "Neptune")
|
71
73
|
#
|
72
|
-
#
|
74
|
+
# ask("What is your favorite Neopolitan flavor?", :limited_to => ["strawberry", "chocolate", "vanilla"])
|
73
75
|
#
|
74
|
-
#
|
76
|
+
# ask("What is your password?", :echo => false)
|
75
77
|
#
|
76
|
-
#
|
78
|
+
# ask("Where should the file be saved?", :path => true)
|
77
79
|
#
|
78
80
|
def ask(statement, *args)
|
79
81
|
options = args.last.is_a?(Hash) ? args.pop : {}
|
@@ -91,9 +93,11 @@ class Thor
|
|
91
93
|
# are passed straight to puts (behavior got from Highline).
|
92
94
|
#
|
93
95
|
# ==== Example
|
94
|
-
#
|
96
|
+
# say("I know you knew that.")
|
95
97
|
#
|
96
98
|
def say(message = "", color = nil, force_new_line = (message.to_s !~ /( |\t)\Z/))
|
99
|
+
return if quiet?
|
100
|
+
|
97
101
|
buffer = prepare_message(message, *color)
|
98
102
|
buffer << "\n" if force_new_line && !message.to_s.end_with?("\n")
|
99
103
|
|
@@ -101,6 +105,23 @@ class Thor
|
|
101
105
|
stdout.flush
|
102
106
|
end
|
103
107
|
|
108
|
+
# Say (print) an error to the user. If the sentence ends with a whitespace
|
109
|
+
# or tab character, a new line is not appended (print + flush). Otherwise
|
110
|
+
# are passed straight to puts (behavior got from Highline).
|
111
|
+
#
|
112
|
+
# ==== Example
|
113
|
+
# say_error("error: something went wrong")
|
114
|
+
#
|
115
|
+
def say_error(message = "", color = nil, force_new_line = (message.to_s !~ /( |\t)\Z/))
|
116
|
+
return if quiet?
|
117
|
+
|
118
|
+
buffer = prepare_message(message, *color)
|
119
|
+
buffer << "\n" if force_new_line && !message.to_s.end_with?("\n")
|
120
|
+
|
121
|
+
stderr.print(buffer)
|
122
|
+
stderr.flush
|
123
|
+
end
|
124
|
+
|
104
125
|
# Say a status with the given color and appends the message. Since this
|
105
126
|
# method is used frequently by actions, it allows nil or false to be given
|
106
127
|
# in log_status, avoiding the message from being shown. If a Symbol is
|
@@ -109,30 +130,31 @@ class Thor
|
|
109
130
|
def say_status(status, message, log_status = true)
|
110
131
|
return if quiet? || log_status == false
|
111
132
|
spaces = " " * (padding + 1)
|
112
|
-
color = log_status.is_a?(Symbol) ? log_status : :green
|
113
|
-
|
114
133
|
status = status.to_s.rjust(12)
|
134
|
+
margin = " " * status.length + spaces
|
135
|
+
|
136
|
+
color = log_status.is_a?(Symbol) ? log_status : :green
|
115
137
|
status = set_color status, color, true if color
|
116
138
|
|
117
|
-
|
118
|
-
buffer = "#{
|
139
|
+
message = message.to_s.chomp.gsub(/(?<!\A)^/, margin)
|
140
|
+
buffer = "#{status}#{spaces}#{message}\n"
|
119
141
|
|
120
142
|
stdout.print(buffer)
|
121
143
|
stdout.flush
|
122
144
|
end
|
123
145
|
|
124
|
-
#
|
146
|
+
# Asks the user a question and returns true if the user replies "y" or
|
125
147
|
# "yes".
|
126
148
|
#
|
127
149
|
def yes?(statement, color = nil)
|
128
|
-
!!(ask(statement, color, :
|
150
|
+
!!(ask(statement, color, add_to_history: false) =~ is?(:yes))
|
129
151
|
end
|
130
152
|
|
131
|
-
#
|
153
|
+
# Asks the user a question and returns true if the user replies "n" or
|
132
154
|
# "no".
|
133
155
|
#
|
134
156
|
def no?(statement, color = nil)
|
135
|
-
!!(ask(statement, color, :
|
157
|
+
!!(ask(statement, color, add_to_history: false) =~ is?(:no))
|
136
158
|
end
|
137
159
|
|
138
160
|
# Prints values in columns
|
@@ -141,16 +163,8 @@ class Thor
|
|
141
163
|
# Array[String, String, ...]
|
142
164
|
#
|
143
165
|
def print_in_columns(array)
|
144
|
-
|
145
|
-
|
146
|
-
array.each_with_index do |value, index|
|
147
|
-
# Don't output trailing spaces when printing the last column
|
148
|
-
if ((((index + 1) % (terminal_width / colwidth))).zero? && !index.zero?) || index + 1 == array.length
|
149
|
-
stdout.puts value
|
150
|
-
else
|
151
|
-
stdout.printf("%-#{colwidth}s", value)
|
152
|
-
end
|
153
|
-
end
|
166
|
+
printer = ColumnPrinter.new(stdout)
|
167
|
+
printer.print(array)
|
154
168
|
end
|
155
169
|
|
156
170
|
# Prints a table.
|
@@ -161,58 +175,11 @@ class Thor
|
|
161
175
|
# ==== Options
|
162
176
|
# indent<Integer>:: Indent the first column by indent value.
|
163
177
|
# colwidth<Integer>:: Force the first column to colwidth spaces wide.
|
178
|
+
# borders<Boolean>:: Adds ascii borders.
|
164
179
|
#
|
165
|
-
def print_table(array, options = {}) # rubocop:disable MethodLength
|
166
|
-
|
167
|
-
|
168
|
-
formats = []
|
169
|
-
indent = options[:indent].to_i
|
170
|
-
colwidth = options[:colwidth]
|
171
|
-
options[:truncate] = terminal_width if options[:truncate] == true
|
172
|
-
|
173
|
-
formats << "%-#{colwidth + 2}s".dup if colwidth
|
174
|
-
start = colwidth ? 1 : 0
|
175
|
-
|
176
|
-
colcount = array.max { |a, b| a.size <=> b.size }.size
|
177
|
-
|
178
|
-
maximas = []
|
179
|
-
|
180
|
-
start.upto(colcount - 1) do |index|
|
181
|
-
maxima = array.map { |row| row[index] ? row[index].to_s.size : 0 }.max
|
182
|
-
maximas << maxima
|
183
|
-
formats << if index == colcount - 1
|
184
|
-
# Don't output 2 trailing spaces when printing the last column
|
185
|
-
"%-s".dup
|
186
|
-
else
|
187
|
-
"%-#{maxima + 2}s".dup
|
188
|
-
end
|
189
|
-
end
|
190
|
-
|
191
|
-
formats[0] = formats[0].insert(0, " " * indent)
|
192
|
-
formats << "%s"
|
193
|
-
|
194
|
-
array.each do |row|
|
195
|
-
sentence = "".dup
|
196
|
-
|
197
|
-
row.each_with_index do |column, index|
|
198
|
-
maxima = maximas[index]
|
199
|
-
|
200
|
-
f = if column.is_a?(Numeric)
|
201
|
-
if index == row.size - 1
|
202
|
-
# Don't output 2 trailing spaces when printing the last column
|
203
|
-
"%#{maxima}s"
|
204
|
-
else
|
205
|
-
"%#{maxima}s "
|
206
|
-
end
|
207
|
-
else
|
208
|
-
formats[index]
|
209
|
-
end
|
210
|
-
sentence << f % column.to_s
|
211
|
-
end
|
212
|
-
|
213
|
-
sentence = truncate(sentence, options[:truncate]) if options[:truncate]
|
214
|
-
stdout.puts sentence
|
215
|
-
end
|
180
|
+
def print_table(array, options = {}) # rubocop:disable Metrics/MethodLength
|
181
|
+
printer = TablePrinter.new(stdout, options)
|
182
|
+
printer.print(array)
|
216
183
|
end
|
217
184
|
|
218
185
|
# Prints a long string, word-wrapping the text to the current width of the
|
@@ -225,32 +192,8 @@ class Thor
|
|
225
192
|
# indent<Integer>:: Indent each line of the printed paragraph by indent value.
|
226
193
|
#
|
227
194
|
def print_wrapped(message, options = {})
|
228
|
-
|
229
|
-
|
230
|
-
paras = message.split("\n\n")
|
231
|
-
|
232
|
-
paras.map! do |unwrapped|
|
233
|
-
counter = 0
|
234
|
-
unwrapped.split(" ").inject do |memo, word|
|
235
|
-
word = word.gsub(/\n\005/, "\n").gsub(/\005/, "\n")
|
236
|
-
counter = 0 if word.include? "\n"
|
237
|
-
if (counter + word.length + 1) < width
|
238
|
-
memo = "#{memo} #{word}"
|
239
|
-
counter += (word.length + 1)
|
240
|
-
else
|
241
|
-
memo = "#{memo}\n#{word}"
|
242
|
-
counter = word.length
|
243
|
-
end
|
244
|
-
memo
|
245
|
-
end
|
246
|
-
end.compact!
|
247
|
-
|
248
|
-
paras.each do |para|
|
249
|
-
para.split("\n").each do |line|
|
250
|
-
stdout.puts line.insert(0, " " * indent)
|
251
|
-
end
|
252
|
-
stdout.puts unless para == paras.last
|
253
|
-
end
|
195
|
+
printer = WrappedPrinter.new(stdout, options)
|
196
|
+
printer.print(message)
|
254
197
|
end
|
255
198
|
|
256
199
|
# Deals with file collision and returns true if the file should be
|
@@ -268,7 +211,7 @@ class Thor
|
|
268
211
|
loop do
|
269
212
|
answer = ask(
|
270
213
|
%[Overwrite #{destination}? (enter "h" for help) #{options}],
|
271
|
-
:
|
214
|
+
add_to_history: false
|
272
215
|
)
|
273
216
|
|
274
217
|
case answer
|
@@ -295,24 +238,11 @@ class Thor
|
|
295
238
|
|
296
239
|
say "Please specify merge tool to `THOR_MERGE` env."
|
297
240
|
else
|
298
|
-
say file_collision_help
|
241
|
+
say file_collision_help(block_given?)
|
299
242
|
end
|
300
243
|
end
|
301
244
|
end
|
302
245
|
|
303
|
-
# This code was copied from Rake, available under MIT-LICENSE
|
304
|
-
# Copyright (c) 2003, 2004 Jim Weirich
|
305
|
-
def terminal_width
|
306
|
-
result = if ENV["THOR_COLUMNS"]
|
307
|
-
ENV["THOR_COLUMNS"].to_i
|
308
|
-
else
|
309
|
-
unix? ? dynamic_width : DEFAULT_TERMINAL_WIDTH
|
310
|
-
end
|
311
|
-
result < 10 ? DEFAULT_TERMINAL_WIDTH : result
|
312
|
-
rescue
|
313
|
-
DEFAULT_TERMINAL_WIDTH
|
314
|
-
end
|
315
|
-
|
316
246
|
# Called if something goes wrong during the execution. This is used by Thor
|
317
247
|
# internally and should not be used inside your scripts. If something went
|
318
248
|
# wrong, you can always raise an exception. If you raise a Thor::Error, it
|
@@ -363,16 +293,21 @@ class Thor
|
|
363
293
|
end
|
364
294
|
end
|
365
295
|
|
366
|
-
def file_collision_help #:nodoc:
|
367
|
-
<<-HELP
|
296
|
+
def file_collision_help(block_given) #:nodoc:
|
297
|
+
help = <<-HELP
|
368
298
|
Y - yes, overwrite
|
369
299
|
n - no, do not overwrite
|
370
300
|
a - all, overwrite this and all others
|
371
301
|
q - quit, abort
|
372
|
-
d - diff, show the differences between the old and the new
|
373
302
|
h - help, show this help
|
374
|
-
m - merge, run merge tool
|
375
303
|
HELP
|
304
|
+
if block_given
|
305
|
+
help << <<-HELP
|
306
|
+
d - diff, show the differences between the old and the new
|
307
|
+
m - merge, run merge tool
|
308
|
+
HELP
|
309
|
+
end
|
310
|
+
help
|
376
311
|
end
|
377
312
|
|
378
313
|
def show_diff(destination, content) #:nodoc:
|
@@ -390,46 +325,8 @@ class Thor
|
|
390
325
|
mute? || (base && base.options[:quiet])
|
391
326
|
end
|
392
327
|
|
393
|
-
# Calculate the dynamic width of the terminal
|
394
|
-
def dynamic_width
|
395
|
-
@dynamic_width ||= (dynamic_width_stty.nonzero? || dynamic_width_tput)
|
396
|
-
end
|
397
|
-
|
398
|
-
def dynamic_width_stty
|
399
|
-
`stty size 2>/dev/null`.split[1].to_i
|
400
|
-
end
|
401
|
-
|
402
|
-
def dynamic_width_tput
|
403
|
-
`tput cols 2>/dev/null`.to_i
|
404
|
-
end
|
405
|
-
|
406
328
|
def unix?
|
407
|
-
|
408
|
-
end
|
409
|
-
|
410
|
-
def truncate(string, width)
|
411
|
-
as_unicode do
|
412
|
-
chars = string.chars.to_a
|
413
|
-
if chars.length <= width
|
414
|
-
chars.join
|
415
|
-
else
|
416
|
-
chars[0, width - 3].join + "..."
|
417
|
-
end
|
418
|
-
end
|
419
|
-
end
|
420
|
-
|
421
|
-
if "".respond_to?(:encode)
|
422
|
-
def as_unicode
|
423
|
-
yield
|
424
|
-
end
|
425
|
-
else
|
426
|
-
def as_unicode
|
427
|
-
old = $KCODE
|
428
|
-
$KCODE = "U"
|
429
|
-
yield
|
430
|
-
ensure
|
431
|
-
$KCODE = old
|
432
|
-
end
|
329
|
+
Terminal.unix?
|
433
330
|
end
|
434
331
|
|
435
332
|
def ask_simply(statement, color, options)
|
@@ -451,16 +348,25 @@ class Thor
|
|
451
348
|
|
452
349
|
def ask_filtered(statement, color, options)
|
453
350
|
answer_set = options[:limited_to]
|
351
|
+
case_insensitive = options.fetch(:case_insensitive, false)
|
454
352
|
correct_answer = nil
|
455
353
|
until correct_answer
|
456
354
|
answers = answer_set.join(", ")
|
457
355
|
answer = ask_simply("#{statement} [#{answers}]", color, options)
|
458
|
-
correct_answer = answer_set
|
356
|
+
correct_answer = answer_match(answer_set, answer, case_insensitive)
|
459
357
|
say("Your response must be one of: [#{answers}]. Please try again.") unless correct_answer
|
460
358
|
end
|
461
359
|
correct_answer
|
462
360
|
end
|
463
361
|
|
362
|
+
def answer_match(possibilities, answer, case_insensitive)
|
363
|
+
if case_insensitive
|
364
|
+
possibilities.detect{ |possibility| possibility.downcase == answer.downcase }
|
365
|
+
else
|
366
|
+
possibilities.detect{ |possibility| possibility == answer }
|
367
|
+
end
|
368
|
+
end
|
369
|
+
|
464
370
|
def merge(destination, content) #:nodoc:
|
465
371
|
require "tempfile"
|
466
372
|
Tempfile.open([File.basename(destination), File.extname(destination)], File.dirname(destination)) do |temp|
|
data/lib/thor/shell/color.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
|
-
|
1
|
+
require_relative "basic"
|
2
|
+
require_relative "lcs_diff"
|
2
3
|
|
3
4
|
class Thor
|
4
5
|
module Shell
|
@@ -6,6 +7,8 @@ class Thor
|
|
6
7
|
# Thor::Shell::Basic to see all available methods.
|
7
8
|
#
|
8
9
|
class Color < Basic
|
10
|
+
include LCSDiff
|
11
|
+
|
9
12
|
# Embed in a String to clear all previous ANSI sequences.
|
10
13
|
CLEAR = "\e[0m"
|
11
14
|
# The start of an ANSI bold sequence.
|
@@ -97,52 +100,15 @@ class Thor
|
|
97
100
|
protected
|
98
101
|
|
99
102
|
def can_display_colors?
|
100
|
-
|
101
|
-
end
|
102
|
-
|
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")
|
110
|
-
|
111
|
-
Diff::LCS.sdiff(actual, content).each do |diff|
|
112
|
-
output_diff_line(diff)
|
113
|
-
end
|
114
|
-
else
|
115
|
-
super
|
116
|
-
end
|
103
|
+
are_colors_supported? && !are_colors_disabled?
|
117
104
|
end
|
118
105
|
|
119
|
-
def
|
120
|
-
|
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
|
130
|
-
end
|
106
|
+
def are_colors_supported?
|
107
|
+
stdout.tty? && ENV["TERM"] != "dumb"
|
131
108
|
end
|
132
109
|
|
133
|
-
|
134
|
-
|
135
|
-
#
|
136
|
-
def diff_lcs_loaded? #:nodoc:
|
137
|
-
return true if defined?(Diff::LCS)
|
138
|
-
return @diff_lcs_loaded unless @diff_lcs_loaded.nil?
|
139
|
-
|
140
|
-
@diff_lcs_loaded = begin
|
141
|
-
require "diff/lcs"
|
142
|
-
true
|
143
|
-
rescue LoadError
|
144
|
-
false
|
145
|
-
end
|
110
|
+
def are_colors_disabled?
|
111
|
+
!ENV["NO_COLOR"].nil? && !ENV["NO_COLOR"].empty?
|
146
112
|
end
|
147
113
|
end
|
148
114
|
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require_relative "terminal"
|
2
|
+
|
3
|
+
class Thor
|
4
|
+
module Shell
|
5
|
+
class ColumnPrinter
|
6
|
+
attr_reader :stdout, :options
|
7
|
+
|
8
|
+
def initialize(stdout, options = {})
|
9
|
+
@stdout = stdout
|
10
|
+
@options = options
|
11
|
+
@indent = options[:indent].to_i
|
12
|
+
end
|
13
|
+
|
14
|
+
def print(array)
|
15
|
+
return if array.empty?
|
16
|
+
colwidth = (array.map { |el| el.to_s.size }.max || 0) + 2
|
17
|
+
array.each_with_index do |value, index|
|
18
|
+
# Don't output trailing spaces when printing the last column
|
19
|
+
if ((((index + 1) % (Terminal.terminal_width / colwidth))).zero? && !index.zero?) || index + 1 == array.length
|
20
|
+
stdout.puts value
|
21
|
+
else
|
22
|
+
stdout.printf("%-#{colwidth}s", value)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
data/lib/thor/shell/html.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
|
-
|
1
|
+
require_relative "basic"
|
2
|
+
require_relative "lcs_diff"
|
2
3
|
|
3
4
|
class Thor
|
4
5
|
module Shell
|
@@ -6,6 +7,8 @@ class Thor
|
|
6
7
|
# Thor::Shell::Basic to see all available methods.
|
7
8
|
#
|
8
9
|
class HTML < Basic
|
10
|
+
include LCSDiff
|
11
|
+
|
9
12
|
# The start of an HTML bold sequence.
|
10
13
|
BOLD = "font-weight: bold"
|
11
14
|
|
@@ -51,20 +54,20 @@ class Thor
|
|
51
54
|
def set_color(string, *colors)
|
52
55
|
if colors.all? { |color| color.is_a?(Symbol) || color.is_a?(String) }
|
53
56
|
html_colors = colors.map { |color| lookup_color(color) }
|
54
|
-
"<span style=\"#{html_colors.join('; ')};\">#{string}</span>"
|
57
|
+
"<span style=\"#{html_colors.join('; ')};\">#{Thor::Util.escape_html(string)}</span>"
|
55
58
|
else
|
56
59
|
color, bold = colors
|
57
60
|
html_color = self.class.const_get(color.to_s.upcase) if color.is_a?(Symbol)
|
58
61
|
styles = [html_color]
|
59
62
|
styles << BOLD if bold
|
60
|
-
"<span style=\"#{styles.join('; ')};\">#{string}</span>"
|
63
|
+
"<span style=\"#{styles.join('; ')};\">#{Thor::Util.escape_html(string)}</span>"
|
61
64
|
end
|
62
65
|
end
|
63
66
|
|
64
67
|
# Ask something to the user and receives a response.
|
65
68
|
#
|
66
69
|
# ==== Example
|
67
|
-
#
|
70
|
+
# ask("What is your name?")
|
68
71
|
#
|
69
72
|
# TODO: Implement #ask for Thor::Shell::HTML
|
70
73
|
def ask(statement, color = nil)
|
@@ -76,51 +79,6 @@ class Thor
|
|
76
79
|
def can_display_colors?
|
77
80
|
true
|
78
81
|
end
|
79
|
-
|
80
|
-
# Overwrite show_diff to show diff with colors if Diff::LCS is
|
81
|
-
# available.
|
82
|
-
#
|
83
|
-
def show_diff(destination, content) #:nodoc:
|
84
|
-
if diff_lcs_loaded? && ENV["THOR_DIFF"].nil? && ENV["RAILS_DIFF"].nil?
|
85
|
-
actual = File.binread(destination).to_s.split("\n")
|
86
|
-
content = content.to_s.split("\n")
|
87
|
-
|
88
|
-
Diff::LCS.sdiff(actual, content).each do |diff|
|
89
|
-
output_diff_line(diff)
|
90
|
-
end
|
91
|
-
else
|
92
|
-
super
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
def output_diff_line(diff) #:nodoc:
|
97
|
-
case diff.action
|
98
|
-
when "-"
|
99
|
-
say "- #{diff.old_element.chomp}", :red, true
|
100
|
-
when "+"
|
101
|
-
say "+ #{diff.new_element.chomp}", :green, true
|
102
|
-
when "!"
|
103
|
-
say "- #{diff.old_element.chomp}", :red, true
|
104
|
-
say "+ #{diff.new_element.chomp}", :green, true
|
105
|
-
else
|
106
|
-
say " #{diff.old_element.chomp}", nil, true
|
107
|
-
end
|
108
|
-
end
|
109
|
-
|
110
|
-
# Check if Diff::LCS is loaded. If it is, use it to create pretty output
|
111
|
-
# for diff.
|
112
|
-
#
|
113
|
-
def diff_lcs_loaded? #:nodoc:
|
114
|
-
return true if defined?(Diff::LCS)
|
115
|
-
return @diff_lcs_loaded unless @diff_lcs_loaded.nil?
|
116
|
-
|
117
|
-
@diff_lcs_loaded = begin
|
118
|
-
require "diff/lcs"
|
119
|
-
true
|
120
|
-
rescue LoadError
|
121
|
-
false
|
122
|
-
end
|
123
|
-
end
|
124
82
|
end
|
125
83
|
end
|
126
84
|
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module LCSDiff
|
2
|
+
protected
|
3
|
+
|
4
|
+
# Overwrite show_diff to show diff with colors if Diff::LCS is
|
5
|
+
# available.
|
6
|
+
def show_diff(destination, content) #:nodoc:
|
7
|
+
if diff_lcs_loaded? && ENV["THOR_DIFF"].nil? && ENV["RAILS_DIFF"].nil?
|
8
|
+
actual = File.binread(destination).to_s.split("\n")
|
9
|
+
content = content.to_s.split("\n")
|
10
|
+
|
11
|
+
Diff::LCS.sdiff(actual, content).each do |diff|
|
12
|
+
output_diff_line(diff)
|
13
|
+
end
|
14
|
+
else
|
15
|
+
super
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def output_diff_line(diff) #:nodoc:
|
22
|
+
case diff.action
|
23
|
+
when "-"
|
24
|
+
say "- #{diff.old_element.chomp}", :red, true
|
25
|
+
when "+"
|
26
|
+
say "+ #{diff.new_element.chomp}", :green, true
|
27
|
+
when "!"
|
28
|
+
say "- #{diff.old_element.chomp}", :red, true
|
29
|
+
say "+ #{diff.new_element.chomp}", :green, true
|
30
|
+
else
|
31
|
+
say " #{diff.old_element.chomp}", nil, true
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Check if Diff::LCS is loaded. If it is, use it to create pretty output
|
36
|
+
# for diff.
|
37
|
+
def diff_lcs_loaded? #:nodoc:
|
38
|
+
return true if defined?(Diff::LCS)
|
39
|
+
return @diff_lcs_loaded unless @diff_lcs_loaded.nil?
|
40
|
+
|
41
|
+
@diff_lcs_loaded = begin
|
42
|
+
require "diff/lcs"
|
43
|
+
true
|
44
|
+
rescue LoadError
|
45
|
+
false
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|