$:.unshift File.expand_path(File.dirname(__FILE__)) require 'thor/base' require 'thor/group' require 'thor/actions' class Thor class << self # Sets the default task when thor is executed without an explicit task to be called. # # ==== Parameters # meth:: name of the defaut task # def default_task(meth=nil) case meth when :none @default_task = 'help' when nil @default_task ||= from_superclass(:default_task, 'help') else @default_task = meth.to_s end end # Defines the usage and the description of the next task. # # ==== Parameters # usage # description # def desc(usage, description, options={}) if options[:for] task = find_and_refresh_task(options[:for]) task.usage = usage if usage task.description = description if description else @usage, @desc = usage, description end end # Maps an input to a task. If you define: # # map "-T" => "list" # # Running: # # thor -T # # Will invoke the list task. # # ==== Parameters # Hash[String|Array => Symbol]:: Maps the string or the strings in the array to the given task. # 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 # Declares the options for the next task 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 :optional, :required, :boolean or :numeric. # def method_options(options=nil) @method_options ||= Thor::CoreExt::OrderedHash.new build_options(options, @method_options) if options @method_options end # Adds an option to the set of class options. If :for is given as option, # it allows you to change the options from a previous defined task. # # def previous_task # # magic # end # # method_options :foo => :bar, :for => :previous_task # # def next_task # # magic # end # # ==== Parameters # name:: The name of the argument. # options:: 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, :boolean or :default. # Default accepts arguments as booleans (--switch) or as strings (--switch=VALUE). # def method_option(name, options) scope = if options[:for] find_and_refresh_task(options[:for]).options else method_options end build_option(name, options, scope) 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 # 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) # def start(args=ARGV, config={}) config[:shell] ||= Thor::Base.shell.new meth = normalize_task_name(args.shift) task = self[meth] options = class_options.merge(task.options) opts = Thor::Options.new(options) opts.parse(args) instance = new(opts.arguments, opts.options, config) instance.invoke(task.name, *opts.trailing) rescue Thor::Error => e config[:shell].error e.message end # Prints help information. If a task name is given, it shows information # only about the specific task. # # ==== Parameters # meth:: An optional task name to print usage information about. # # ==== Options # namespace:: When true, shows the namespace in the output before the usage. # skip_inherited:: When true, does not show tasks from superclass. # def help(shell, meth=nil, options={}) meth, options = nil, meth if meth.is_a?(Hash) if meth task = self.all_tasks[meth] raise UndefinedTaskError, "task '#{meth}' could not be found in namespace '#{self.namespace}'" unless task shell.say "Usage:" shell.say " #{banner(task, options[:namespace])}" shell.say class_options_help(shell, "Class") shell.say task.description else list = (options[:short] ? tasks : all_tasks).map do |_, task| [ banner(task, options[:namespace]), task.short_description || '' ] end if options[:short] shell.print_table(list, :emphasize_last => true) else shell.say "Tasks:" shell.print_table(list, :ident => 2, :emphasize_last => true) shell.say class_options_help(shell, "Class") end end end protected # The banner for this class. You can customize it if you are invoking the # thor class by another means which is not the Thor::Runner. It receives # the task that is going to be invoked and if the namespace should be # displayed. # def banner(task, namespace=true) #:nodoc: task.formatted_usage(self, namespace) end def baseclass #:nodoc: Thor end def valid_task?(meth) #:nodoc: public_instance_methods.include?(meth) && @usage && @desc end def create_task(meth) #:nodoc: tasks[meth.to_s] = Thor::Task.new(meth, @desc, @usage, method_options) @usage, @desc, @method_options = nil end def initialize_added #:nodoc: class_options.merge!(method_options) @method_options = nil end # Receives a task name (can be nil), and try to get a map from it. # If a map can't be found use the sent name or the default task. # def normalize_task_name(meth) #:nodoc: mapping = map[meth.to_s] meth = mapping || meth || default_task meth.to_s.gsub('-','_') # treat foo-bar > foo_bar end end include Thor::Base map HELP_MAPPINGS => :help desc "help [TASK]", "Describe available tasks or one specific task" def help(task=nil) self.class.help(shell, task, :namespace => task && task.include?(?:)) end end