Class: Thor

Inherits:
Object
  • Object
show all
Includes:
ActiveSupport::Callbacks, Base
Defined in:
lib/thor-plus.rb,
lib/thor-plus/base.rb,
lib/thor-plus/util.rb,
lib/thor-plus/error.rb,
lib/thor-plus/shell.rb,
lib/thor-plus/actions.rb,
lib/thor-plus/command.rb,
lib/thor-plus/version.rb,
lib/thor-plus/invocation.rb,
lib/thor-plus/shell/html.rb,
lib/thor-plus/line_editor.rb,
lib/thor-plus/rake_compat.rb,
lib/thor-plus/shell/basic.rb,
lib/thor-plus/shell/color.rb,
lib/thor-plus/parser/option.rb,
lib/thor-plus/parser/options.rb,
lib/thor-plus/parser/argument.rb,
lib/thor-plus/parser/arguments.rb,
lib/thor-plus/actions/directory.rb,
lib/thor-plus/line_editor/basic.rb,
lib/thor-plus/actions/create_file.rb,
lib/thor-plus/actions/create_link.rb,
lib/thor-plus/line_editor/readline.rb,
lib/thor-plus/core_ext/ordered_hash.rb,
lib/thor-plus/actions/empty_directory.rb,
lib/thor-plus/actions/inject_into_file.rb,
lib/thor-plus/actions/file_manipulation.rb,
lib/thor-plus/core_ext/hash_with_indifferent_access.rb

Overview

rubocop:disable ClassLength

Direct Known Subclasses

Runner

Defined Under Namespace

Modules: Actions, Base, CoreExt, Invocation, LineEditor, RakeCompat, Sandbox, Shell, Util Classes: AmbiguousCommandError, Argument, Arguments, Command, DynamicCommand, Error, Group, HiddenCommand, InvocationError, MalformattedArgumentError, Option, Options, RequiredArgumentMissingError, Runner, UndefinedCommandError, UnknownArgumentError

Constant Summary collapse

HELP_MAPPINGS =

Shortcuts for help.

%w[-h -? --help -D]
THOR_RESERVED_WORDS =

Thor methods that should not be overwritten by the user.

%w[invoke shell options behavior root destination_root relative_root
action add_file create_file in_root inside run run_ruby_script]
TEMPLATE_EXTNAME =
".tt"
UndefinedTaskError =

rubocop:disable ConstantName

UndefinedCommandError
AmbiguousTaskError =

rubocop:disable ConstantName

AmbiguousCommandError
Task =

rubocop:disable ConstantName

Command
HiddenTask =

rubocop:disable ConstantName

HiddenCommand
DynamicTask =

rubocop:disable ConstantName

DynamicCommand
VERSION =
"1.0.0"

Instance Attribute Summary

Attributes included from Base

#args, #current_command, #options, #parent_options

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Base

#execute_command, included, #initialize, register_klass_file, subclass_files, subclasses

Class Method Details

.after_command(*arguments) ⇒ Object Also known as: after_task

Adds a callback method that should be executed after a task is executed.

Parameters

methods<*String|Symbol>

Callbacks to execute after command runs.



52
53
54
# File 'lib/thor-plus.rb', line 52

def after_command(*arguments)
  set_callback :invoke, :after, *arguments
end

.around_command(*arguments) ⇒ Object Also known as: around_task

Adds a callback method that should be executed around an executing task.

Parameters

methods<*String|Symbol>

Callbacks to execute after command runs.



61
62
63
# File 'lib/thor-plus.rb', line 61

def around_command(*arguments)
  set_callback :invoke, :around, *arguments
end

.before_command(*arguments) ⇒ Object Also known as: before_task

Adds a callback method that should be executed before a command is executed.

Parameters

methods<*String|Symbol>

Callbacks to execute before command runs.



43
44
45
# File 'lib/thor-plus.rb', line 43

def before_command(*arguments)
  set_callback :invoke, :before, *arguments
end

.check_unknown_options!(options = {}) ⇒ Object

Extend check unknown options to accept a hash of conditions.

Parameters

options<Hash>: A hash containing :only and/or :except keys



280
281
282
283
284
285
286
287
288
289
290
# File 'lib/thor-plus.rb', line 280

def check_unknown_options!(options = {})
  @check_unknown_options ||= {}
  options.each do |key, value|
    if value
      @check_unknown_options[key] = Array(value)
    else
      @check_unknown_options.delete(key)
    end
  end
  @check_unknown_options
end

.check_unknown_options?(config) ⇒ Boolean

Overwrite check_unknown_options? to take subcommands and options into account.

Returns:

  • (Boolean)


293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
# File 'lib/thor-plus.rb', line 293

