thor 1.2.2 → 1.4.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.
@@ -0,0 +1,42 @@
1
+ class Thor
2
+ module Shell
3
+ module Terminal
4
+ DEFAULT_TERMINAL_WIDTH = 80
5
+
6
+ class << self
7
+ # This code was copied from Rake, available under MIT-LICENSE
8
+ # Copyright (c) 2003, 2004 Jim Weirich
9
+ def terminal_width
10
+ result = if ENV["THOR_COLUMNS"]
11
+ ENV["THOR_COLUMNS"].to_i
12
+ else
13
+ unix? ? dynamic_width : DEFAULT_TERMINAL_WIDTH
14
+ end
15
+ result < 10 ? DEFAULT_TERMINAL_WIDTH : result
16
+ rescue
17
+ DEFAULT_TERMINAL_WIDTH
18
+ end
19
+
20
+ def unix?
21
+ RUBY_PLATFORM =~ /(aix|darwin|linux|(net|free|open)bsd|cygwin|solaris)/i
22
+ end
23
+
24
+ private
25
+
26
+ # Calculate the dynamic width of the terminal
27
+ def dynamic_width
28
+ @dynamic_width ||= (dynamic_width_stty.nonzero? || dynamic_width_tput)
29
+ end
30
+
31
+ def dynamic_width_stty
32
+ `stty size 2>/dev/null`.split[1].to_i
33
+ end
34
+
35
+ def dynamic_width_tput
36
+ `tput cols 2>/dev/null`.to_i
37
+ end
38
+
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,38 @@
1
+ require_relative "column_printer"
2
+ require_relative "terminal"
3
+
4
+ class Thor
5
+ module Shell
6
+ class WrappedPrinter < ColumnPrinter
7
+ def print(message)
8
+ width = Terminal.terminal_width - @indent
9
+ paras = message.split("\n\n")
10
+
11
+ paras.map! do |unwrapped|
12
+ words = unwrapped.split(" ")
13
+ counter = words.first.length
14
+ words.inject do |memo, word|
15
+ word = word.gsub(/\n\005/, "\n").gsub(/\005/, "\n")
16
+ counter = 0 if word.include? "\n"
17
+ if (counter + word.length + 1) < width
18
+ memo = "#{memo} #{word}"
19
+ counter += (word.length + 1)
20
+ else
21
+ memo = "#{memo}\n#{word}"
22
+ counter = word.length
23
+ end
24
+ memo
25
+ end
26
+ end.compact!
27
+
28
+ paras.each do |para|
29
+ para.split("\n").each do |line|
30
+ stdout.puts line.insert(0, " " * @indent)
31
+ end
32
+ stdout.puts unless para == paras.last
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+
data/lib/thor/shell.rb CHANGED
@@ -75,7 +75,7 @@ class Thor
75
75
  # Allow shell to be shared between invocations.
76
76
  #
77
77
  def _shared_configuration #:nodoc:
78
- super.merge!(:shell => shell)
78
+ super.merge!(shell: shell)
79
79
  end
80
80
  end
81
81
  end
data/lib/thor/util.rb CHANGED
@@ -130,9 +130,10 @@ class Thor
130
130
  #
131
131
  def find_class_and_command_by_namespace(namespace, fallback = true)
132
132
  if namespace.include?(":") # look for a namespaced command
133
- pieces = namespace.split(":")
134
- command = pieces.pop
135
- klass = Thor::Util.find_by_namespace(pieces.join(":"))
133
+ *pieces, command = namespace.split(":")
134
+ namespace = pieces.join(":")
135
+ namespace = "default" if namespace.empty?
136
+ klass = Thor::Base.subclasses.detect { |thor| thor.namespace == namespace && thor.command_exists?(command) }
136
137
  end
137
138
  unless klass # look for a Thor::Group with the right name
138
139
  klass = Thor::Util.find_by_namespace(namespace)
data/lib/thor/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  class Thor
2
- VERSION = "1.2.2"
2
+ VERSION = "1.4.0"
3
3
  end
data/lib/thor.rb CHANGED
@@ -65,8 +65,15 @@ class Thor
65
65
 
66
66
  # Defines the long description of the next command.
67
67
  #
68
+ # Long description is by default indented, line-wrapped and repeated whitespace merged.
69
+ # In order to print long description verbatim, with indentation and spacing exactly
70
+ # as found in the code, use the +wrap+ option
71
+ #
72
+ # long_desc 'your very long description', wrap: false
73
+ #
68
74
  # ==== Parameters
69
75
  # long description<String>
76
+ # options<Hash>
70
77
  #
71
78
  def long_desc(long_description, options = {})
72
79
  if options[:for]
@@ -74,6 +81,7 @@ class Thor
74
81
  command.long_description = long_description if long_description
75
82
  else
