class Thor
def banner(command, namespace = nil, subcommand = false)
the namespace should be displayed as arguments.
the command that is going to be invoked and a boolean which indicates if
thor class by another ways which is not the Thor::Runner. It receives
The banner for this class. You can customize it if you are invoking the
def banner(command, namespace = nil, subcommand = false) command.formatted_usage(self, $thor_runner, subcommand).split("\n").map do |formatted_usage| "#{basename} #{formatted_usage}" end.join("\n") end
def baseclass #:nodoc:
def baseclass #:nodoc: Thor end
def check_unknown_options!(options = {})
=== Parameters
Extend check unknown options to accept a hash of conditions.
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
def check_unknown_options?(config) #:nodoc:
Overwrite check_unknown_options? to take subcommands and options into account.
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
def command_exists?(command_name) #:nodoc:
Boolean:: +true+ if the command exists, +false+ otherwise.
==== Returns
command_name
==== Parameters
Checks if a specified command exists.
def command_exists?(command_name) #:nodoc: commands.keys.include?(normalize_command_name(command_name)) end
def command_help(shell, command_name)
command_name
shell
==== Parameters
Prints help information for the given command.
def command_help(shell, command_name) meth = normalize_command_name(command_name) command = all_commands[meth] handle_no_command_error(meth) unless command shell.say "Usage:" shell.say " #{banner(command).split("\n").join("\n ")}" shell.say class_options_help(shell, nil => command.options.values) print_exclusive_options(shell, command) print_at_least_one_required_options(shell, command) if command.long_description shell.say "Description:" if command.wrap_long_description shell.print_wrapped(command.long_description, indent: 2) else shell.say command.long_description end else shell.say command.description end end
def create_command(meth) #:nodoc:
def create_command(meth) #:nodoc: @usage ||= nil @desc ||= nil @long_desc ||= nil @long_desc_wrap ||= nil @hide ||= nil if @usage && @desc base_class = @hide ? Thor::HiddenCommand : Thor::Command relations = {exclusive_option_names: method_exclusive_option_names, at_least_one_option_names: method_at_least_one_option_names} commands[meth] = base_class.new(meth, @desc, @long_desc, @long_desc_wrap, @usage, method_options, relations) @usage, @desc, @long_desc, @long_desc_wrap, @method_options, @hide = nil @method_exclusive_option_names, @method_at_least_one_option_names = nil true elsif all_commands[meth] || meth == "method_missing" true else puts "[WARNING] Attempted to create command #{meth.inspect} without usage or description. " \ "Call desc if you want this method to be available as command or declare it inside a " \ "no_commands{} block. Invoked from #{caller[1].inspect}." false end end
def default_command(meth = nil)
meth
==== Parameters
Sets the default command when thor is executed without an explicit command to be called.
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
def deprecation_warning(message) #:nodoc:
def deprecation_warning(message) #:nodoc: unless ENV["THOR_SILENCE_DEPRECATION"] warn "Deprecation warning: #{message}\n" + "You can silence deprecations warning by setting the environment variable THOR_SILENCE_DEPRECATION." end end
def desc(usage, description, options = {})
options
description
usage
==== Parameters
Defines the usage and the description of the next command.
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 = usage @desc = description @hide = options[:hide] || false end end
def disable_required_check #:nodoc:
help command has the required check disabled by default.
def disable_required_check #:nodoc: @disable_required_check ||= [:help] end
def disable_required_check!(*command_names)
==== Parameters
to work, like help.
This is useful if you have a command that does not need the required options
Disable the check for required options for the given commands.
def disable_required_check!(*command_names) @disable_required_check = disable_required_check | command_names end
def disable_required_check?(command) #:nodoc:
def disable_required_check?(command) #:nodoc: command && disable_required_check.include?(command.name.to_sym) end
def dispatch(meth, given_args, given_opts, config) #:nodoc:
The method responsible for dispatching given the args.
def dispatch(meth, given_args, given_opts, config) #:nodoc: meth ||= retrieve_command_name(given_args) command = all_commands[normalize_command_name(meth)] if !command && config[:invoked_via_subcommand] # We're a subcommand and our first argument didn't match any of our # commands. So we put it back and call our default command. given_args.unshift(meth) command = all_commands[normalize_command_name(default_command)] end if command args, opts = Thor::Options.split(given_args) if stop_on_unknown_option?(command) && !args.empty? # given_args starts with a non-option, so we treat everything as # ordinary arguments args.concat opts opts.clear end else args = given_args opts = nil command = dynamic_command_class.new(meth) end opts = given_opts || opts || [] config[:current_command] = command config[:command_options] = command.options instance = new(args, opts, config) yield instance if block_given? args = instance.args trailing = args[Range.new(arguments.size, -1)] instance.invoke_command(command, trailing || []) end
def dynamic_command_class #:nodoc:
def dynamic_command_class #:nodoc: Thor::DynamicCommand end
def find_command_possibilities(meth)
and determines whether it is an unambiguous substrings of a command or
this is the logic that takes the command name passed in by the user
def find_command_possibilities(meth) len = meth.to_s.length possibilities = all_commands.merge(map).keys.select { |n| meth == n[0, len] }.sort unique_possibilities = possibilities.map { |k| map[k] || k }.uniq if possibilities.include?(meth) [meth] elsif unique_possibilities.size == 1 unique_possibilities else possibilities end end
def help(shell, subcommand = false)
shell
==== Parameters
Prints help information for this class.
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 sort_commands!(list) if defined?(@package_name) && @package_name shell.say "#{@package_name} commands:" else shell.say "Commands:" end shell.print_table(list, indent: 2, truncate: true) shell.say class_options_help(shell) print_exclusive_options(shell) print_at_least_one_required_options(shell) end
def help(command = nil, subcommand = false)
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) end else self.class.help(shell, subcommand) end end
def initialize_added #:nodoc:
def initialize_added #:nodoc: class_options.merge!(method_options) @method_options = nil end
def long_desc(long_description, options = {})
options
long description
==== Parameters
long_desc 'your very long description', wrap: false
as found in the code, use the +wrap+ option
In order to print long description verbatim, with indentation and spacing exactly
Long description is by default indented, line-wrapped and repeated whitespace merged.
Defines the long description of the next command.
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 @long_desc_wrap = options[:wrap] != false end end
def map(mappings = nil, **kw)
Hash[String|Array => Symbol]:: Maps the string or the strings in the array to the given command.
==== Parameters
Will invoke the list command.
thor -T
Running:
map "-T" => "list"
Maps an input to a command. If you define:
def map(mappings = nil, **kw) @map ||= from_superclass(:map, {}) if mappings && !kw.empty? mappings = kw.merge!(mappings) else mappings ||= kw end 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
def method_at_least_one(*args, &block)
Then it is required either only one of "--one" or "--two".
end
end
option :two
option :one
at_least_one do
exclusive do
You can use at_least_one and exclusive at the same time.
will be raised.
If you do not give "--one" and "--two" AtLeastOneRequiredArgumentError
at_least_one :one, :two
option :two
option :one
Or
end
option :two
option :one
at_least_one do
==== Examples
options
Array[Thor::Option.name]
==== Parameters
a previous defined command.
If :for is given as option, it allows you to change the options from
block of arguments. You can declare options as the outside of the block.
Adds and declares option group for required at least one of options in the
def method_at_least_one(*args, &block) register_options_relation_for(:method_options, :method_at_least_one_option_names, *args, &block) end
def method_at_least_one_option_names #:nodoc:
Array[Array[Thor::Option.name]]
==== Returns
Returns this class at least one of required options array set.
def method_at_least_one_option_names #:nodoc: @method_at_least_one_option_names ||= [] end
def method_exclusive(*args, &block)
will be raised.
If you give "--one" and "--two" at the same time ExclusiveArgumentsError
exclusive :one, :two
option :two
option :one
Or
end
option :two
option :one
exclusive do
==== Examples
options
Array[Thor::Option.name]
==== Parameters
a previous defined command.
If :for is given as option, it allows you to change the options from
block and arguments. You can declare options as the outside of the block.
Adds and declares option group for exclusive options in the
def method_exclusive(*args, &block) register_options_relation_for(:method_options, :method_exclusive_option_names, *args, &block) end
def method_exclusive_option_names #:nodoc:
Array[Array[Thor::Option.name]]
==== Returns
Returns this class exclusive options array set.
def method_exclusive_option_names #:nodoc: @method_exclusive_option_names ||= [] end
def method_option(name, options = {})
:hide - If you want to hide this option from the help.
:banner - String to show on usage notes.
:type - The type of the argument, can be :string, :hash, :array, :numeric or :boolean.
:aliases - Aliases for this option.
:default - Default value for this argument. It cannot be required and have default values.
:required - If the argument is required or not.
:desc - Description for the argument.
==== Options
options
name
==== Parameters
end
# magic
def next_command
method_option :foo, :for => :previous_command
end
# magic
def previous_command
it allows you to change the options from a previous defined command.
Adds an option to the set of method options. If :for is given as option,
def method_option(name, options = {}) unless [ Symbol, String ].any? { |klass| name.is_a?(klass) } raise ArgumentError, "Expected a Symbol or String, got #{name.inspect}" end scope = if options[:for] find_and_refresh_command(options[:for]).options else method_options end build_option(name, options, scope) end
def method_options(options = nil)
or :required (string). If you give a value, the type of the value is used.
is the type of the option. Can be :string, :array, :hash, :boolean, :numeric
Hash[Symbol => Object]:: The hash key is the name of the option and the value
==== Parameters
Declares the options for the next command to be declared.
def method_options(options = nil) @method_options ||= {} build_options(options, @method_options) if options @method_options end
def normalize_command_name(meth) #:nodoc:
into +animal_prison+.
+normalize_command_name+ also converts names like +animal-prison+
a command or alias.
will determine if a shortened command is an unambiguous substring of
the commands hash. In addition to normalizing aliases, this logic
receives a (possibly nil) command name and returns a name that is in
def normalize_command_name(meth) #:nodoc: return default_command.to_s.tr("-", "_") unless meth possibilities = find_command_possibilities(meth) raise AmbiguousTaskError, "Ambiguous command #{meth} matches [#{possibilities.join(', ')}]" if possibilities.size > 1 if possibilities.empty? meth ||= default_command elsif map[meth] meth = map[meth] else meth = possibilities.first end meth.to_s.tr("-", "_") # treat foo-bar as foo_bar end
def package_name(name, _ = {})
options
name
=== Parameters
Allows for custom "Command" package naming.
def package_name(name, _ = {}) @package_name = name.nil? || name == "" ? nil : name end
def print_at_least_one_required_options(shell, command = nil) # :nodoc:
def print_at_least_one_required_options(shell, command = nil) # :nodoc: opts = [] opts = command.method_at_least_one_option_names unless command.nil? opts += class_at_least_one_option_names unless opts.empty? shell.say "Required At Least One:" shell.print_table(opts.map{ |ex| ex.map{ |e| "--#{e}"}}, indent: 2 ) shell.say end end
def print_exclusive_options(shell, command = nil) # :nodoc:
def print_exclusive_options(shell, command = nil) # :nodoc: opts = [] opts = command.method_exclusive_option_names unless command.nil? opts += class_exclusive_option_names unless opts.empty? shell.say "Exclusive Options:" shell.print_table(opts.map{ |ex| ex.map{ |e| "--#{e}"}}, indent: 2 ) shell.say end end
def printable_commands(all = true, subcommand = false)
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
def register(klass, subcommand_name, usage, description, options = {})
usage
command
klass
==== Parameters
Registers another Thor subclass as a command.
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
def retrieve_command_name(args) #:nodoc:
Retrieve the command name from given args.
def retrieve_command_name(args) #:nodoc: meth = args.first.to_s unless args.empty? args.shift if meth && (map[meth] || meth !~ /^\-/) end
def sort_commands!(list)
Can be overridden in the subclass to change the display order of the
Sort the commands, lexicographically by default.
def sort_commands!(list) list.sort! { |a, b| a[0] <=> b[0] } end
def stop_on_unknown_option #:nodoc:
def stop_on_unknown_option #:nodoc: @stop_on_unknown_option ||= [] end
def stop_on_unknown_option!(*command_names)
==== Parameters
--verbose foo
$ thor exec echo --verbose foo
But if +--verbose+ is given after +echo+, it is passed to +echo+ instead:
foo
diagnostic output
$ thor exec --verbose echo foo
e.g.:
Here +exec+ can be called with +--verbose+ to get diagnostic output,
end
Kernel.exec(*args)
puts "diagnostic output" if options[:verbose]
def exec(*args)
desc "exec", "Run a shell command"
check_unknown_options! :except => :exec
stop_on_unknown_option! :exec
class_option "verbose", :type => :boolean
which should be handled by Thor.
arguments to that command. The command itself also accepts some options,
an external command. A user may want to pass arbitrary options and
To better understand how this is useful, let's consider a command that calls
==== Example
Thor.
options, and where those additional options should not be handled by
This is useful if you have a command that can receive arbitrary additional
argument is encountered. All remaining arguments are passed to the command.
Stop parsing of options as soon as an unknown option or a regular
def stop_on_unknown_option!(*command_names) @stop_on_unknown_option = stop_on_unknown_option | command_names end
def stop_on_unknown_option?(command) #:nodoc:
def stop_on_unknown_option?(command) #:nodoc: command && stop_on_unknown_option.include?(command.name.to_sym) end
def subcommand(subcommand, subcommand_class)
def subcommand(subcommand, subcommand_class) subcommands << subcommand.to_s subcommand_class.subcommand_help subcommand subcommand_classes[subcommand.to_s] = subcommand_class define_method(subcommand) do |*args| args, opts = Thor::Arguments.split(args) invoke_args = [args, opts, {invoked_via_subcommand: true, class_options: options}] invoke_args.unshift "help" if opts.delete("--help") || opts.delete("-h") invoke subcommand_class, *invoke_args end subcommand_class.commands.each do |_meth, command| command.ancestor_name = subcommand end end
def subcommand_classes
def subcommand_classes @subcommand_classes ||= {} end
def subcommand_help(cmd)
def subcommand_help(cmd) desc "help [COMMAND]", "Describe subcommands or one specific subcommand" class_eval " def help(command = nil, subcommand = true); super; end end
def subcommands
def subcommands @subcommands ||= from_superclass(:subcommands, []) end