def check_unknown_options?(config) #:nodoc:
  options = check_unknown_options
  return false unless options

  command = config[:current_command]
  return true unless command

  name = command.name

  if subcommands.include?(name)
    false
  elsif options[:except]
    !options[:except].include?(name.to_sym)
  elsif options[:only]
    options[:only].include?(name.to_sym)
  else
    true
  end
end

.command_help(shell, command_name, subcommand = false) ⇒ Object Also known as: task_help

Prints help information for the given command.

Parameters

shell<Thor::Shell> command_name<String>



205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
# File 'lib/thor-plus.rb', line 205

def command_help(shell, command_name, subcommand = false)
  meth = normalize_command_name(command_name)
  command = all_commands[meth]
  handle_no_command_error(meth) unless command

  shell.say "Usage:"
  shell.say "  #{banner(command, nil, subcommand)}"
  shell.say
  class_options_help(shell, nil => command.options.values)
  if command.long_description
    shell.say "Description:"
    shell.print_wrapped(command.long_description, :indent => 2)
  else
    shell.say command.description
  end
end

.default_command(meth = nil) ⇒ Object Also known as: default_task

Sets the default command when thor is executed without an explicit command to be called.

Parameters

meth<Symbol>

name of the default command



30
31
32
33
34
35
36
# File 'lib/thor-plus.rb', line 30

def default_command(meth = nil)
  if meth
    @default_command = meth == :none ? "help" : meth.to_s
  else
    @default_command ||= from_superclass(:default_command, "help")
  end
end

.desc(usage, description, options = {}) ⇒ Object

Defines the usage and the description of the next command.

Parameters

usage<String> description<String> options<String>



90
91
92
93
94
95
96
97
98
# File 'lib/thor-plus.rb', line 90

def desc(usage, description, options = {})
  if options[:for]
    command = find_and_refresh_command(options[:for])
    command.usage = usage             if usage
    command.description = description if description
  else
    @usage, @desc, @hide = usage, description, options[:hide] || false
  end
end

.disable_class_optionsObject



195
196
197
# File 'lib/thor-plus.rb', line 195

def disable_class_options
  @disable_class_options = true
end

.help(shell, subcommand = false) ⇒ Object

Prints help information for this class.

Parameters

shell<Thor::Shell>



228
229
230
231
232
233
234
235
236
237
238
239
# File 'lib/thor-plus.rb', line 228

def help(shell, subcommand = false)
  list = printable_commands(true, subcommand)
  Thor::Util.thor_classes_in(self).each do |klass|
    list += klass.printable_commands(false)
  end
  list.sort! { |a, b| a[0] <=> b[0] }

  shell.say "#{package_name} commands:"
  shell.print_table(list, :indent => 2, :truncate => true)
  shell.say
  class_options_help(shell)
end

.long_desc(long_description, options = {}) ⇒ Object

Defines the long description of the next command.

Parameters

long description<String>



105
106
107
108
109
110
111
112
# File 'lib/thor-plus.rb', line 105

def long_desc(long_description, options = {})
  if options[:for]
    command = find_and_refresh_command(options[:for])
    command.long_description = long_description if long_description
  else
    @long_desc = long_description
  end
end

.map(mappings = nil) ⇒ Object

Maps an input to a command. If you define:

map "-T" => "list"

Running:

thor -T

Will invoke the list command.

Parameters

Hash[String|Array => Symbol]

Maps the string or the strings in the array to the given command.



127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/thor-plus.rb', line 127

def map(mappings = nil)
  @map ||= from_superclass(:map, {})

  if mappings
    mappings.each do |key, value|
      if key.respond_to?(:each)
        key.each { |subkey| @map[subkey] = value }
      else
        @map[key] = value
      end
    end
  end

  @map
end

.method_option(name, options = {}) ⇒ Object Also known as: option

Adds an option to the set of method options. If :for is given as option, it allows you to change the options from a previous defined command.

def previous_command
  # magic
end

method_option :foo => :bar, :for => :previous_command

def next_command
  # magic
end

Parameters

name<Symbol>

The name of the argument.

options<Hash>

Described below.

Options

:desc - Description for the argument. :required - If the argument is required or not. :default - Default value for this argument. It cannot be required and have default values. :aliases - Aliases for this option. :type - The type of the argument, can be :string, :hash, :array, :numeric or :boolean. :banner - String to show on usage notes. :hide - If you want to hide this option from the help.



184
185
186
187
188
189
190
191
192
# File 'lib/thor-plus.rb', line 184

def method_option(name, options = {})
  scope = if options[:for]
    find_and_refresh_command(options[:for]).options
  else
    method_options
  end

  build_option(name, options, scope)
end

.method_options(options = nil) ⇒ Object Also known as: options

Declares the options for the next command to be declared.

Parameters

Hash[Symbol => Object]

The hash key is the name of the option and the value

is the type of the option. Can be :string, :array, :hash, :boolean, :numeric or :required (string). If you give a value, the type of the value is used.



