classThorclassTask<Struct.new(:name,:description,:long_description,:usage,:options)FILE_REGEXP=/^#{Regexp.escape(File.dirname(__FILE__))}/definitialize(name,description,long_description,usage,options=nil)super(name.to_s,description,long_description,usage,options||{})enddefinitialize_copy(other)#:nodoc:super(other)self.options=other.options.dupifother.optionsenddefhidden?falseend# By default, a task invokes a method in the thor class. You can change this# implementation to create custom tasks.defrun(instance,args=[])arity=nilifprivate_method?(instance)instance.class.handle_no_task_error(name)elsifpublic_method?(instance)arity=instance.method(name).arityinstance.send(name,*args)elsiflocal_method?(instance,:method_missing)instance.send(:method_missing,name.to_sym,*args)elseinstance.class.handle_no_task_error(name)endrescueArgumentError=>ehandle_argument_error?(instance,e,caller)?instance.class.handle_argument_error(self,e,arity):(raisee)rescueNoMethodError=>ehandle_no_method_error?(instance,e,caller)?instance.class.handle_no_task_error(name):(raisee)end# Returns the formatted usage by injecting given required arguments# and required options into the given usage.defformatted_usage(klass,namespace=true,subcommand=false)ifnamespacenamespace=klass.namespaceformatted="#{namespace.gsub(/^(default)/,'')}:"endformatted="#{klass.namespace.split(':').last} "ifsubcommandformatted||=""# Add usage with required argumentsformatted<<ifklass&&!klass.arguments.empty?usage.to_s.gsub(/^#{name}/)do|match|match<<" "<<klass.arguments.map{|a|a.usage}.compact.join(' ')endelseusage.to_send# Add required optionsformatted<<" #{required_options}"# Strip and go!formatted.stripendprotecteddefnot_debugging?(instance)!(instance.class.respond_to?(:debugging)&&instance.class.debugging)enddefrequired_options@required_options||=options.map{|_,o|o.usageifo.required?}.compact.sort.join(" ")end# Given a target, checks if this class name is a public method.defpublic_method?(instance)#:nodoc:!(instance.public_methods&[name.to_s,name.to_sym]).empty?enddefprivate_method?(instance)!(instance.private_methods&[name.to_s,name.to_sym]).empty?enddeflocal_method?(instance,name)methods=instance.public_methods(false)+instance.private_methods(false)+instance.protected_methods(false)!(methods&[name.to_s,name.to_sym]).empty?enddefsans_backtrace(backtrace,caller)#:nodoc:saned=backtrace.reject{|frame|frame=~FILE_REGEXP||(frame=~/\.java:/&&RUBY_PLATFORM=~/java/)}saned-=callerenddefhandle_argument_error?(instance,error,caller)not_debugging?(instance)&&error.message=~/wrong number of arguments/&&beginsaned=sans_backtrace(error.backtrace,caller)# Ruby 1.9 always include the called method in the backtracesaned.empty?||(saned.size==1&&RUBY_VERSION>="1.9")endenddefhandle_no_method_error?(instance,error,caller)not_debugging?(instance)&&error.message=~/^undefined method `#{name}' for #{Regexp.escape(instance.to_s)}$/endend# A task that is hidden in help messages but still invocable.classHiddenTask<Taskdefhidden?trueendend# A dynamic task that handles method missing scenarios.classDynamicTask<Taskdefinitialize(name,options=nil)super(name.to_s,"A dynamically-generated task",name.to_s,name.to_s,options)enddefrun(instance,args=[])if(instance.methods&[name.to_s,name.to_sym]).empty?superelseinstance.class.handle_no_task_error(name)endendendend