module Bundler::Thor::Base::ClassMethods
def all_commands
objects as values.
OrderedHash:: An ordered hash with commands names as keys and Bundler::Thor::Command
==== Returns
Returns the commands for this Bundler::Thor class and all subclasses.
def all_commands @all_commands ||= from_superclass(:all_commands, Bundler::Thor::CoreExt::OrderedHash.new) @all_commands.merge(commands) end
def argument(name, options = {}) # rubocop:disable MethodLength
ArgumentError:: Raised if you supply a required argument after a non required one.
==== Errors
:banner - String to show on usage notes.
:default - Default value for this argument. It cannot be required and have default values.
:type - The type of the argument, can be :string, :hash, :array, :numeric.
:optional - If the argument is optional or not.
:required - If the argument is required or not.
:desc - Description for the argument.
==== Options
options
name
==== Parameters
try it, an error is raised.
you cannot have a required argument after a non-required argument. If you
optional (supplying :optional => :true or :required => false), although
Finally, arguments cannot have type :default or :boolean but can be
while options are all kept in a hash (self.options).
Besides, arguments are used inside your code as an accessor (self.argument),
thor command --name=NAME
Instead of:
thor command NAME
from position:
is how they are parsed from the command line, arguments are retrieved
Arguments are different from options in several aspects. The first one
Adds an argument to the class and creates an attr_accessor for it.
def argument(name, options = {}) # rubocop:disable MethodLength is_thor_reserved_word?(name, :argument) no_commands { attr_accessor name } required = if options.key?(:optional) !options[:optional] elsif options.key?(:required) options[:required] else options[:default].nil? end remove_argument name arguments.each do |argument| next if argument.required? fail ArgumentError, "You cannot have #{name.to_s.inspect} as required argument after " << "the non-required argument #{argument.human_name.inspect}." end if required options[:required] = required arguments << Bundler::Thor::Argument.new(name, options) end
def arguments
Array[Bundler::Thor::Argument]
==== Returns
Returns this class arguments, looking up in the ancestors chain.
def arguments @arguments ||= from_superclass(:arguments, []) end
def attr_accessor(*) #:nodoc:
def attr_accessor(*) #:nodoc: no_commands { super } end
def attr_reader(*) #:nodoc:
def attr_reader(*) #:nodoc: no_commands { super } end
def attr_writer(*) #:nodoc:
def attr_writer(*) #:nodoc: no_commands { super } end
def baseclass #:nodoc:
finishes.
SIGNATURE: Sets the baseclass. This is where the superclass lookup
def baseclass #:nodoc: end
def basename
The basename of the program invoking the thor class.
def basename File.basename($PROGRAM_NAME).split(" ").first end
def build_option(name, options, scope) #:nodoc:
scope
options
name
==== Parameters
Build an option and adds it to the given scope.
def build_option(name, options, scope) #:nodoc: scope[name] = Bundler::Thor::Option.new(name, options) end
def build_options(options, scope) #:nodoc:
Hash[Symbol => Object]
==== Parameters
build_options :foo => true, :bar => :required, :baz => :string
fast way to set a bunch of options:
Receives a hash of options, parse them and add to the scope. This is a
def build_options(options, scope) #:nodoc: options.each do |key, value| scope[key] = Bundler::Thor::Option.parse(key, value) end end
def check_unknown_options #:nodoc:
def check_unknown_options #:nodoc: @check_unknown_options ||= from_superclass(:check_unknown_options, false) end
def check_unknown_options!
If you want to raise an error for unknown options, call check_unknown_options!
def check_unknown_options! @check_unknown_options = true end
def check_unknown_options?(config) #:nodoc:
def check_unknown_options?(config) #:nodoc: !!check_unknown_options end
def class_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. Note: Bundler::Thor follows a convention of one-dash-one-letter options. Thus aliases like "-something" wouldn't be parsed; use either "\--something" or "-s" instead.
:group:: -- The group for this options. Use by class options to output options in different levels.
:default:: -- Default value for this argument.
:required:: -- If the argument is required or not.
:desc:: -- Description for the argument.
==== Options
options
name
==== Parameters
Adds an option to the set of class options
def class_option(name, options = {}) build_option(name, options, class_options) end
def class_options(options = nil)
Hash[Symbol => Object]
==== Parameters
If you prefer more detailed declaration, check class_option.
class_options :foo => false, :bar => :required, :baz => :string
Adds a bunch of options to the set of class options.
def class_options(options = nil) @class_options ||= from_superclass(:class_options, {}) build_options(options, @class_options) if options @class_options end
def class_options_help(shell, groups = {}) #:nodoc:
any group, it's printed as Class option.
Prints the class options per group. If an option does not belong to
def class_options_help(shell, groups = {}) #:nodoc: # Group options by group class_options.each do |_, value| groups[value.group] ||= [] groups[value.group] << value end # Deal with default group global_options = groups.delete(nil) || [] print_options(shell, global_options) # Print all others groups.each do |group_name, options| print_options(shell, options, group_name) end end
def commands
objects as values.
OrderedHash:: An ordered hash with commands names as keys and Bundler::Thor::Command
==== Returns
Returns the commands for this Bundler::Thor class.
def commands @commands ||= Bundler::Thor::CoreExt::OrderedHash.new end
def create_command(meth) #:nodoc:
called when a new method is added to the class.
SIGNATURE: Creates a new command if valid_command? is true. This method is
def create_command(meth) #:nodoc: end
def dispatch(command, given_args, given_opts, config) #:nodoc:
SIGNATURE: The hook invoked by start.
def dispatch(command, given_args, given_opts, config) #:nodoc: fail NotImplementedError end
def exit_on_failure?
def exit_on_failure? false end
def find_and_refresh_command(name) #:nodoc:
current command hash.
class, just return it, otherwise dup it and add the fresh copy to the
Finds a command with the given name. If the command belongs to the current
def find_and_refresh_command(name) #:nodoc: if commands[name.to_s] commands[name.to_s] elsif command = all_commands[name.to_s] # rubocop:disable AssignmentInCondition commands[name.to_s] = command.clone else fail ArgumentError, "You supplied :for => #{name.inspect}, but the command #{name.inspect} could not be found." end end
def from_superclass(method, default = nil)
Retrieves a value from superclass. If it reaches the baseclass,
def from_superclass(method, default = nil) if self == baseclass || !superclass.respond_to?(method, true) default else value = superclass.send(method) # Ruby implements `dup` on Object, but raises a `TypeError` # if the method is called on immediates. As a result, we # don't have a good way to check whether dup will succeed # without calling it and rescuing the TypeError. begin value.dup rescue TypeError value end end end
def group(name = nil)
name
==== Parameters
that only commands from a pre-defined group will be shown. Defaults to standard.
Defines the group. This is used when thor list is invoked so you can specify
def group(name = nil) if name @group = name.to_s else @group ||= from_superclass(:group, "standard") end end
def handle_argument_error(command, error, args, arity) #:nodoc:
def handle_argument_error(command, error, args, arity) #:nodoc: msg = "ERROR: \"#{basename} #{command.name}\" was called with " msg << "no arguments" if args.empty? msg << "arguments " << args.inspect unless args.empty? msg << "\nUsage: #{banner(command).inspect}" fail InvocationError, msg end
def handle_no_command_error(command, has_namespace = $thor_runner) #:nodoc:
def handle_no_command_error(command, has_namespace = $thor_runner) #:nodoc: if has_namespace fail UndefinedCommandError, "Could not find command #{command.inspect} in #{namespace.inspect} namespace." else fail UndefinedCommandError, "Could not find command #{command.inspect}." end end
def inherited(klass)
Everytime someone inherits from a Bundler::Thor class, register the klass
def inherited(klass) Bundler::Thor::Base.register_klass_file(klass) klass.instance_variable_set(:@no_commands, false) end
def initialize_added #:nodoc:
class.
SIGNATURE: Defines behavior when the initialize method is added to the
def initialize_added #:nodoc: end
def is_thor_reserved_word?(word, type) #:nodoc:
Raises an error if the word given is a Bundler::Thor reserved word.
def is_thor_reserved_word?(word, type) #:nodoc: return false unless THOR_RESERVED_WORDS.include?(word.to_s) fail "#{word.inspect} is a Bundler::Thor reserved word and cannot be defined as #{type}" end
def method_added(meth)
Fire this callback whenever a method is added. Added methods are
def method_added(meth) meth = meth.to_s if meth == "initialize" initialize_added return end # Return if it's not a public instance method return unless public_method_defined?(meth.to_sym) @no_commands ||= false return if @no_commands || !create_command(meth) is_thor_reserved_word?(meth, :command) Bundler::Thor::Base.register_klass_file(self) end
def namespace(name = nil)
thor :my_command
Your commands can be invoked with a shortcut. Instead of:
namespace :default
Finally, if you change your namespace to default:
thor my_scripts -h
You change how your commands are invoked:
namespace :my_scripts
If you change the namespace:
thor scripts:my_script -h
Scripts::MyScript, the help method, for example, will be called as:
namespace is retrieved from the class name. If your Bundler::Thor class is named
Sets the namespace for the Bundler::Thor or Bundler::Thor::Group class. By default the
def namespace(name = nil) if name @namespace = name.to_s else @namespace ||= Bundler::Thor::Util.namespace_from_thor_class(self) end end
def no_commands
end
remove_command :this_is_not_a_command
end
def this_is_not_a_command
class MyScript < Bundler::Thor
You can also add the method and remove it from the command list:
end
end
end
def this_is_not_a_command
no_commands do
class MyScript < Bundler::Thor
So you can do:
All methods defined inside the given block are not added as commands.
def no_commands @no_commands = true yield ensure @no_commands = false end
def print_options(shell, options, group_name = nil)
def print_options(shell, options, group_name = nil) return if options.empty? list = [] padding = options.map { |o| o.aliases.size }.max.to_i * 4 options.each do |option| unless option.hide item = [option.usage(padding)] item.push(option.description ? "# #{option.description}" : "") list << item list << ["", "# Default: #{option.default}"] if option.show_default? list << ["", "# Possible values: #{option.enum.join(', ')}"] if option.enum end end shell.say(group_name ? "#{group_name} options:" : "Options:") shell.print_table(list, :indent => 2) shell.say "" end
def public_command(*names)
public_command :foo, :bar, :baz
public_command :foo
==== Examples
names
==== Parameters
Allows to use private methods from parent in child classes as commands.
def public_command(*names) names.each do |name| class_eval "def #{name}(*); super end" end end
def remove_argument(*names)
remove_argument :foo, :bar, :baz, :undefine => true
remove_argument :foo
==== Examples
names
==== Parameters
accessors as well.
Removes a previous defined argument. If :undefine is given, undefine
def remove_argument(*names) options = names.last.is_a?(Hash) ? names.pop : {} names.each do |name| arguments.delete_if { |a| a.name == name.to_s } undef_method name, "#{name}=" if options[:undefine] end end
def remove_class_option(*names)
remove_class_option :foo, :bar, :baz
remove_class_option :foo
==== Examples
names
==== Parameters
Removes a previous defined class option.
def remove_class_option(*names) names.each do |name| class_options.delete(name) end end
def remove_command(*names)
to be undefined from the class as well.
options
name
==== Parameters
:undefine => true to undefine the method from the class as well.
By default it only remove the mapping to the command. But you can supply
anymore.
are inheriting from another class and don't want it to be available
Removes a given command from this Bundler::Thor class. This is usually done if you
def remove_command(*names) options = names.last.is_a?(Hash) ? names.pop : {} names.each do |name| commands.delete(name.to_s) all_commands.delete(name.to_s) undef_method name if options[:undefine] end end
def start(given_args = ARGV, config = {})
script.invoke(:command, first_arg, second_arg, third_arg)
script = MyScript.new(args, options, config)
can simply initialize it:
from an array. If you are inside Ruby and want to use a Bundler::Thor class, you
and invoke the command. This method is used when the arguments must be parsed
Parses the command and options from the given args, instantiate the class
def start(given_args = ARGV, config = {}) config[:shell] ||= Bundler::Thor::Base.shell.new dispatch(nil, given_args.dup, nil, config) rescue Bundler::Thor::Error => e config[:debug] || ENV["THOR_DEBUG"] == "1" ? (raise e) : config[:shell].error(e.message) exit(1) if exit_on_failure? rescue Errno::EPIPE # This happens if a thor command is piped to something like `head`, # which closes the pipe when it's done reading. This will also # mean that if the pipe is closed, further unnecessary # computation will not occur. exit(0) end
def stop_on_unknown_option?(command_name) #:nodoc:
the command as regular arguments.
regular argument is encountered. All remaining arguments are passed to
If true, option parsing is suspended as soon as an unknown option or a
def stop_on_unknown_option?(command_name) #:nodoc: false end
def strict_args_position #:nodoc:
def strict_args_position #:nodoc: @strict_args_position ||= from_superclass(:strict_args_position, false) end
def strict_args_position!
call strict_args_position! This is disabled by default to allow dynamic
If you want only strict string args (useful when cascading thor classes),
def strict_args_position! @strict_args_position = true end
def strict_args_position?(config) #:nodoc:
def strict_args_position?(config) #:nodoc: !!strict_args_position end