diff options
Diffstat (limited to 'railties/lib/rails/vendor/thor-0.12.0/lib/thor/task.rb')
-rw-r--r-- | railties/lib/rails/vendor/thor-0.12.0/lib/thor/task.rb | 122 |
1 files changed, 122 insertions, 0 deletions
diff --git a/railties/lib/rails/vendor/thor-0.12.0/lib/thor/task.rb b/railties/lib/rails/vendor/thor-0.12.0/lib/thor/task.rb new file mode 100644 index 0000000000..91c7564d3f --- /dev/null +++ b/railties/lib/rails/vendor/thor-0.12.0/lib/thor/task.rb @@ -0,0 +1,122 @@ +class Thor + class Task < Struct.new(:name, :description, :usage, :options) + + # A dynamic task that handles method missing scenarios. + # + class Dynamic < Task + def initialize(name) + super(name.to_s, "A dynamically-generated task", name.to_s) + end + + def run(instance, args=[]) + unless (instance.methods & [name.to_s, name.to_sym]).empty? + raise Error, "could not find Thor class or task '#{name}'" + end + super + end + end + + def initialize(name, description, usage, options=nil) + super(name.to_s, description, usage, options || {}) + end + + def initialize_copy(other) #:nodoc: + super(other) + self.options = other.options.dup if other.options + end + + def short_description + description.split("\n").first if description + end + + # By default, a task invokes a method in the thor class. You can change this + # implementation to create custom tasks. + # + def run(instance, args=[]) + raise UndefinedTaskError, "the '#{name}' task of #{instance.class} is private" unless public_method?(instance) + instance.send(name, *args) + rescue ArgumentError => e + parse_argument_error(instance, e, caller) + rescue NoMethodError => e + parse_no_method_error(instance, e) + end + + # Returns the formatted usage. If a class is given, the class arguments are + # injected in the usage. + # + def formatted_usage(klass=nil, namespace=false, show_options=true) + formatted = if namespace.is_a?(String) + "#{namespace}:" + elsif klass && namespace + "#{klass.namespace.gsub(/^default/,'')}:" + else + "" + end + + formatted << formatted_arguments(klass) + formatted << " #{formatted_options}" if show_options + formatted.strip! + formatted + end + + # Injects the class arguments into the task usage. + # + def formatted_arguments(klass) + if klass && !klass.arguments.empty? + usage.to_s.gsub(/^#{name}/) do |match| + match << " " << klass.arguments.map{ |a| a.usage }.join(' ') + end + else + usage.to_s + end + end + + # Returns the options usage for this task. + # + def formatted_options + @formatted_options ||= options.map{ |_, o| o.usage }.sort.join(" ") + end + + protected + + # Given a target, checks if this class name is not a private/protected method. + # + def public_method?(instance) #:nodoc: + collection = instance.private_methods + instance.protected_methods + (collection & [name.to_s, name.to_sym]).empty? + end + + # Clean everything that comes from the Thor gempath and remove the caller. + # + def sans_backtrace(backtrace, caller) #:nodoc: + dirname = /^#{Regexp.escape(File.dirname(__FILE__))}/ + saned = backtrace.reject { |frame| frame =~ dirname } + saned -= caller + end + + def parse_argument_error(instance, e, caller) #:nodoc: + backtrace = sans_backtrace(e.backtrace, caller) + + if backtrace.empty? && e.message =~ /wrong number of arguments/ + if instance.is_a?(Thor::Group) + raise e, "'#{name}' was called incorrectly. Are you sure it has arity equals to 0?" + else + raise InvocationError, "'#{name}' was called incorrectly. Call as " << + "'#{formatted_usage(instance.class, true)}'" + end + else + raise e + end + end + + def parse_no_method_error(instance, e) #:nodoc: + if e.message =~ /^undefined method `#{name}' for #{Regexp.escape(instance.to_s)}$/ + raise UndefinedTaskError, "The #{instance.class.namespace} namespace " << + "doesn't have a '#{name}' task" + else + raise e + end + end + + end +end |