76
83
  @long_desc = long_description
84
+ @long_desc_wrap = options[:wrap] != false
77
85
  end
78
86
  end
79
87
 
@@ -133,7 +141,7 @@ class Thor
133
141
  # # magic
134
142
  # end
135
143
  #
136
- # method_option :foo => :bar, :for => :previous_command
144
+ # method_option :foo, :for => :previous_command
137
145
  #
138
146
  # def next_command
139
147
  # # magic
@@ -153,6 +161,9 @@ class Thor
153
161
  # :hide - If you want to hide this option from the help.
154
162
  #
155
163
  def method_option(name, options = {})
164
+ unless [ Symbol, String ].any? { |klass| name.is_a?(klass) }
165
+ raise ArgumentError, "Expected a Symbol or String, got #{name.inspect}"
166
+ end
156
167
  scope = if options[:for]
157
168
  find_and_refresh_command(options[:for]).options
158
169
  else
@@ -163,6 +174,81 @@ class Thor
163
174
  end
164
175
  alias_method :option, :method_option
165
176
 
177
+ # Adds and declares option group for exclusive options in the
178
+ # block and arguments. You can declare options as the outside of the block.
179
+ #
180
+ # If :for is given as option, it allows you to change the options from
181
+ # a previous defined command.
182
+ #
183
+ # ==== Parameters
184
+ # Array[Thor::Option.name]
185
+ # options<Hash>:: :for is applied for previous defined command.
186
+ #
187
+ # ==== Examples
188
+ #
189
+ # exclusive do
190
+ # option :one
191
+ # option :two
192
+ # end
193
+ #
194
+ # Or
195
+ #
196
+ # option :one
197
+ # option :two
198
+ # exclusive :one, :two
199
+ #
200
+ # If you give "--one" and "--two" at the same time ExclusiveArgumentsError
201
+ # will be raised.
202
+ #
203
+ def method_exclusive(*args, &block)
204
+ register_options_relation_for(:method_options,
205
+ :method_exclusive_option_names, *args, &block)
206
+ end
207
+ alias_method :exclusive, :method_exclusive
208
+
209
+ # Adds and declares option group for required at least one of options in the
210
+ # block of arguments. You can declare options as the outside of the block.
211
+ #
212
+ # If :for is given as option, it allows you to change the options from
213
+ # a previous defined command.
214
+ #
215
+ # ==== Parameters
216
+ # Array[Thor::Option.name]
217
+ # options<Hash>:: :for is applied for previous defined command.
218
+ #
219
+ # ==== Examples
220
+ #
221
+ # at_least_one do
222
+ # option :one
223
+ # option :two
224
+ # end
225
+ #
226
+ # Or
227
+ #
228
+ # option :one
229
+ # option :two
230
+ # at_least_one :one, :two
231
+ #
232
+ # If you do not give "--one" and "--two" AtLeastOneRequiredArgumentError
233
+ # will be raised.
234
+ #
235
+ # You can use at_least_one and exclusive at the same time.
236
+ #
237
+ # exclusive do
238
+ # at_least_one do
239
+ # option :one
240
+ # option :two
241
+ # end
242
+ # end
243
+ #
244
+ # Then it is required either only one of "--one" or "--two".
245
+ #
246
+ def method_at_least_one(*args, &block)
247
+ register_options_relation_for(:method_options,
248
+ :method_at_least_one_option_names, *args, &block)
249
+ end
250
+ alias_method :at_least_one, :method_at_least_one
251
+
166
252
  # Prints help information for the given command.
167
253
  #
168
254
  # ==== Parameters
@@ -178,9 +264,16 @@ class Thor
178
264
  shell.say " #{banner(command).split("\n").join("\n ")}"
179
265
  shell.say
180
266
  class_options_help(shell, nil => command.options.values)
267
+ print_exclusive_options(shell, command)
268
+ print_at_least_one_required_options(shell, command)
269
+
181
270
  if command.long_description
182
271
  shell.say "Description:"
183
- shell.print_wrapped(command.long_description, :indent => 2)
272
+ if command.wrap_long_description
273
+ shell.print_wrapped(command.long_description, indent: 2)
274
+ else
275
+ shell.say command.long_description
276
+ end
184
277
  else
185
278
  shell.say command.description
186
279
  end
@@ -197,7 +290,7 @@ class Thor
197
290
  Thor::Util.thor_classes_in(self).each do |klass|
198
291
  list += klass.printable_commands(false)
199
292
  end
200
- list.sort! { |a, b| a[0] <=> b[0] }
293
+ sort_commands!(list)
201
294
 
202
295
  if defined?(@package_name) && @package_name
203
296
  shell.say "#{@package_name} commands:"
@@ -205,9 +298,11 @@ class Thor
205
298
  shell.say "Commands:"
206
299
  end
207
300
 
