classThorclassCommand<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 command invokes a method in the thor class. You can change this# implementation to create custom commands.defrun(instance,args=[])arity=nilifprivate_method?(instance)instance.class.handle_no_command_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_command_error(name)endrescueArgumentError=>ehandle_argument_error?(instance,e,caller)?instance.class.handle_argument_error(self,e,args,arity):(raisee)rescueNoMethodError=>ehandle_no_method_error?(instance,e,caller)?instance.class.handle_no_command_error(name):(faile)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)}$/endendTask=Command# rubocop:disable ConstantName# A command that is hidden in help messages but still invocable.classHiddenCommand<Commanddefhidden?trueendendHiddenTask=HiddenCommand# rubocop:disable ConstantName# A dynamic command that handles method missing scenarios.classDynamicCommand<Commanddefinitialize(name,options=nil)super(name.to_s,'A dynamically-generated command',name.to_s,name.to_s,options)enddefrun(instance,args=[])if(instance.methods&[name.to_s,name.to_sym]).empty?superelseinstance.class.handle_no_command_error(name)endendendDynamicTask=DynamicCommand# rubocop:disable ConstantNameend