lib/github_cli/vendor/thor/base.rb in github_cli-0.5.3 vs lib/github_cli/vendor/thor/base.rb in github_cli-0.5.4

- old
+ new

@@ -1,17 +1,18 @@ +require 'thor/command' require 'thor/core_ext/hash_with_indifferent_access' require 'thor/core_ext/ordered_hash' require 'thor/error' -require 'thor/shell' require 'thor/invocation' require 'thor/parser' -require 'thor/task' +require 'thor/shell' require 'thor/util' class Thor autoload :Actions, 'thor/actions' autoload :RakeCompat, 'thor/rake_compat' + autoload :Group, 'thor/group' # Shortcuts for help. HELP_MAPPINGS = %w(-h -? --help -D) # Thor methods that should not be overwritten by the user. @@ -44,24 +45,26 @@ # that looks like an option (starts with - or --). It then calls # new, passing in the two halves of the arguments Array as the # first two parameters. if options.is_a?(Array) - task_options = config.delete(:task_options) # hook for start - parse_options = parse_options.merge(task_options) if task_options + command_options = config.delete(:command_options) # hook for start + parse_options = parse_options.merge(command_options) if command_options array_options, hash_options = options, {} else # Handle the case where the class was explicitly instantiated # with pre-parsed options. array_options, hash_options = [], options end # Let Thor::Options parse the options first, so it can remove # declared options from the array. This will leave us with # a list of arguments that weren't declared. - opts = Thor::Options.new(parse_options, hash_options) + stop_on_unknown = self.class.stop_on_unknown_option? config[:current_command] + opts = Thor::Options.new(parse_options, hash_options, stop_on_unknown) self.options = opts.parse(array_options) + self.options = config[:class_options].merge(self.options) if config[:class_options] # If unknown options are disallowed, make sure that none of the # remaining arguments looks like an option. opts.check_unknown! if self.class.check_unknown_options?(config) @@ -114,22 +117,10 @@ file_subclasses << klass unless file_subclasses.include?(klass) end end module ClassMethods - def attr_reader(*) #:nodoc: - no_tasks { super } - end - - def attr_writer(*) #:nodoc: - no_tasks { super } - end - - def attr_accessor(*) #:nodoc: - no_tasks { super } - end - # If you want to raise an error for unknown options, call check_unknown_options! # This is disabled by default to allow dynamic invocations. def check_unknown_options! @check_unknown_options = true end @@ -140,10 +131,17 @@ def check_unknown_options?(config) #:nodoc: !!check_unknown_options end + # If true, option parsing is suspended as soon as an unknown option or a + # regular argument is encountered. All remaining arguments are passed to + # the command as regular arguments. + def stop_on_unknown_option?(command_name) #:nodoc: + false + end + # If you want only strict string args (useful when cascading thor classes), # call strict_args_position! This is disabled by default to allow dynamic # invocations. def strict_args_position! @strict_args_position = true @@ -161,15 +159,15 @@ # # Arguments are different from options in several aspects. The first one # is how they are parsed from the command line, arguments are retrieved # from position: # - # thor task NAME + # thor command NAME # # Instead of: # - # thor task --name=NAME + # thor command --name=NAME # # Besides, arguments are used inside your code as an accessor (self.argument), # while options are all kept in a hash (self.options). # # Finally, arguments cannot have type :default or :boolean but can be @@ -192,11 +190,11 @@ # ==== Errors # ArgumentError:: Raised if you supply a required argument after a non required one. # def argument(name, options={}) is_thor_reserved_word?(name, :argument) - no_tasks { attr_accessor name } + no_commands { attr_accessor name } required = if options.key?(:optional) !options[:optional] elsif options.key?(:required) options[:required] @@ -296,92 +294,96 @@ class_options.delete(name) end end # Defines the group. This is used when thor list is invoked so you can specify - # that only tasks from a pre-defined group will be shown. Defaults to standard. + # that only commands from a pre-defined group will be shown. Defaults to standard. # # ==== Parameters # name<String|Symbol> # def group(name=nil) - case name - when nil - @group ||= from_superclass(:group, 'standard') - else - @group = name.to_s + @group = case name + when nil + @group || from_superclass(:group, 'standard') + else + name.to_s end end - # Returns the tasks for this Thor class. + # Returns the commands for this Thor class. # # ==== Returns - # OrderedHash:: An ordered hash with tasks names as keys and Thor::Task + # OrderedHash:: An ordered hash with commands names as keys and Thor::Command # objects as values. # - def tasks - @tasks ||= Thor::CoreExt::OrderedHash.new + def commands + @commands ||= Thor::CoreExt::OrderedHash.new end + alias tasks commands - # Returns the tasks for this Thor class and all subclasses. + # Returns the commands for this Thor class and all subclasses. # # ==== Returns - # OrderedHash:: An ordered hash with tasks names as keys and Thor::Task + # OrderedHash:: An ordered hash with commands names as keys and Thor::Command # objects as values. # - def all_tasks - @all_tasks ||= from_superclass(:all_tasks, Thor::CoreExt::OrderedHash.new) - @all_tasks.merge(tasks) + def all_commands + @all_commands ||= from_superclass(:all_commands, Thor::CoreExt::OrderedHash.new) + @all_commands.merge(commands) end + alias all_tasks all_commands - # Removes a given task from this Thor class. This is usually done if you + # Removes a given command from this Thor class. This is usually done if you # are inheriting from another class and don't want it to be available # anymore. # - # By default it only remove the mapping to the task. But you can supply + # By default it only remove the mapping to the command. But you can supply # :undefine => true to undefine the method from the class as well. # # ==== Parameters - # name<Symbol|String>:: The name of the task to be removed - # options<Hash>:: You can give :undefine => true if you want tasks the method + # name<Symbol|String>:: The name of the command to be removed + # options<Hash>:: You can give :undefine => true if you want commands the method # to be undefined from the class as well. # - def remove_task(*names) + def remove_command(*names) options = names.last.is_a?(Hash) ? names.pop : {} names.each do |name| - tasks.delete(name.to_s) - all_tasks.delete(name.to_s) + commands.delete(name.to_s) + all_commands.delete(name.to_s) undef_method name if options[:undefine] end end + alias remove_task remove_command - # All methods defined inside the given block are not added as tasks. + # All methods defined inside the given block are not added as commands. # # So you can do: # # class MyScript < Thor - # no_tasks do - # def this_is_not_a_task + # no_commands do + # def this_is_not_a_command # end # end # end # - # You can also add the method and remove it from the task list: + # You can also add the method and remove it from the command list: # # class MyScript < Thor - # def this_is_not_a_task + # def this_is_not_a_command # end - # remove_task :this_is_not_a_task + # remove_command :this_is_not_a_command # end # - def no_tasks - @no_tasks = true + def no_commands + @no_commands = true yield ensure - @no_tasks = false + @no_commands = false end + alias no_tasks no_commands # Sets the namespace for the Thor or Thor::Group class. By default the # namespace is retrieved from the class name. If your Thor class is named # Scripts::MyScript, the help method, for example, will be called as: # @@ -389,88 +391,90 @@ # # If you change the namespace: # # namespace :my_scripts # - # You change how your tasks are invoked: + # You change how your commands are invoked: # # thor my_scripts -h # # Finally, if you change your namespace to default: # # namespace :default # - # Your tasks can be invoked with a shortcut. Instead of: + # Your commands can be invoked with a shortcut. Instead of: # - # thor :my_task + # thor :my_command # def namespace(name=nil) - case name + @namespace = case name when nil - @namespace ||= Thor::Util.namespace_from_thor_class(self) + @namespace || Thor::Util.namespace_from_thor_class(self) else @namespace = name.to_s end end - # Parses the task and options from the given args, instantiate the class - # and invoke the task. This method is used when the arguments must be parsed + # Parses the command and options from the given args, instantiate the class + # and invoke the command. This method is used when the arguments must be parsed # from an array. If you are inside Ruby and want to use a Thor class, you # can simply initialize it: # # script = MyScript.new(args, options, config) - # script.invoke(:task, first_arg, second_arg, third_arg) + # script.invoke(:command, first_arg, second_arg, third_arg) # def start(given_args=ARGV, config={}) config[:shell] ||= Thor::Base.shell.new dispatch(nil, given_args.dup, nil, config) rescue Thor::Error => e 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 task is piped to something like `head`, + # 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 - # Allows to use private methods from parent in child classes as tasks. + # Allows to use private methods from parent in child classes as commands. # # ==== Parameters - # names<Array>:: Method names to be used as tasks + # names<Array>:: Method names to be used as commands # # ==== Examples # - # public_task :foo - # public_task :foo, :bar, :baz + # public_command :foo + # public_command :foo, :bar, :baz # - def public_task(*names) + def public_command(*names) names.each do |name| class_eval "def #{name}(*); super end" end end + alias public_task public_command - def handle_no_task_error(task, has_namespace = $thor_runner) #:nodoc: + def handle_no_command_error(command, has_namespace = $thor_runner) #:nodoc: if has_namespace - raise UndefinedTaskError, "Could not find task #{task.inspect} in #{namespace.inspect} namespace." + raise UndefinedCommandError, "Could not find command #{command.inspect} in #{namespace.inspect} namespace." else - raise UndefinedTaskError, "Could not find task #{task.inspect}." + raise UndefinedCommandError, "Could not find command #{command.inspect}." end end + alias handle_no_task_error handle_no_command_error - def handle_argument_error(task, error, arity=nil) #:nodoc: - msg = "#{basename} #{task.name}" - if arity + def handle_argument_error(command, error, arity=nil) #:nodoc: + msg = "#{basename} #{command.name}" + if arity && arity != 0 required = arity < 0 ? (-1 - arity) : arity msg << " requires at least #{required} argument" msg << "s" if required > 1 else msg = "call #{msg} as" end - msg << ": #{self.banner(task).inspect}." + msg << ": #{self.banner(command).inspect}." raise InvocationError, msg end protected @@ -544,47 +548,50 @@ options.each do |key, value| scope[key] = Thor::Option.parse(key, value) end end - # Finds a task with the given name. If the task belongs to the current + # Finds a command with the given name. If the command belongs to the current # class, just return it, otherwise dup it and add the fresh copy to the - # current task hash. - def find_and_refresh_task(name) #:nodoc: - task = if task = tasks[name.to_s] - task - elsif task = all_tasks[name.to_s] - tasks[name.to_s] = task.clone + # current command hash. + def find_and_refresh_command(name) #:nodoc: + command = if command = commands[name.to_s] + command + elsif command = all_commands[name.to_s] + commands[name.to_s] = command.clone else - raise ArgumentError, "You supplied :for => #{name.inspect}, but the task #{name.inspect} could not be found." + raise ArgumentError, "You supplied :for => #{name.inspect}, but the command #{name.inspect} could not be found." end end + alias find_and_refresh_task find_and_refresh_command # Everytime someone inherits from a Thor class, register the klass # and file into baseclass. def inherited(klass) Thor::Base.register_klass_file(klass) - klass.instance_variable_set(:@no_tasks, false) + klass.instance_variable_set(:@no_commands, false) end # Fire this callback whenever a method is added. Added methods are - # tracked as tasks by invoking the create_task method. + # tracked as commands by invoking the create_command method. 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_instance_methods.include?(meth) || - public_instance_methods.include?(meth.to_sym) + return unless public_method_defined?(meth.to_sym) - return if @no_tasks || !create_task(meth) + # Return if attr_* added the method + return if caller.first.to_s[/`attr_(reader|writer|accessor)'/] - is_thor_reserved_word?(meth, :task) + return if @no_commands || !create_command(meth) + + is_thor_reserved_word?(meth, :command) Thor::Base.register_klass_file(self) end # Retrieves a value from superclass. If it reaches the baseclass, # returns default. @@ -619,21 +626,22 @@ # SIGNATURE: Sets the baseclass. This is where the superclass lookup # finishes. def baseclass #:nodoc: end - # SIGNATURE: Creates a new task if valid_task? is true. This method is + # SIGNATURE: Creates a new command if valid_command? is true. This method is # called when a new method is added to the class. - def create_task(meth) #:nodoc: + def create_command(meth) #:nodoc: end + alias create_task create_command # SIGNATURE: Defines behavior when the initialize method is added to the # class. def initialize_added #:nodoc: end # SIGNATURE: The hook invoked by start. - def dispatch(task, given_args, given_opts, config) #:nodoc: + def dispatch(command, given_args, given_opts, config) #:nodoc: raise NotImplementedError end end end