208
- shell.print_table(list, :indent => 2, :truncate => true)
301
+ shell.print_table(list, indent: 2, truncate: true)
209
302
  shell.say
210
303
  class_options_help(shell)
304
+ print_exclusive_options(shell)
305
+ print_at_least_one_required_options(shell)
211
306
  end
212
307
 
213
308
  # Returns commands ready to be printed.
@@ -238,7 +333,7 @@ class Thor
238
333
 
239
334
  define_method(subcommand) do |*args|
240
335
  args, opts = Thor::Arguments.split(args)
241
- invoke_args = [args, opts, {:invoked_via_subcommand => true, :class_options => options}]
336
+ invoke_args = [args, opts, {invoked_via_subcommand: true, class_options: options}]
242
337
  invoke_args.unshift "help" if opts.delete("--help") || opts.delete("-h")
243
338
  invoke subcommand_class, *invoke_args
244
339
  end
@@ -344,8 +439,37 @@ class Thor
344
439
  command && disable_required_check.include?(command.name.to_sym)
345
440
  end
346
441
 
442
+ # Checks if a specified command exists.
443
+ #
444
+ # ==== Parameters
445
+ # command_name<String>:: The name of the command to check for existence.
446
+ #
447
+ # ==== Returns
448
+ # Boolean:: +true+ if the command exists, +false+ otherwise.
449
+ def command_exists?(command_name) #:nodoc:
450
+ commands.keys.include?(normalize_command_name(command_name))
451
+ end
452
+
347
453
  protected
348
454
 
455
+ # Returns this class exclusive options array set.
456
+ #
457
+ # ==== Returns
458
+ # Array[Array[Thor::Option.name]]
459
+ #
460
+ def method_exclusive_option_names #:nodoc:
461
+ @method_exclusive_option_names ||= []
462
+ end
463
+
464
+ # Returns this class at least one of required options array set.
465
+ #
466
+ # ==== Returns
467
+ # Array[Array[Thor::Option.name]]
468
+ #
469
+ def method_at_least_one_option_names #:nodoc:
470
+ @method_at_least_one_option_names ||= []
471
+ end
472
+
349
473
  def stop_on_unknown_option #:nodoc:
350
474
  @stop_on_unknown_option ||= []
351
475
  end
@@ -355,6 +479,28 @@ class Thor
355
479
  @disable_required_check ||= [:help]
356
480
  end
357
481
 
482
+ def print_exclusive_options(shell, command = nil) # :nodoc:
483
+ opts = []
484
+ opts = command.method_exclusive_option_names unless command.nil?
485
+ opts += class_exclusive_option_names
486
+ unless opts.empty?
487
+ shell.say "Exclusive Options:"
488
+ shell.print_table(opts.map{ |ex| ex.map{ |e| "--#{e}"}}, indent: 2 )
489
+ shell.say
490
+ end
491
+ end
492
+
493
+ def print_at_least_one_required_options(shell, command = nil) # :nodoc:
494
+ opts = []
495
+ opts = command.method_at_least_one_option_names unless command.nil?
496
+ opts += class_at_least_one_option_names
497
+ unless opts.empty?
498
+ shell.say "Required At Least One:"
499
+ shell.print_table(opts.map{ |ex| ex.map{ |e| "--#{e}"}}, indent: 2 )
500
+ shell.say
501
+ end
502
+ end
503
+
358
504
  # The method responsible for dispatching given the args.
359
505
  def dispatch(meth, given_args, given_opts, config) #:nodoc:
360
506
  meth ||= retrieve_command_name(given_args)
@@ -415,12 +561,16 @@ class Thor
415
561
  @usage ||= nil
416
562
  @desc ||= nil
417
563
  @long_desc ||= nil
564
+ @long_desc_wrap ||= nil
418
565
  @hide ||= nil
419
566
 
420
567
  if @usage && @desc
421
568
  base_class = @hide ? Thor::HiddenCommand : Thor::Command
422
- commands[meth] = base_class.new(meth, @desc, @long_desc, @usage, method_options)
423
- @usage, @desc, @long_desc, @method_options, @hide = nil
569
+ relations = {exclusive_option_names: method_exclusive_option_names,
570
+ at_least_one_option_names: method_at_least_one_option_names}
571
+ commands[meth] = base_class.new(meth, @desc, @long_desc, @long_desc_wrap, @usage, method_options, relations)
572
+ @usage, @desc, @long_desc, @long_desc_wrap, @method_options, @hide = nil
573
+ @method_exclusive_option_names, @method_at_least_one_option_names = nil
424
574
  true
425
575
  elsif all_commands[meth] || meth == "method_missing"
426
576
  true
@@ -495,6 +645,14 @@ class Thor
495
645
  "
496
646
  end
497
647
  alias_method :subtask_help, :subcommand_help
