diff options
author | Andre Arko <andre@arko.net> | 2010-02-17 18:33:36 -0800 |
---|---|---|
committer | Andre Arko <andre@arko.net> | 2010-02-17 21:33:56 -0800 |
commit | 749214d04ea3d5bd262e2f43141108f4bdac3367 (patch) | |
tree | 91a2981b3fb0e39aea603e615c7e4e2859c90c7f | |
parent | 44b5c801350d7c29e7ee52ec9a438e49b9c07814 (diff) | |
download | bundler-749214d04ea3d5bd262e2f43141108f4bdac3367.tar.gz |
Update vendored Thor to 0.13.3
-rw-r--r-- | lib/bundler/vendor/thor.rb | 16 | ||||
-rw-r--r-- | lib/bundler/vendor/thor/base.rb | 50 | ||||
-rw-r--r-- | lib/bundler/vendor/thor/error.rb | 3 | ||||
-rw-r--r-- | lib/bundler/vendor/thor/invocation.rb | 31 | ||||
-rw-r--r-- | lib/bundler/vendor/thor/parser/arguments.rb | 9 | ||||
-rw-r--r-- | lib/bundler/vendor/thor/parser/option.rb | 4 | ||||
-rw-r--r-- | lib/bundler/vendor/thor/parser/options.rb | 33 | ||||
-rw-r--r-- | lib/bundler/vendor/thor/task.rb | 49 | ||||
-rw-r--r-- | lib/bundler/vendor/thor/util.rb | 25 | ||||
-rw-r--r-- | lib/bundler/vendor/thor/version.rb | 2 |
10 files changed, 117 insertions, 105 deletions
diff --git a/lib/bundler/vendor/thor.rb b/lib/bundler/vendor/thor.rb index 6bc533adf0..df6ea7bf35 100644 --- a/lib/bundler/vendor/thor.rb +++ b/lib/bundler/vendor/thor.rb @@ -120,8 +120,8 @@ class Thor # script = MyScript.new(args, options, config) # script.invoke(:task, first_arg, second_arg, third_arg) # - def start(given_args=ARGV, config={}) - super do + def start(original_args=ARGV, config={}) + super do |given_args| meth = normalize_task_name(given_args.shift) task = all_tasks[meth] @@ -145,8 +145,9 @@ class Thor # task_name<String> # def task_help(shell, task_name) - task = all_tasks[task_name] - raise UndefinedTaskError, "task '#{task_name}' could not be found in namespace '#{self.namespace}'" unless task + meth = normalize_task_name(task_name) + task = all_tasks[meth] + handle_no_task_error(meth) unless task shell.say "Usage:" shell.say " #{banner(task)}" @@ -183,6 +184,10 @@ class Thor end end + def handle_argument_error(task, error) #:nodoc: + raise InvocationError, "#{task.name.inspect} was called incorrectly. Call as #{task.formatted_usage(self, banner_base == "thor").inspect}." + end + protected # The banner for this class. You can customize it if you are invoking the @@ -191,8 +196,7 @@ class Thor # the namespace should be displayed as arguments. # def banner(task) - base = $thor_runner ? "thor" : File.basename($0.split(" ").first) - "#{base} #{task.formatted_usage(self, base == "thor")}" + "#{banner_base} #{task.formatted_usage(self, banner_base == "thor")}" end def baseclass #:nodoc: diff --git a/lib/bundler/vendor/thor/base.rb b/lib/bundler/vendor/thor/base.rb index 6e6c840427..8d0312c9ce 100644 --- a/lib/bundler/vendor/thor/base.rb +++ b/lib/bundler/vendor/thor/base.rb @@ -38,9 +38,8 @@ class Thor # config<Hash>:: Configuration for this Thor class. # def initialize(args=[], options={}, config={}) - Thor::Arguments.parse(self.class.arguments, args).each do |key, value| - send("#{key}=", value) - end + args = Thor::Arguments.parse(self.class.arguments, args) + args.each { |key, value| send("#{key}=", value) } parse_options = self.class.class_options @@ -52,9 +51,9 @@ class Thor array_options, hash_options = [], options end - options = Thor::Options.parse(parse_options, array_options) - self.options = Thor::CoreExt::HashWithIndifferentAccess.new(options).merge!(hash_options) - self.options.freeze + opts = Thor::Options.new(parse_options, hash_options) + self.options = opts.parse(array_options) + opts.check_unknown! if self.class.check_unknown_options? end class << self @@ -109,6 +108,16 @@ class Thor no_tasks { super } end + # If you want to raise an error for unknown options, call check_unknown_options! + # This is disabled by default to allow dynamic invocations. + def check_unknown_options! + @check_unknown_options = true + end + + def check_unknown_options? #:nodoc: + @check_unknown_options || false + end + # Adds an argument to the class and creates an attr_accessor for it. # # Arguments are different from options in several aspects. The first one @@ -355,7 +364,7 @@ class Thor def namespace(name=nil) case name when nil - @namespace ||= Thor::Util.namespace_from_thor_class(self, false) + @namespace ||= Thor::Util.namespace_from_thor_class(self) else @namespace = name.to_s end @@ -366,14 +375,18 @@ class Thor def start(given_args=ARGV, config={}) self.debugging = given_args.include?("--debug") config[:shell] ||= Thor::Base.shell.new - yield + yield(given_args.dup) rescue Thor::Error => e - if debugging - raise e + debugging ? (raise e) : config[:shell].error(e.message) + exit(1) if exit_on_failure? + end + + def handle_no_task_error(task) #:nodoc: + if self.banner_base == "thor" + raise UndefinedTaskError, "Could not find task #{task.inspect} in #{namespace.inspect} namespace." else - config[:shell].error e.message + raise UndefinedTaskError, "Could not find task #{task.inspect}." end - exit(1) if exit_on_failure? end protected @@ -419,7 +432,6 @@ class Thor end # Raises an error if the word given is a Thor reserved word. - # def is_thor_reserved_word?(word, type) #:nodoc: return false unless THOR_RESERVED_WORDS.include?(word.to_s) raise "#{word.inspect} is a Thor reserved word and cannot be defined as #{type}" @@ -430,7 +442,6 @@ class Thor # ==== Parameters # name<Symbol>:: The name of the argument. # options<Hash>:: Described in both class_option and method_option. - # def build_option(name, options, scope) #:nodoc: scope[name] = Thor::Option.new(name, options[:desc], options[:required], options[:type], options[:default], options[:banner], @@ -444,7 +455,6 @@ class Thor # # ==== Parameters # Hash[Symbol => Object] - # def build_options(options, scope) #:nodoc: options.each do |key, value| scope[key] = Thor::Option.parse(key, value) @@ -454,7 +464,6 @@ class Thor # Finds a task with the given name. If the task belongs to the current # class, just return it, otherwise dup it and add the fresh copy to the # current task hash. - # def find_and_refresh_task(name) #:nodoc: task = if task = tasks[name.to_s] task @@ -467,14 +476,12 @@ class Thor # Everytime someone inherits from a Thor class, register the klass # and file into baseclass. - # def inherited(klass) Thor::Base.register_klass_file(klass) end # Fire this callback whenever a method is added. Added methods are # tracked as tasks by invoking the create_task method. - # def method_added(meth) meth = meth.to_s @@ -495,7 +502,6 @@ class Thor # Retrieves a value from superclass. If it reaches the baseclass, # returns default. - # def from_superclass(method, default=nil) if self == baseclass || !superclass.respond_to?(method, true) default @@ -506,11 +512,15 @@ class Thor end # A flag that makes the process exit with status 1 if any error happens. - # def exit_on_failure? false end + # Returns the base for banner. + def banner_base + @banner_base ||= $thor_runner ? "thor" : File.basename($0.split(" ").first) + end + # SIGNATURE: Sets the baseclass. This is where the superclass lookup # finishes. def baseclass #:nodoc: diff --git a/lib/bundler/vendor/thor/error.rb b/lib/bundler/vendor/thor/error.rb index f9b31a35d1..9746b88245 100644 --- a/lib/bundler/vendor/thor/error.rb +++ b/lib/bundler/vendor/thor/error.rb @@ -19,6 +19,9 @@ class Thor class InvocationError < Error end + class UnknownArgumentError < Error + end + class RequiredArgumentMissingError < InvocationError end diff --git a/lib/bundler/vendor/thor/invocation.rb b/lib/bundler/vendor/thor/invocation.rb index 32e6a72454..3f74e3458e 100644 --- a/lib/bundler/vendor/thor/invocation.rb +++ b/lib/bundler/vendor/thor/invocation.rb @@ -5,21 +5,20 @@ class Thor end module ClassMethods - # Prepare for class methods invocations. This method must return a klass to - # have the invoked class options showed in help messages in generators. - # + # This method is responsible for receiving a name and find the proper + # class and task for it. The key is an optional parameter which is + # available only in class methods invocations (i.e. in Thor::Group). def prepare_for_invocation(key, name) #:nodoc: case name when Symbol, String - Thor::Util.namespace_to_thor_class_and_task(name.to_s, false) + Thor::Util.find_class_and_task_by_namespace(name.to_s) else name end end end - # Make initializer aware of invocations and the initializer proc. - # + # Make initializer aware of invocations and the initialization args. def initialize(args=[], options={}, config={}, &block) #:nodoc: @_invocations = config[:invocations] || Hash.new { |h,k| h[k] = [] } @_initializer = [ args, options, config ] @@ -34,6 +33,8 @@ class Thor # the task to be invoked, if none is given, the same values used to # initialize the invoker are used to initialize the invoked. # + # When no name is given, it will invoke the default task of the current class. + # # ==== Examples # # class A < Thor @@ -92,9 +93,9 @@ class Thor # # invoke Rspec::RR, [], :style => :foo # - def invoke(name=nil, task=nil, args=nil, opts=nil, config=nil) - task, args, opts, config = nil, task, args, opts if task.nil? || task.is_a?(Array) - args, opts, config = nil, args, opts if args.is_a?(Hash) + def invoke(name=nil, *args) + args.unshift(nil) if Array === args.first || NilClass === args.first + task, args, opts, config = args object, task = _prepare_for_invocation(name, task) klass, instance = _initialize_klass_with_initializer(object, args, opts, config) @@ -121,15 +122,13 @@ class Thor protected # Configuration values that are shared between invocations. - # def _shared_configuration #:nodoc: { :invocations => @_invocations } end - # Prepare for invocation in the instance level. In this case, we have to - # take into account that a just a task name from the current class was - # given or even a Thor::Task object. - # + # This method can receive several different types of arguments and it's then + # responsible to normalize them by returning the object where the task should + # be invoked and a Thor::Task object. def _prepare_for_invocation(name, sent_task=nil) #:nodoc: if name.is_a?(Thor::Task) task = name @@ -147,18 +146,16 @@ class Thor # Check if the object given is a Thor class object and get a task object # for it. - # def _validate_task(object, task) #:nodoc: klass = object.is_a?(Class) ? object : object.class raise "Expected Thor class, got #{klass}" unless klass <= Thor::Base - task ||= klass.default_task if klass <= Thor + task ||= klass.default_task if klass.respond_to?(:default_task) task = klass.all_tasks[task.to_s] || Thor::Task::Dynamic.new(task) if task && !task.is_a?(Thor::Task) task end # Initialize klass using values stored in the @_initializer. - # def _initialize_klass_with_initializer(object, args, opts, config) #:nodoc: if object.is_a?(Class) klass = object diff --git a/lib/bundler/vendor/thor/parser/arguments.rb b/lib/bundler/vendor/thor/parser/arguments.rb index fb5d965e06..1fb1f03b31 100644 --- a/lib/bundler/vendor/thor/parser/arguments.rb +++ b/lib/bundler/vendor/thor/parser/arguments.rb @@ -16,8 +16,9 @@ class Thor return arguments, args[Range.new(arguments.size, -1)] end - def self.parse(base, args) - new(base).parse(args) + def self.parse(*args) + to_parse = args.pop + new(*args).parse(to_parse) end # Takes an array of Thor::Argument objects. @@ -116,7 +117,7 @@ class Thor return shift if peek.is_a?(Numeric) unless peek =~ NUMERIC && $& == peek - raise MalformattedArgumentError, "expected numeric value for '#{name}'; got #{peek.inspect}" + raise MalformattedArgumentError, "Expected numeric value for '#{name}'; got #{peek.inspect}" end $&.index('.') ? shift.to_f : shift.to_i @@ -137,7 +138,7 @@ class Thor end.join("', '") class_name = self.class.name.split('::').last.downcase - raise RequiredArgumentMissingError, "no value provided for required #{class_name} '#{names}'" + raise RequiredArgumentMissingError, "No value provided for required #{class_name} '#{names}'" end end diff --git a/lib/bundler/vendor/thor/parser/option.rb b/lib/bundler/vendor/thor/parser/option.rb index 9e40ec73fa..fee89067b8 100644 --- a/lib/bundler/vendor/thor/parser/option.rb +++ b/lib/bundler/vendor/thor/parser/option.rb @@ -55,10 +55,6 @@ class Thor value elsif required = (value == :required) :string - elsif value == :optional - # TODO Remove this warning in the future. - warn "Optional type is deprecated. Choose :boolean or :string instead. Assumed to be :boolean." - :boolean end when TrueClass, FalseClass :boolean diff --git a/lib/bundler/vendor/thor/parser/options.rb b/lib/bundler/vendor/thor/parser/options.rb index 75092308b5..d557ce5bda 100644 --- a/lib/bundler/vendor/thor/parser/options.rb +++ b/lib/bundler/vendor/thor/parser/options.rb @@ -10,7 +10,6 @@ class Thor SHORT_NUM = /^(-[a-z])#{NUMERIC}$/i # Receives a hash and makes it switches. - # def self.to_switches(options) options.map do |key, value| case value @@ -28,12 +27,18 @@ class Thor end.join(" ") end - # Takes a hash of Thor::Option objects. - # - def initialize(options={}) - options = options.values + # Takes a hash of Thor::Option and a hash with defaults. + def initialize(hash_options={}, defaults={}) + options = hash_options.values super(options) - @shorts, @switches = {}, {} + + # Add defaults + defaults.each do |key, value| + @assigns[key.to_s] = value + @non_assigned_required.delete(hash_options[key]) + end + + @shorts, @switches, @unknown = {}, {}, [] options.each do |option| @switches[option.switch_name] = option @@ -61,16 +66,24 @@ class Thor end switch = normalize_switch(switch) - next unless option = switch_option(switch) - + option = switch_option(switch) @assigns[option.human_name] = parse_peek(switch, option) + elsif peek =~ /^\-/ + @unknown << shift else shift end end check_requirement! - @assigns + + assigns = Thor::CoreExt::HashWithIndifferentAccess.new(@assigns) + assigns.freeze + assigns + end + + def check_unknown! + raise UnknownArgumentError, "Unknown switches '#{@unknown.join(', ')}'" unless @unknown.empty? end protected @@ -130,7 +143,7 @@ class Thor elsif option.string? && !option.required? return option.human_name # Return the option name else - raise MalformattedArgumentError, "no value provided for option '#{switch}'" + raise MalformattedArgumentError, "No value provided for option '#{switch}'" end end diff --git a/lib/bundler/vendor/thor/task.rb b/lib/bundler/vendor/thor/task.rb index f0522d807a..856ef16a22 100644 --- a/lib/bundler/vendor/thor/task.rb +++ b/lib/bundler/vendor/thor/task.rb @@ -9,10 +9,11 @@ class Thor 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}'" + if (instance.methods & [name.to_s, name.to_sym]).empty? + super + else + instance.class.handle_no_task_error(name) end - super end end @@ -28,14 +29,14 @@ class Thor # 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) + public_method?(instance) ? + instance.send(name, *args) : instance.class.handle_no_task_error(name) rescue ArgumentError => e - raise e if instance.class.respond_to?(:debugging) && instance.class.debugging - parse_argument_error(instance, e, caller) + handle_argument_error?(instance, e, caller) ? + instance.class.handle_argument_error(self, e) : (raise e) rescue NoMethodError => e - raise e if instance.class.respond_to?(:debugging) && instance.class.debugging - parse_no_method_error(instance, e) + handle_no_method_error?(instance, e, caller) ? + instance.class.handle_no_task_error(name) : (raise e) end # Returns the formatted usage by injecting given required arguments @@ -68,6 +69,10 @@ class Thor protected + def not_debugging?(instance) + !(instance.class.respond_to?(:debugging) && instance.class.debugging) + end + def required_options @required_options ||= options.map{ |_, o| o.usage if o.required? }.compact.sort.join(" ") end @@ -83,28 +88,14 @@ class Thor 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)}'" - end - else - raise e - end + def handle_argument_error?(instance, error, caller) + not_debugging?(instance) && error.message =~ /wrong number of arguments/ && + sans_backtrace(error.backtrace, caller).empty? 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 + def handle_no_method_error?(instance, error, caller) + not_debugging?(instance) && + error.message =~ /^undefined method `#{name}' for #{Regexp.escape(instance.to_s)}$/ end end diff --git a/lib/bundler/vendor/thor/util.rb b/lib/bundler/vendor/thor/util.rb index c2aed89ccf..d2c6a150c8 100644 --- a/lib/bundler/vendor/thor/util.rb +++ b/lib/bundler/vendor/thor/util.rb @@ -23,10 +23,7 @@ class Thor # def self.find_by_namespace(namespace) namespace = "default#{namespace}" if namespace.empty? || namespace =~ /^:/ - - Thor::Base.subclasses.find do |klass| - klass.namespace == namespace - end + Thor::Base.subclasses.find { |klass| klass.namespace == namespace } end # Receives a constant and converts it to a Thor namespace. Since Thor tasks @@ -43,10 +40,9 @@ class Thor # ==== Returns # String:: If we receive Foo::Bar::Baz it returns "foo:bar:baz" # - def self.namespace_from_thor_class(constant, remove_default=true) + def self.namespace_from_thor_class(constant) constant = constant.to_s.gsub(/^Thor::Sandbox::/, "") constant = snake_case(constant).squeeze(":") - constant.gsub!(/^default/, '') if remove_default constant end @@ -132,13 +128,7 @@ class Thor # ==== Parameters # namespace<String> # - # ==== Errors - # Thor::Error:: raised if the namespace cannot be found. - # - # Thor::Error:: raised if the namespace evals to a class which does not - # inherit from Thor or Thor::Group. - # - def self.namespace_to_thor_class_and_task(namespace, raise_if_nil=true) + def self.find_class_and_task_by_namespace(namespace) if namespace.include?(?:) pieces = namespace.split(":") task = pieces.pop @@ -149,7 +139,14 @@ class Thor klass, task = Thor::Util.find_by_namespace(namespace), nil end - raise Error, "could not find Thor class or task '#{namespace}'" if raise_if_nil && klass.nil? + return klass, task + end + + # The same as namespace_to_thor_class_and_task!, but raises an error if a klass + # could not be found. + def self.find_class_and_task_by_namespace!(namespace) + klass, task = find_class_and_task_by_namespace(namespace) + raise Error, "Could not find namespace or task #{namespace.inspect}." unless klass return klass, task end diff --git a/lib/bundler/vendor/thor/version.rb b/lib/bundler/vendor/thor/version.rb index 8ffab9d42c..b95dbbce4b 100644 --- a/lib/bundler/vendor/thor/version.rb +++ b/lib/bundler/vendor/thor/version.rb @@ -1,3 +1,3 @@ class Thor - VERSION = "0.12.4".freeze + VERSION = "0.13.3".freeze end |