thor 0.20.0 → 1.2.1

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.
@@ -1,6 +1,8 @@
1
1
  class Thor
2
2
  module Shell
3
3
  class Basic
4
+ DEFAULT_TERMINAL_WIDTH = 80
5
+
4
6
  attr_accessor :base
5
7
  attr_reader :padding
6
8
 
@@ -45,6 +47,10 @@ class Thor
45
47
 
46
48
  # Asks something to the user and receives a response.
47
49
  #
50
+ # If a default value is specified it will be presented to the user
51
+ # and allows them to select that value with an empty response. This
52
+ # option is ignored when limited answers are supplied.
53
+ #
48
54
  # If asked to limit the correct responses, you can pass in an
49
55
  # array of acceptable answers. If one of those is not supplied,
50
56
  # they will be shown a message stating that one of those answers
@@ -61,6 +67,8 @@ class Thor
61
67
  # ==== Example
62
68
  # ask("What is your name?")
63
69
  #
70
+ # ask("What is the planet furthest from the sun?", :default => "Pluto")
71
+ #
64
72
  # ask("What is your favorite Neopolitan flavor?", :limited_to => ["strawberry", "chocolate", "vanilla"])
65
73
  #
66
74
  # ask("What is your password?", :echo => false)
@@ -86,6 +94,8 @@ class Thor
86
94
  # say("I know you knew that.")
87
95
  #
88
96
  def say(message = "", color = nil, force_new_line = (message.to_s !~ /( |\t)\Z/))
97
+ return if quiet?
98
+
89
99
  buffer = prepare_message(message, *color)
90
100
  buffer << "\n" if force_new_line && !message.to_s.end_with?("\n")
91
101
 
@@ -93,6 +103,23 @@ class Thor
93
103
  stdout.flush
94
104
  end
95
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
+
96
123
  # Say a status with the given color and appends the message. Since this
97
124
  # method is used frequently by actions, it allows nil or false to be given
98
125
  # in log_status, avoiding the message from being shown. If a Symbol is
@@ -101,13 +128,14 @@ class Thor
101
128
  def say_status(status, message, log_status = true)
102
129
  return if quiet? || log_status == false
103
130
  spaces = " " * (padding + 1)
104
- color = log_status.is_a?(Symbol) ? log_status : :green
105
-
106
131
  status = status.to_s.rjust(12)
132
+ margin = " " * status.length + spaces
133
+
134
+ color = log_status.is_a?(Symbol) ? log_status : :green
107
135
  status = set_color status, color, true if color
108
136
 
109
- buffer = "#{status}#{spaces}#{message}"
110
- buffer = "#{buffer}\n" unless buffer.end_with?("\n")
137
+ message = message.to_s.chomp.gsub(/(?<!\A)^/, margin)
138
+ buffer = "#{status}#{spaces}#{message}\n"
111
139
 
112
140
  stdout.print(buffer)
113
141
  stdout.flush
@@ -222,8 +250,21 @@ class Thor
222
250
  paras = message.split("\n\n")
223
251
 
224
252
  paras.map! do |unwrapped|
