classBundler::ThorclassCommand<Struct.new(:name,:description,:long_description,:usage,:options,:ancestor_name)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):(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)ifancestor_nameformatted="#{ancestor_name} ".dup# add spaceelsifnamespacenamespace=klass.namespaceformatted="#{namespace.gsub(/^(default)/,'')}:".dupendformatted||="#{klass.namespace.split(':').last} ".dupifsubcommandformatted||="".dupArray(usage).mapdo|specific_usage|formatted_specific_usage=formattedformatted_specific_usage+=required_arguments_for(klass,specific_usage)# Add required optionsformatted_specific_usage+=" #{required_options}"# Strip and go!formatted_specific_usage.stripend.join("\n")endprotected# Add usage with required argumentsdefrequired_arguments_for(klass,usage)ifklass&&!klass.arguments.empty?usage.to_s.gsub(/^#{name}/)do|match|match<<" "<<klass.arguments.map(&:usage).compact.join(" ")endelseusage.to_sendenddefnot_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/)||(frame=~%r{^kernel/}&&RUBY_ENGINE=~/rbx/)}saned-callerenddefhandle_argument_error?(instance,error,caller)not_debugging?(instance)&&(error.message=~/wrong number of arguments/||error.message=~/given \d*, expected \d*/)&&beginsaned=sans_backtrace(error.backtrace,caller)saned.empty?||saned.size==1endenddefhandle_no_method_error?(instance,error,caller)not_debugging?(instance)&&error.message=~/^undefined method `#{name}' for #{Regexp.escape(instance.to_s)}$/endendTask=Command# A command that is hidden in help messages but still invocable.classHiddenCommand<Commanddefhidden?trueendendHiddenTask=HiddenCommand# 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=DynamicCommandend