648
+
649
+ # Sort the commands, lexicographically by default.
650
+ #
651
+ # Can be overridden in the subclass to change the display order of the
652
+ # commands.
653
+ def sort_commands!(list)
654
+ list.sort! { |a, b| a[0] <=> b[0] }
655
+ end
498
656
  end
499
657
 
500
658
  include Thor::Base
data/thor.gemspec CHANGED
@@ -4,15 +4,15 @@ $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", "< 3"
7
+ spec.name = "thor"
8
+ spec.version = Thor::VERSION
9
+ spec.licenses = %w(MIT)
8
10
  spec.authors = ["Yehuda Katz", "José Valim"]
9
- spec.description = "Thor is a toolkit for building powerful command-line interfaces."
10
11
  spec.email = "ruby-thor@googlegroups.com"
11
- spec.executables = %w(thor)
12
- spec.files = %w(.document thor.gemspec) + Dir["*.md", "bin/*", "lib/**/*.rb"]
13
12
  spec.homepage = "http://whatisthor.com/"
14
- spec.licenses = %w(MIT)
15
- spec.name = "thor"
13
+ spec.description = "Thor is a toolkit for building powerful command-line interfaces."
14
+ spec.summary = spec.description
15
+
16
16
  spec.metadata = {
17
17
  "bug_tracker_uri" => "https://github.com/rails/thor/issues",
18
18
  "changelog_uri" => "https://github.com/rails/thor/releases/tag/v#{Thor::VERSION}",
@@ -21,9 +21,13 @@ Gem::Specification.new do |spec|
21
21
  "wiki_uri" => "https://github.com/rails/thor/wiki",
22
22
  "rubygems_mfa_required" => "true",
23
23
  }
24
- spec.require_paths = %w(lib)
25
- spec.required_ruby_version = ">= 2.0.0"
24
+
25
+ spec.required_ruby_version = ">= 2.6.0"
26
26
  spec.required_rubygems_version = ">= 1.3.5"
27
- spec.summary = spec.description
28
- spec.version = Thor::VERSION
27
+
28
+ spec.files = %w(.document thor.gemspec) + Dir["*.md", "bin/*", "lib/**/*.rb"]
29
+ spec.executables = %w(thor)
30
+ spec.require_paths = %w(lib)
31
+
32
+ spec.add_development_dependency "bundler", ">= 1.0", "< 3"
29
33
  end
metadata CHANGED
@@ -1,15 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: thor
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.2
4
+ version: 1.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yehuda Katz
8
8
  - José Valim
9
- autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2023-05-11 00:00:00.000000000 Z
11
+ date: 1980-01-02 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: bundler
@@ -71,7 +70,12 @@ files:
71
70
  - lib/thor/shell.rb
72
71
  - lib/thor/shell/basic.rb
73
72
  - lib/thor/shell/color.rb
73
+ - lib/thor/shell/column_printer.rb
74
74
  - lib/thor/shell/html.rb
75
+ - lib/thor/shell/lcs_diff.rb
76
+ - lib/thor/shell/table_printer.rb
77
+ - lib/thor/shell/terminal.rb
78
+ - lib/thor/shell/wrapped_printer.rb
75
79
  - lib/thor/util.rb
76
80
  - lib/thor/version.rb
77
81
  - thor.gemspec
@@ -80,12 +84,11 @@ licenses:
80
84
  - MIT
81
85
  metadata:
82
86
  bug_tracker_uri: https://github.com/rails/thor/issues
83
- changelog_uri: https://github.com/rails/thor/releases/tag/v1.2.2
87
+ changelog_uri: https://github.com/rails/thor/releases/tag/v1.4.0
84
88
  documentation_uri: http://whatisthor.com/
85
- source_code_uri: https://github.com/rails/thor/tree/v1.2.2
89
+ source_code_uri: https://github.com/rails/thor/tree/v1.4.0
86
90
  wiki_uri: https://github.com/rails/thor/wiki
87
91
  rubygems_mfa_required: 'true'
88
- post_install_message:
89
92
  rdoc_options: []
90
93
  require_paths:
91
94
  - lib
@@ -93,15 +96,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
93
96
  requirements:
94
97
  - - ">="
95
98
  - !ruby/object:Gem::Version
96
- version: 2.0.0
99
+ version: 2.6.0
97
100
  required_rubygems_version: !ruby/object:Gem::Requirement
98
101
  requirements:
99
102
  - - ">="
100
103
  - !ruby/object:Gem::Version
101
104
  version: 1.3.5
102
105
  requirements: []
103
- rubygems_version: 3.4.10
104
- signing_key:
106
+ rubygems_version: 3.6.7
105
107
  specification_version: 4
106
108
  summary: Thor is a toolkit for building powerful command-line interfaces.
107
109
  test_files: []