225
- unwrapped.strip.tr("\n", " ").squeeze(" ").gsub(/.{1,#{width}}(?:\s|\Z)/) { ($& + 5.chr).gsub(/\n\005/, "\n").gsub(/\005/, "\n") }
226
- end
253
+ words = unwrapped.split(" ")
254
+ counter = words.first.length
255
+ words.inject do |memo, word|
256
+ word = word.gsub(/\n\005/, "\n").gsub(/\005/, "\n")
257
+ counter = 0 if word.include? "\n"
258
+ if (counter + word.length + 1) < width
259
+ memo = "#{memo} #{word}"
260
+ counter += (word.length + 1)
261
+ else
262
+ memo = "#{memo}\n#{word}"
263
+ counter = word.length
264
+ end
265
+ memo
266
+ end
267
+ end.compact!
227
268
 
228
269
  paras.each do |para|
229
270
  para.split("\n").each do |line|
@@ -239,11 +280,11 @@ class Thor
239
280
  #
240
281
  # ==== Parameters
241
282
  # destination<String>:: the destination file to solve conflicts
242
- # block<Proc>:: an optional block that returns the value to be used in diff
283
+ # block<Proc>:: an optional block that returns the value to be used in diff and merge
243
284
  #
244
285
  def file_collision(destination)
245
286
  return true if @always_force
246
- options = block_given? ? "[Ynaqdh]" : "[Ynaqh]"
287
+ options = block_given? ? "[Ynaqdhm]" : "[Ynaqh]"
247
288
 
248
289
  loop do
249
290
  answer = ask(
@@ -267,6 +308,13 @@ class Thor
267
308
  when is?(:diff)
268
309
  show_diff(destination, yield) if block_given?
269
310
  say "Retrying..."
311
+ when is?(:merge)
312
+ if block_given? && !merge_tool.empty?
313
+ merge(destination, yield)
314
+ return nil
315
+ end
316
+
317
+ say "Please specify merge tool to `THOR_MERGE` env."
270
318
  else
271
319
  say file_collision_help
272
320
  end
@@ -279,11 +327,11 @@ class Thor
279
327
  result = if ENV["THOR_COLUMNS"]
280
328
  ENV["THOR_COLUMNS"].to_i
281
329
  else
282
- unix? ? dynamic_width : 80
330
+ unix? ? dynamic_width : DEFAULT_TERMINAL_WIDTH
283
331
  end
284
- result < 10 ? 80 : result
332
+ result < 10 ? DEFAULT_TERMINAL_WIDTH : result
285
333
  rescue
286
- 80
334
+ DEFAULT_TERMINAL_WIDTH
287
335
  end
288
336
 
289
337
  # Called if something goes wrong during the execution. This is used by Thor
@@ -344,6 +392,7 @@ class Thor
344
392
  q - quit, abort
345
393
  d - diff, show the differences between the old and the new
346
394
  h - help, show this help
395
+ m - merge, run merge tool
347
396
  HELP
348
397
  end
349
398
 
@@ -423,15 +472,41 @@ class Thor
423
472
 
424
473
  def ask_filtered(statement, color, options)
425
474
  answer_set = options[:limited_to]
475
+ case_insensitive = options.fetch(:case_insensitive, false)
426
476
  correct_answer = nil
427
477
  until correct_answer
428
478
  answers = answer_set.join(", ")
429
479
  answer = ask_simply("#{statement} [#{answers}]", color, options)
430
- correct_answer = answer_set.include?(answer) ? answer : nil
480
+ correct_answer = answer_match(answer_set, answer, case_insensitive)
431
481
  say("Your response must be one of: [#{answers}]. Please try again.") unless correct_answer
432
482
  end
433
483
  correct_answer
434
484
  end
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
+
494
+ def merge(destination, content) #:nodoc:
495
+ require "tempfile"
496
+ Tempfile.open([File.basename(destination), File.extname(destination)], File.dirname(destination)) do |temp|
497
+ temp.write content
498
+ temp.rewind
499
+ system %(#{merge_tool} "#{temp.path}" "#{destination}")
500
+ end
501
+ end
502
+
503
+ def merge_tool #:nodoc:
504
+ @merge_tool ||= ENV["THOR_MERGE"] || git_merge_tool
505
+ end
506
+
507
+ def git_merge_tool #:nodoc:
508
+ `git config merge.tool`.rstrip rescue ""
509
+ end
435
510
  end
436
511
  end
437
512
  end
@@ -1,4 +1,4 @@
1
- require "thor/shell/basic"
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
- stdout.tty?
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
@@ -1,4 +1,4 @@
1
- require "thor/shell/basic"
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, "thor/shell/basic"
28
- autoload :Color, "thor/shell/color"
29
- autoload :HTML, "thor/shell/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
  #
@@ -55,7 +55,7 @@ class Thor
55
55
 
56
56
  # Common methods that are delegated to the shell.
57
57
  SHELL_DELEGATED_METHODS.each do |method|
58
- module_eval <<-METHOD, __FILE__, __LINE__
58
+ module_eval <<-METHOD, __FILE__, __LINE__ + 1
59
59
  def #{method}(*args,&block)
60
60
  shell.#{method}(*args,&block)
61
61
  end
data/lib/thor/util.rb CHANGED
@@ -27,7 +27,7 @@ class Thor
27
27
  end
28
28
 
29
29
  # Receives a constant and converts it to a Thor namespace. Since Thor
30
- # commands can be added to a sandbox, this method is also responsable for
30
+ # commands can be added to a sandbox, this method is also responsible for
31
31
  # removing the sandbox namespace.
32
32
  #
33
33
  # This method should not be used in general because it's used to deal with
@@ -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/*.thor"]
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>') # => "&lt;div&gt;"
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
@@ -1,3 +1,3 @@
1
1
  class Thor
2
- VERSION = "0.20.0"
2
+ VERSION = "1.2.1"
3
3
  end
data/lib/thor.rb CHANGED
@@ -1,7 +1,7 @@
1
- require "set"
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.merge(command_names)
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.merge(command_names)
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 ||= Set.new
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 ||= Set.new([:help])
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
- "#{basename} #{command.formatted_usage(self, $thor_runner, subcommand)}"
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:
data/thor.gemspec CHANGED
@@ -4,7 +4,7 @@ $LOAD_PATH.unshift lib unless $LOAD_PATH.include?(lib)
4
4
  require "thor/version"
5
5
 
6
6
  Gem::Specification.new do |spec|
7
- spec.add_development_dependency "bundler", "~> 1.0"
7
+ spec.add_development_dependency "bundler", ">= 1.0", "< 3"
8
8
  spec.authors = ["Yehuda Katz", "José Valim"]
9
9
  spec.description = "Thor is a toolkit for building powerful command-line interfaces."
10
10
  spec.email = "ruby-thor@googlegroups.com"
@@ -13,8 +13,16 @@ Gem::Specification.new do |spec|
13
13
  spec.homepage = "http://whatisthor.com/"
14
14
  spec.licenses = %w(MIT)
15
15
  spec.name = "thor"
16
+ spec.metadata = {
17
+ "bug_tracker_uri" => "https://github.com/rails/thor/issues",
18
+ "changelog_uri" => "https://github.com/rails/thor/releases/tag/v#{Thor::VERSION}",
19
+ "documentation_uri" => "http://whatisthor.com/",
20
+ "source_code_uri" => "https://github.com/rails/thor/tree/v#{Thor::VERSION}",
21
+ "wiki_uri" => "https://github.com/rails/thor/wiki",
22
+ "rubygems_mfa_required" => "true",
23
+ }
16
24
  spec.require_paths = %w(lib)
17
- spec.required_ruby_version = ">= 1.8.7"
25
+ spec.required_ruby_version = ">= 2.0.0"
18
26
  spec.required_rubygems_version = ">= 1.3.5"
19
27
  spec.summary = spec.description
20
28
  spec.version = Thor::VERSION
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: thor
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.20.0
4
+ version: 1.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yehuda Katz
@@ -9,22 +9,28 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2017-08-16 00:00:00.000000000 Z
12
+ date: 2022-01-04 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
16
16
  requirement: !ruby/object:Gem::Requirement
17
17
  requirements:
18
- - - "~>"
18
+ - - ">="
19
19
  - !ruby/object:Gem::Version
20
20
  version: '1.0'
21
+ - - "<"
22
+ - !ruby/object:Gem::Version
23
+ version: '3'
21
24
  type: :development
22
25
  prerelease: false
23
26
  version_requirements: !ruby/object:Gem::Requirement
24
27
  requirements:
25
- - - "~>"
28
+ - - ">="
26
29
  - !ruby/object:Gem::Version
27
30
  version: '1.0'
31
+ - - "<"
32
+ - !ruby/object:Gem::Version
33
+ version: '3'
28
34
  description: Thor is a toolkit for building powerful command-line interfaces.
29
35
  email: ruby-thor@googlegroups.com
30
36
  executables:
@@ -33,7 +39,6 @@ extensions: []
33
39
  extra_rdoc_files: []
34
40
  files:
35
41
  - ".document"
36
- - CHANGELOG.md
37
42
  - CONTRIBUTING.md
38
43
  - LICENSE.md
39
44
  - README.md
@@ -49,14 +54,13 @@ files:
49
54
  - lib/thor/base.rb
50
55
  - lib/thor/command.rb
51
56
  - lib/thor/core_ext/hash_with_indifferent_access.rb
52
- - lib/thor/core_ext/io_binary_read.rb
53
- - lib/thor/core_ext/ordered_hash.rb
54
57
  - lib/thor/error.rb
55
58
  - lib/thor/group.rb
56
59
  - lib/thor/invocation.rb
57
60
  - lib/thor/line_editor.rb
58
61
  - lib/thor/line_editor/basic.rb
59
62
  - lib/thor/line_editor/readline.rb
63
+ - lib/thor/nested_context.rb
60
64
  - lib/thor/parser.rb
61
65
  - lib/thor/parser/argument.rb
62
66
  - lib/thor/parser/arguments.rb
@@ -74,7 +78,13 @@ files:
74
78
  homepage: http://whatisthor.com/
75
79
  licenses:
76
80
  - MIT
77
- metadata: {}
81
+ metadata:
82
+ bug_tracker_uri: https://github.com/rails/thor/issues
83
+ changelog_uri: https://github.com/rails/thor/releases/tag/v1.2.1
84
+ documentation_uri: http://whatisthor.com/
85
+ source_code_uri: https://github.com/rails/thor/tree/v1.2.1
86
+ wiki_uri: https://github.com/rails/thor/wiki
87
+ rubygems_mfa_required: 'true'
78
88
  post_install_message:
79
89
  rdoc_options: []
80
90
  require_paths:
@@ -83,15 +93,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
83
93
  requirements:
84
94
  - - ">="
85
95
  - !ruby/object:Gem::Version
86
- version: 1.8.7
96
+ version: 2.0.0
87
97
  required_rubygems_version: !ruby/object:Gem::Requirement
88
98
  requirements:
89
99
  - - ">="
90
100
  - !ruby/object:Gem::Version
91
101
  version: 1.3.5
92
102
  requirements: []
93
- rubyforge_project:
94
- rubygems_version: 2.6.12
103
+ rubygems_version: 3.2.32
95
104
  signing_key:
96
105
  specification_version: 4
97
106
  summary: Thor is a toolkit for building powerful command-line interfaces.