150
151
152
153
154
# File 'lib/thor-plus.rb', line 150

def method_options(options = nil)
  @method_options ||= {}
  build_options(options, @method_options) if options
  @method_options
end

.package_name(name = nil, options = {}) ⇒ Object

Allows for custom “Command” package naming.

Parameters

name<String> options<Hash>



17
18
19
20
21
22
23
# File 'lib/thor-plus.rb', line 17

def package_name(name = nil, options = {})
  if name
    @package_name = name.nil? || name == "" ? nil : name
  else
    @package_name ||= basename
  end
end

.printable_commands(all = true, subcommand = false) ⇒ Object Also known as: printable_tasks

Returns commands ready to be printed.



242
243
244
245
246
247
248
249
250
# File 'lib/thor-plus.rb', line 242

def printable_commands(all = true, subcommand = false)
  (all ? all_commands : commands).map do |_, command|
    next if command.hidden?
    item = []
    item << banner(command, false, subcommand)
    item << (command.description ? "# #{command.description.gsub(/\s+/m, ' ')}" : "")
    item
  end.compact
end

.register(klass, subcommand_name, usage, description, options = {}) ⇒ Object

Registers another Thor subclass as a command.

Parameters

klass<Class>

Thor subclass to register

command<String>

Subcommand name to use

usage<String>

Short usage for the subcommand

description<String>

Description for the subcommand



73
74
75
76
77
78
79
80
81
# File 'lib/thor-plus.rb', line 73

def register(klass, subcommand_name, usage, description, options = {})
  if klass <= Thor::Group
    desc usage, description, options
    define_method(subcommand_name) { |*args| invoke(klass, args) }
  else
    desc usage, description, options
    subcommand subcommand_name, klass
  end
end

.stop_on_unknown_option!(*command_names) ⇒ Object

Stop parsing of options as soon as an unknown option or a regular argument is encountered. All remaining arguments are passed to the command. This is useful if you have a command that can receive arbitrary additional options, and where those additional options should not be handled by Thor.

Example

To better understand how this is useful, let’s consider a command that calls an external command. A user may want to pass arbitrary options and arguments to that command. The command itself also accepts some options, which should be handled by Thor.

class_option "verbose",  :type => :boolean
stop_on_unknown_option! :exec
check_unknown_options!  :except => :exec

desc "exec", "Run a shell command"
def exec(*args)
  puts "diagnostic output" if options[:verbose]
  Kernel.exec(*args)
end

Here exec can be called with --verbose to get diagnostic output, e.g.:

$ thor exec --verbose echo foo
diagnostic output
foo

But if --verbose is given after echo, it is passed to echo instead:

$ thor exec echo --verbose foo
--verbose foo

Parameters

Symbol …

A list of commands that should be affected.



350
351
352
# File 'lib/thor-plus.rb', line 350

def stop_on_unknown_option!(*command_names)
  stop_on_unknown_option.merge(command_names)
end

.stop_on_unknown_option?(command) ⇒ Boolean

:nodoc:

Returns:

  • (Boolean)


354
355
356
# File 'lib/thor-plus.rb', line 354

def stop_on_unknown_option?(command) #:nodoc:
  command && stop_on_unknown_option.include?(command.name.to_sym)
end

.subcommand(subcommand, subcommand_class) ⇒ Object Also known as: subtask



262
263
264
265
266
267
268
269
270
271
272
273
# File 'lib/thor-plus.rb', line 262

def subcommand(subcommand, subcommand_class)
  subcommands << subcommand.to_s
  subcommand_class.package_name(self.package_name)
  subcommand_class.subcommand_help subcommand
  subcommand_classes[subcommand.to_s] = subcommand_class

  define_method(subcommand) do |*args|
    args, opts = Thor::Arguments.split(args)
    args.unshift("help") if opts.include? "--help" or opts.include? "-h"
    invoke subcommand_class, args, opts, :invoked_via_subcommand => true, :class_options => options
  end
end

.subcommand_classesObject



258
259
260
# File 'lib/thor-plus.rb', line 258

def subcommand_classes
  @subcommand_classes ||= {}
end

.subcommandsObject Also known as: subtasks



253
254
255
# File 'lib/thor-plus.rb', line 253

def subcommands
  @subcommands ||= from_superclass(:subcommands, [])
end

Instance Method Details

#help(command = nil, subcommand = false) ⇒ Object



514
515
516
517
518
519
520
521
522
523
524
# File 'lib/thor-plus.rb', line 514

def help(command = nil, subcommand = false)
  if command
    if self.class.subcommands.include? command
      self.class.subcommand_classes[command].help(shell, true)
    else
      self.class.command_help(shell, command, subcommand)
    end
  else
    self.class.help(shell, subcommand)
  end
end