diff options
24 files changed, 592 insertions, 241 deletions
diff --git a/lib/bundler/cli.rb b/lib/bundler/cli.rb index c5f4fc7a..2131edf6 100644 --- a/lib/bundler/cli.rb +++ b/lib/bundler/cli.rb @@ -14,7 +14,7 @@ module Bundler Bundler.rubygems.ui = UI::RGProxy.new(Bundler.ui) end - check_unknown_options! + check_unknown_options!(:except => [:config, :exec]) default_task :install class_option "no-color", :type => :boolean, :banner => "Disable colorization in output" @@ -416,20 +416,18 @@ module Bundler bundle exec you can require and call the bundled gems as if they were installed into the systemwide Rubygems repository. D - def exec(*) - ARGV.shift # remove "exec" - + def exec(*args) Bundler.definition.validate_ruby! Bundler.load.setup_environment begin # Run - Kernel.exec(*ARGV) + Kernel.exec(*args) rescue Errno::EACCES - Bundler.ui.error "bundler: not executable: #{ARGV.first}" + Bundler.ui.error "bundler: not executable: #{args.first}" exit 126 rescue Errno::ENOENT - Bundler.ui.error "bundler: command not found: #{ARGV.first}" + Bundler.ui.error "bundler: command not found: #{args.first}" Bundler.ui.warn "Install missing gem executables with `bundle install`" exit 127 rescue ArgumentError @@ -450,14 +448,11 @@ module Bundler will show the current value, as well as any superceded values and where they were specified. D - def config(*) - values = ARGV.dup - values.shift # remove config - - peek = values.shift + def config(*args) + peek = args.shift if peek && peek =~ /^\-\-/ - name, scope = values.shift, $' + name, scope = args.shift, $' else name, scope = peek, "global" end @@ -482,7 +477,7 @@ module Bundler Bundler.settings.set_local(name, nil) Bundler.settings.set_global(name, nil) when "local", "global" - if values.empty? + if args.empty? Bundler.ui.confirm "Settings for `#{name}` in order of priority. The top value will be used" with_padding do Bundler.settings.pretty_values_for(name).each { |line| Bundler.ui.info line } @@ -512,7 +507,7 @@ module Bundler Bundler.ui.info "You are replacing the current local value of #{name}, which is currently #{local.inspect}" end - Bundler.settings.send("set_#{scope}", name, values.join(" ")) + Bundler.settings.send("set_#{scope}", name, args.join(" ")) else Bundler.ui.error "Invalid scope --#{scope} given. Please use --local or --global." exit 1 diff --git a/lib/bundler/vendor/thor.rb b/lib/bundler/vendor/thor.rb index 92b24342..225c085b 100644 --- a/lib/bundler/vendor/thor.rb +++ b/lib/bundler/vendor/thor.rb @@ -5,7 +5,7 @@ class Thor # Sets the default task when thor is executed without an explicit task to be called. # # ==== Parameters - # meth<Symbol>:: name of the defaut task + # meth<Symbol>:: name of the default task # def default_task(meth=nil) case meth @@ -28,7 +28,7 @@ class Thor def register(klass, subcommand_name, usage, description, options={}) if klass <= Thor::Group desc usage, description, options - define_method(subcommand_name) { invoke klass } + define_method(subcommand_name) { |*args| invoke(klass, args) } else desc usage, description, options subcommand subcommand_name, klass @@ -108,6 +108,8 @@ class Thor @method_options end + alias options method_options + # Adds an option to the set of method options. If :for is given as option, # it allows you to change the options from a previous defined task. # @@ -132,6 +134,7 @@ class Thor # :aliases - Aliases for this option. # :type - The type of the argument, can be :string, :hash, :array, :numeric or :boolean. # :banner - String to show on usage notes. + # :hide - If you want to hide this option from the help. # def method_option(name, options={}) scope = if options[:for] @@ -143,6 +146,8 @@ class Thor build_option(name, options, scope) end + alias option method_option + # Prints help information for the given task. # # ==== Parameters @@ -160,7 +165,7 @@ class Thor class_options_help(shell, nil => task.options.map { |_, o| o }) if task.long_description shell.say "Description:" - shell.print_wrapped(task.long_description, :ident => 2) + shell.print_wrapped(task.long_description, :indent => 2) else shell.say task.description end @@ -179,7 +184,7 @@ class Thor list.sort!{ |a,b| a[0] <=> b[0] } shell.say "Tasks:" - shell.print_table(list, :ident => 2, :truncate => true) + shell.print_table(list, :indent => 2, :truncate => true) shell.say class_options_help(shell) end @@ -202,7 +207,11 @@ class Thor def subcommand(subcommand, subcommand_class) self.subcommands << subcommand.to_s subcommand_class.subcommand_help subcommand - define_method(subcommand) { |*args| invoke subcommand_class, args } + + define_method(subcommand) do |*args| + args, opts = Thor::Arguments.split(args) + invoke subcommand_class, args, opts + end end # Extend check unknown options to accept a hash of conditions. @@ -259,8 +268,11 @@ class Thor opts = given_opts || opts || [] config.merge!(:current_task => task, :task_options => task.options) + instance = new(args, opts, config) + yield instance if block_given? + args = instance.args trailing = args[Range.new(arguments.size, -1)] - new(args, opts, config).invoke_task(task, trailing || []) + instance.invoke_task(task, trailing || []) end # The banner for this class. You can customize it if you are invoking the @@ -300,7 +312,6 @@ class Thor # Retrieve the task name from given args. def retrieve_task_name(args) #:nodoc: meth = args.first.to_s unless args.empty? - if meth && (map[meth] || meth !~ /^\-/) args.shift else @@ -308,35 +319,45 @@ class Thor end end - # Receives a task name (can be nil), and try to get a map from it. - # If a map can't be found use the sent name or the default task. + # receives a (possibly nil) task name and returns a name that is in + # the tasks hash. In addition to normalizing aliases, this logic + # will determine if a shortened command is an unambiguous prefix of + # a task or alias. + # + # +normalize_task_name+ also converts names like +animal-prison+ + # into +animal_prison+. def normalize_task_name(meth) #:nodoc: - meth = map[meth.to_s] || find_subcommand_and_update_argv(meth) || meth || default_task - meth.to_s.gsub('-','_') # treat foo-bar > foo_bar - end - - # terrible hack that overwrites ARGV - def find_subcommand_and_update_argv(subcmd_name) #:nodoc: - return unless subcmd_name - cmd = find_subcommand(subcmd_name) - ARGV[0] = cmd if cmd - cmd - end + return default_task.to_s.gsub('-', '_') unless meth - def find_subcommand(subcmd_name) - possibilities = find_subcommand_possibilities subcmd_name + possibilities = find_task_possibilities(meth) if possibilities.size > 1 - raise "Ambiguous subcommand #{subcmd_name} matches [#{possibilities.join(', ')}]" + raise ArgumentError, "Ambiguous task #{meth} matches [#{possibilities.join(', ')}]" elsif possibilities.size < 1 - return nil + meth = meth || default_task + elsif map[meth] + meth = map[meth] + else + meth = possibilities.first end - possibilities.first + meth.to_s.gsub('-','_') # treat foo-bar as foo_bar end - def find_subcommand_possibilities(subcmd_name) - len = subcmd_name.length - all_tasks.map {|t| t.first}.select { |n| subcmd_name == n[0, len] } + # this is the logic that takes the task name passed in by the user + # and determines whether it is an unambiguous prefix of a task or + # alias name. + def find_task_possibilities(meth) + len = meth.to_s.length + possibilities = all_tasks.merge(map).keys.select { |n| meth == n[0, len] }.sort + unique_possibilities = possibilities.map { |k| map[k] || k }.uniq + + if possibilities.include?(meth) + [meth] + elsif unique_possibilities.size == 1 + unique_possibilities + else + possibilities + end end def subcommand_help(cmd) diff --git a/lib/bundler/vendor/thor/actions.rb b/lib/bundler/vendor/thor/actions.rb index 3712c5f4..f9002f59 100644 --- a/lib/bundler/vendor/thor/actions.rb +++ b/lib/bundler/vendor/thor/actions.rb @@ -55,7 +55,7 @@ class Thor :desc => "Run but do not make any changes" class_option :quiet, :type => :boolean, :aliases => "-q", :group => :runtime, - :desc => "Supress status output" + :desc => "Suppress status output" class_option :skip, :type => :boolean, :aliases => "-s", :group => :runtime, :desc => "Skip files that already exist" @@ -114,8 +114,12 @@ class Thor # the script started). # def relative_to_original_destination_root(path, remove_dot=true) - path = path.gsub(@destination_stack[0], '.') - remove_dot ? (path[2..-1] || '') : path + if path =~ /^#{@destination_stack[0]}/ + path = path.gsub(@destination_stack[0], '.') + path = remove_dot ? (path[2..-1] || '') : path + end + + path end # Holds source paths in instance so they can be manipulated. diff --git a/lib/bundler/vendor/thor/actions/create_link.rb b/lib/bundler/vendor/thor/actions/create_link.rb index 1975644a..864a1e99 100644 --- a/lib/bundler/vendor/thor/actions/create_link.rb +++ b/lib/bundler/vendor/thor/actions/create_link.rb @@ -41,7 +41,7 @@ class Thor invoke_with_conflict_check do FileUtils.mkdir_p(File.dirname(destination)) # Create a symlink by default - config[:symbolic] ||= true + config[:symbolic] = true if config[:symbolic].nil? File.unlink(destination) if exists? if config[:symbolic] File.symlink(render, destination) diff --git a/lib/bundler/vendor/thor/actions/directory.rb b/lib/bundler/vendor/thor/actions/directory.rb index dc238939..f6283472 100644 --- a/lib/bundler/vendor/thor/actions/directory.rb +++ b/lib/bundler/vendor/thor/actions/directory.rb @@ -2,13 +2,13 @@ require 'thor/actions/empty_directory' class Thor module Actions - # Copies recursively the files from source directory to root directory. # If any of the files finishes with .tt, it's considered to be a template # and is placed in the destination without the extension .tt. If any # empty directory is found, it's copied and all .empty_directory files are - # ignored. Remember that file paths can also be encoded, let's suppose a doc - # directory with the following files: + # ignored. If any file name is wrapped within % signs, the text within + # the % signs will be executed as a method and replaced with the returned + # value. Let's suppose a doc directory with the following files: # # doc/ # components/.empty_directory @@ -29,6 +29,10 @@ class Thor # rdoc.rb # blog.rb # + # <b>Encoded path note:</b> Since Thor internals use Object#respond_to? to check if it can + # expand %something%, this `something` should be a public method in the class calling + # #directory. If a method is private, Thor stack raises PrivateMethodEncodedError. + # # ==== Parameters # source<String>:: the relative path to the source root. # destination<String>:: the relative path to the destination root. @@ -67,7 +71,8 @@ class Thor protected def execute! - lookup = config[:recursive] ? File.join(source, '**') : source + lookup = Util.escape_globs(source) + lookup = config[:recursive] ? File.join(lookup, '**') : lookup lookup = File.join(lookup, '{*,.[a-z]*}') Dir[lookup].sort.each do |file_source| diff --git a/lib/bundler/vendor/thor/actions/empty_directory.rb b/lib/bundler/vendor/thor/actions/empty_directory.rb index 484cb820..93d3e2a8 100644 --- a/lib/bundler/vendor/thor/actions/empty_directory.rb +++ b/lib/bundler/vendor/thor/actions/empty_directory.rb @@ -90,16 +90,35 @@ class Thor # Filenames in the encoded form are converted. If you have a file: # - # %class_name%.rb + # %file_name%.rb # - # It gets the class name from the base and replace it: + # It calls #file_name from the base and replaces %-string with the + # return value (should be String) of #file_name: # # user.rb # + # The method referenced by %-string SHOULD be public. Otherwise you + # get the exception with the corresponding error message. + # def convert_encoded_instructions(filename) - filename.gsub(/%(.*?)%/) do |string| - instruction = $1.strip - base.respond_to?(instruction) ? base.send(instruction) : string + filename.gsub(/%(.*?)%/) do |initial_string| + call_public_method($1.strip) or initial_string + end + end + + # Calls `base`'s public method `sym`. + # Returns:: result of `base.sym` or `nil` if `sym` wasn't found in + # `base` + # Raises:: Thor::PrivateMethodEncodedError if `sym` references + # a private method. + def call_public_method(sym) + if base.respond_to?(sym) + base.send(sym) + elsif base.respond_to?(sym, true) + raise Thor::PrivateMethodEncodedError, + "Method #{base.class}##{sym} should be public, not private" + else + nil end end diff --git a/lib/bundler/vendor/thor/actions/file_manipulation.rb b/lib/bundler/vendor/thor/actions/file_manipulation.rb index ad049b3c..908cdb01 100644 --- a/lib/bundler/vendor/thor/actions/file_manipulation.rb +++ b/lib/bundler/vendor/thor/actions/file_manipulation.rb @@ -187,7 +187,7 @@ class Thor # # ==== Examples # - # inject_into_class "app/controllers/application_controller.rb", " filter_parameter :password\n" + # inject_into_class "app/controllers/application_controller.rb", ApplicationController, " filter_parameter :password\n" # # inject_into_class "app/controllers/application_controller.rb", ApplicationController do # " filter_parameter :password\n" @@ -229,6 +229,44 @@ class Thor end end + # Uncomment all lines matching a given regex. It will leave the space + # which existed before the comment hash in tact but will remove any spacing + # between the comment hash and the beginning of the line. + # + # ==== Parameters + # path<String>:: path of the file to be changed + # flag<Regexp|String>:: the regexp or string used to decide which lines to uncomment + # config<Hash>:: give :verbose => false to not log the status. + # + # ==== Example + # + # uncomment_lines 'config/initializers/session_store.rb', /active_record/ + # + def uncomment_lines(path, flag, *args) + flag = flag.respond_to?(:source) ? flag.source : flag + + gsub_file(path, /^(\s*)#\s*(.*#{flag})/, '\1\2', *args) + end + + # Comment all lines matching a given regex. It will leave the space + # which existed before the beginning of the line in tact and will insert + # a single space after the comment hash. + # + # ==== Parameters + # path<String>:: path of the file to be changed + # flag<Regexp|String>:: the regexp or string used to decide which lines to comment + # config<Hash>:: give :verbose => false to not log the status. + # + # ==== Example + # + # comment_lines 'config/initializers/session_store.rb', /cookie_store/ + # + def comment_lines(path, flag, *args) + flag = flag.respond_to?(:source) ? flag.source : flag + + gsub_file(path, /^(\s*)([^#|\n]*#{flag})/, '\1# \2', *args) + end + # Removes a file at the given location. # # ==== Parameters diff --git a/lib/bundler/vendor/thor/base.rb b/lib/bundler/vendor/thor/base.rb index 65399ffb..a193d2de 100644 --- a/lib/bundler/vendor/thor/base.rb +++ b/lib/bundler/vendor/thor/base.rb @@ -19,7 +19,7 @@ class Thor action add_file create_file in_root inside run run_ruby_script) module Base - attr_accessor :options + attr_accessor :options, :parent_options, :args # It receives arguments in an Array and two hashes, one for options and # other for configuration. @@ -38,22 +38,43 @@ class Thor # config<Hash>:: Configuration for this Thor class. # def initialize(args=[], options={}, config={}) - args = Thor::Arguments.parse(self.class.arguments, args) - args.each { |key, value| send("#{key}=", value) } - parse_options = self.class.class_options + # The start method splits inbound arguments at the first argument + # that looks like an option (starts with - or --). It then calls + # new, passing in the two halves of the arguments Array as the + # first two parameters. + if options.is_a?(Array) task_options = config.delete(:task_options) # hook for start parse_options = parse_options.merge(task_options) if task_options array_options, hash_options = options, {} else + # Handle the case where the class was explicitly instantiated + # with pre-parsed options. array_options, hash_options = [], options end + # Let Thor::Options parse the options first, so it can remove + # declared options from the array. This will leave us with + # a list of arguments that weren't declared. opts = Thor::Options.new(parse_options, hash_options) self.options = opts.parse(array_options) + + # If unknown options are disallowed, make sure that none of the + # remaining arguments looks like an option. opts.check_unknown! if self.class.check_unknown_options?(config) + + # Add the remaining arguments from the options parser to the + # arguments passed in to initialize. Then remove any positional + # arguments declared using #argument (this is primarily used + # by Thor::Group). Tis will leave us with the remaining + # positional arguments. + thor_args = Thor::Arguments.new(self.class.arguments) + thor_args.parse(args + opts.remaining).each { |k,v| send("#{k}=", v) } + args = thor_args.remaining + + @args = args end class << self @@ -210,13 +231,14 @@ class Thor # options<Hash>:: Described below. # # ==== Options - # :desc - Description for the argument. - # :required - If the argument is required or not. - # :default - Default value for this argument. - # :group - The group for this options. Use by class options to output options in different levels. - # :aliases - Aliases for this option. - # :type - The type of the argument, can be :string, :hash, :array, :numeric or :boolean. - # :banner - String to show on usage notes. + # :desc:: -- Description for the argument. + # :required:: -- If the argument is required or not. + # :default:: -- Default value for this argument. + # :group:: -- The group for this options. Use by class options to output options in different levels. + # :aliases:: -- Aliases for this option. <b>Note:</b> Thor follows a convention of one-dash-one-letter options. Thus aliases like "-something" wouldn't be parsed; use either "\--something" or "-s" instead. + # :type:: -- The type of the argument, can be :string, :hash, :array, :numeric or :boolean. + # :banner:: -- String to show on usage notes. + # :hide:: -- If you want to hide this option from the help. # def class_option(name, options={}) build_option(name, options, class_options) @@ -225,7 +247,7 @@ class Thor # Removes a previous defined argument. If :undefine is given, undefine # accessors as well. # - # ==== Paremeters + # ==== Parameters # names<Array>:: Arguments to be removed # # ==== Examples @@ -244,7 +266,7 @@ class Thor # Removes a previous defined class option. # - # ==== Paremeters + # ==== Parameters # names<Array>:: Class options to be removed # # ==== Examples @@ -387,11 +409,17 @@ class Thor rescue Thor::Error => e ENV["THOR_DEBUG"] == "1" ? (raise e) : config[:shell].error(e.message) exit(1) if exit_on_failure? + rescue Errno::EPIPE + # This happens if a thor task is piped to something like `head`, + # which closes the pipe when it's done reading. This will also + # mean that if the pipe is closed, further unnecessary + # computation will not occur. + exit(0) end # Allows to use private methods from parent in child classes as tasks. # - # ==== Paremeters + # ==== Parameters # names<Array>:: Method names to be used as tasks # # ==== Examples @@ -405,16 +433,26 @@ class Thor end end - def handle_no_task_error(task) #:nodoc: - if $thor_runner + def handle_no_task_error(task, has_namespace = $thor_runner) #:nodoc: + if has_namespace raise UndefinedTaskError, "Could not find task #{task.inspect} in #{namespace.inspect} namespace." else raise UndefinedTaskError, "Could not find task #{task.inspect}." end end - def handle_argument_error(task, error) #:nodoc: - raise InvocationError, "#{task.name.inspect} was called incorrectly. Call as #{self.banner(task).inspect}." + def handle_argument_error(task, error, arity=nil) #:nodoc: + msg = "#{basename} #{task.name}" + if arity + required = arity < 0 ? (-1 - arity) : arity + msg << " requires at least #{required} argument" + msg << "s" if required > 1 + else + msg = "call #{msg} as" + end + + msg << ": #{self.banner(task).inspect}." + raise InvocationError, msg end protected @@ -447,15 +485,17 @@ class Thor padding = options.collect{ |o| o.aliases.size }.max.to_i * 4 options.each do |option| - item = [ option.usage(padding) ] - item.push(option.description ? "# #{option.description}" : "") + unless option.hide + item = [ option.usage(padding) ] + item.push(option.description ? "# #{option.description}" : "") - list << item - list << [ "", "# Default: #{option.default}" ] if option.show_default? + list << item + list << [ "", "# Default: #{option.default}" ] if option.show_default? + end end shell.say(group_name ? "#{group_name} options:" : "Options:") - shell.print_table(list, :ident => 2) + shell.print_table(list, :indent => 2) shell.say "" end @@ -473,7 +513,7 @@ class Thor def build_option(name, options, scope) #:nodoc: scope[name] = Thor::Option.new(name, options[:desc], options[:required], options[:type], options[:default], options[:banner], - options[:lazy_default], options[:group], options[:aliases]) + options[:lazy_default], options[:group], options[:aliases], options[:hide]) end # Receives a hash of options, parse them and add to the scope. This is a @@ -506,6 +546,7 @@ class Thor # and file into baseclass. def inherited(klass) Thor::Base.register_klass_file(klass) + klass.instance_variable_set(:@no_tasks, false) end # Fire this callback whenever a method is added. Added methods are diff --git a/lib/bundler/vendor/thor/core_ext/dir_escape.rb b/lib/bundler/vendor/thor/core_ext/dir_escape.rb new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/lib/bundler/vendor/thor/core_ext/dir_escape.rb diff --git a/lib/bundler/vendor/thor/error.rb b/lib/bundler/vendor/thor/error.rb index 9746b882..532db462 100644 --- a/lib/bundler/vendor/thor/error.rb +++ b/lib/bundler/vendor/thor/error.rb @@ -1,6 +1,6 @@ class Thor # Thor::Error is raised when it's caused by wrong usage of thor classes. Those - # errors have their backtrace supressed and are nicely shown to the user. + # errors have their backtrace suppressed and are nicely shown to the user. # # Errors that are caused by the developer, like declaring a method which # overwrites a thor keyword, it SHOULD NOT raise a Thor::Error. This way, we @@ -27,4 +27,9 @@ class Thor class MalformattedArgumentError < InvocationError end + + # Raised when a user tries to call a private method encoded in templated filename. + # + class PrivateMethodEncodedError < Error + end end diff --git a/lib/bundler/vendor/thor/group.rb b/lib/bundler/vendor/thor/group.rb index 3dbab98a..874ac47a 100644 --- a/lib/bundler/vendor/thor/group.rb +++ b/lib/bundler/vendor/thor/group.rb @@ -104,7 +104,7 @@ class Thor::Group # # ==== Custom invocations # - # You can also supply a block to customize how the option is giong to be + # You can also supply a block to customize how the option is going to be # invoked. The block receives two parameters, an instance of the current # class and the klass to be invoked. # @@ -180,16 +180,16 @@ class Thor::Group end next unless value - klass, task = prepare_for_invocation(name, value) + klass, _ = prepare_for_invocation(name, value) next unless klass && klass.respond_to?(:class_options) value = value.to_s human_name = value.respond_to?(:classify) ? value.classify : value group_options[human_name] ||= [] - group_options[human_name] += klass.class_options.values.select do |option| - base_options[option.name.to_sym].nil? && option.group.nil? && - !group_options.values.flatten.any? { |i| i.name == option.name } + group_options[human_name] += klass.class_options.values.select do |class_option| + base_options[class_option.name.to_sym].nil? && class_option.group.nil? && + !group_options.values.flatten.any? { |i| i.name == class_option.name } end yield klass if block_given? @@ -204,8 +204,16 @@ class Thor::Group [item] end - def handle_argument_error(task, error) #:nodoc: - raise error, "#{task.name.inspect} was called incorrectly. Are you sure it has arity equals to 0?" + def handle_argument_error(task, error, arity=nil) #:nodoc: + if arity > 0 + msg = "#{basename} #{task.name} takes #{arity} argument" + msg << "s" if arity > 1 + msg << ", but it should not." + else + msg = "You should not pass arguments to #{basename} #{task.name}." + end + + raise error, msg end protected @@ -220,10 +228,14 @@ class Thor::Group args, opts = Thor::Options.split(given_args) opts = given_opts || opts + instance = new(args, opts, config) + yield instance if block_given? + args = instance.args + if task - new(args, opts, config).invoke_task(all_tasks[task]) + instance.invoke_task(all_tasks[task]) else - new(args, opts, config).invoke_all + instance.invoke_all end end diff --git a/lib/bundler/vendor/thor/invocation.rb b/lib/bundler/vendor/thor/invocation.rb index 6315dd42..71db7c81 100644 --- a/lib/bundler/vendor/thor/invocation.rb +++ b/lib/bundler/vendor/thor/invocation.rb @@ -85,7 +85,7 @@ class Thor # that it's going to use. # # If you want Rspec::RR to be initialized with its own set of options, you - # have to do that explicitely: + # have to do that explicitly: # # invoke "rspec:rr", [], :style => :foo # @@ -106,7 +106,9 @@ class Thor raise "Expected Thor class, got #{klass}" unless klass <= Thor::Base args, opts, config = _parse_initialization_options(args, opts, config) - klass.send(:dispatch, task, args, opts, config) + klass.send(:dispatch, task, args, opts, config) do |instance| + instance.parent_options = options + end end # Invoke the given task if the given args. diff --git a/lib/bundler/vendor/thor/parser/arguments.rb b/lib/bundler/vendor/thor/parser/arguments.rb index 888ef692..12db2b23 100644 --- a/lib/bundler/vendor/thor/parser/arguments.rb +++ b/lib/bundler/vendor/thor/parser/arguments.rb @@ -49,6 +49,10 @@ class Thor @assigns end + def remaining + @pile + end + private def no_or_skip?(arg) diff --git a/lib/bundler/vendor/thor/parser/option.rb b/lib/bundler/vendor/thor/parser/option.rb index c8f20b13..26da9d6b 100644 --- a/lib/bundler/vendor/thor/parser/option.rb +++ b/lib/bundler/vendor/thor/parser/option.rb @@ -1,14 +1,15 @@ class Thor class Option < Argument #:nodoc: - attr_reader :aliases, :group, :lazy_default + attr_reader :aliases, :group, :lazy_default, :hide VALID_TYPES = [:boolean, :numeric, :hash, :array, :string] - def initialize(name, description=nil, required=nil, type=nil, default=nil, banner=nil, lazy_default=nil, group=nil, aliases=nil) + def initialize(name, description=nil, required=nil, type=nil, default=nil, banner=nil, lazy_default=nil, group=nil, aliases=nil, hide=nil) super(name, description, required, type, default, banner) @lazy_default = lazy_default @group = group.to_s.capitalize if group @aliases = [*aliases].compact + @hide = hide end # This parse quick options given as method_options. It makes several diff --git a/lib/bundler/vendor/thor/parser/options.rb b/lib/bundler/vendor/thor/parser/options.rb index 4a241a47..81b671df 100644 --- a/lib/bundler/vendor/thor/parser/options.rb +++ b/lib/bundler/vendor/thor/parser/options.rb @@ -35,7 +35,7 @@ class Thor @non_assigned_required.delete(hash_options[key]) end - @shorts, @switches, @unknown = {}, {}, [] + @shorts, @switches, @extra = {}, {}, [] options.each do |option| @switches[option.switch_name] = option @@ -46,14 +46,19 @@ class Thor end end + def remaining + @extra + end + def parse(args) @pile = args.dup while peek match, is_switch = current_is_switch? + shifted = shift if is_switch - case shift + case shifted when SHORT_SQ_RE unshift($1.split('').map { |f| "-#{f}" }) next @@ -68,9 +73,10 @@ class Thor option = switch_option(switch) @assigns[option.human_name] = parse_peek(switch, option) elsif match - @unknown << shift + @extra << shifted + @extra << shift while peek && peek !~ /^-/ else - shift + @extra << shifted end end @@ -82,9 +88,9 @@ class Thor end def check_unknown! - unless ARGV.include?("exec") || ARGV.include?("config") - raise UnknownArgumentError, "Unknown switches '#{@unknown.join(', ')}'" unless @unknown.empty? - end + # an unknown option starts with - or -- and has no more --'s afterward. + unknown = @extra.select { |str| str =~ /^--?(?:(?!--).)*$/ } + raise UnknownArgumentError, "Unknown switches '#{unknown.join(', ')}'" unless unknown.empty? end protected diff --git a/lib/bundler/vendor/thor/rake_compat.rb b/lib/bundler/vendor/thor/rake_compat.rb index 0d0757fd..c86e8405 100644 --- a/lib/bundler/vendor/thor/rake_compat.rb +++ b/lib/bundler/vendor/thor/rake_compat.rb @@ -1,4 +1,5 @@ require 'rake' +require 'rake/dsl_definition' class Thor # Adds a compatibility layer to your Thor classes which allows you to use @@ -16,6 +17,8 @@ class Thor # end # module RakeCompat + include Rake::DSL if defined?(Rake::DSL) + def self.rake_classes @rake_classes ||= [] end @@ -29,12 +32,12 @@ class Thor end end -class Object #:nodoc: - alias :rake_task :task - alias :rake_namespace :namespace +# override task on (main), for compatibility with Rake 0.9 +self.instance_eval do + alias rake_namespace namespace - def task(*args, &block) - task = rake_task(*args, &block) + def task(*) + task = super if klass = Thor::RakeCompat.rake_classes.last non_namespaced_name = task.name.split(':').last @@ -43,7 +46,8 @@ class Object #:nodoc: description << task.arg_names.map{ |n| n.to_s.upcase }.join(' ') description.strip! - klass.desc description, task.comment || non_namespaced_name + klass.desc description, Rake.application.last_description || non_namespaced_name + Rake.application.last_description = nil klass.send :define_method, non_namespaced_name do |*args| Rake::Task[task.name.to_sym].invoke(*args) end @@ -52,7 +56,7 @@ class Object #:nodoc: task end - def namespace(name, &block) + def namespace(name) if klass = Thor::RakeCompat.rake_classes.last const_name = Thor::Util.camel_case(name.to_s).to_sym klass.const_set(const_name, Class.new(Thor)) @@ -60,7 +64,8 @@ class Object #:nodoc: Thor::RakeCompat.rake_classes << new_klass end - rake_namespace(name, &block) + super Thor::RakeCompat.rake_classes.pop end end + diff --git a/lib/bundler/vendor/thor/runner.rb b/lib/bundler/vendor/thor/runner.rb index 0d9e3c05..d69fba11 100644 --- a/lib/bundler/vendor/thor/runner.rb +++ b/lib/bundler/vendor/thor/runner.rb @@ -17,6 +17,7 @@ class Thor::Runner < Thor #:nodoc: if meth && !self.respond_to?(meth) initialize_thorfiles(meth) klass, task = Thor::Util.find_class_and_task_by_namespace(meth) + self.class.handle_no_task_error(task, false) if klass.nil? klass.start(["-h", task].compact, :shell => self.shell) else super @@ -30,6 +31,7 @@ class Thor::Runner < Thor #:nodoc: meth = meth.to_s initialize_thorfiles(meth) klass, task = Thor::Util.find_class_and_task_by_namespace(meth) + self.class.handle_no_task_error(task, false) if klass.nil? args.unshift(task) if task klass.start(args, :shell => self.shell) end @@ -124,7 +126,17 @@ class Thor::Runner < Thor #:nodoc: old_filename = thor_yaml[name][:filename] self.options = self.options.merge("as" => name) - filename = install(thor_yaml[name][:location]) + + if File.directory? File.expand_path(name) + FileUtils.rm_rf(File.join(thor_root, old_filename)) + + thor_yaml.delete(old_filename) + save_yaml(thor_yaml) + + filename = install(name) + else + filename = install(thor_yaml[name][:location]) + end unless filename == old_filename File.delete(File.join(thor_root, old_filename)) @@ -190,7 +202,7 @@ class Thor::Runner < Thor #:nodoc: true end - # Load the thorfiles. If relevant_to is supplied, looks for specific files + # Load the Thorfiles. If relevant_to is supplied, looks for specific files # in the thor_root instead of loading them all. # # By default, it also traverses the current path until find Thor files, as @@ -244,7 +256,7 @@ class Thor::Runner < Thor #:nodoc: end end - # Load thorfiles relevant to the given method. If you provide "foo:bar" it + # Load Thorfiles relevant to the given method. If you provide "foo:bar" it # will load all thor files in the thor.yaml that has "foo" e "foo:bar" # namespaces registered. # diff --git a/lib/bundler/vendor/thor/shell.rb b/lib/bundler/vendor/thor/shell.rb index b52c9da2..a718c537 100644 --- a/lib/bundler/vendor/thor/shell.rb +++ b/lib/bundler/vendor/thor/shell.rb @@ -8,7 +8,7 @@ class Thor def self.shell @shell ||= if ENV['THOR_SHELL'] && ENV['THOR_SHELL'].size > 0 Thor::Shell.const_get(ENV['THOR_SHELL']) - elsif RbConfig::CONFIG['host_os'] =~ /mswin|mingw/ + elsif ((RbConfig::CONFIG['host_os'] =~ /mswin|mingw/) && !(ENV['ANSICON'])) Thor::Shell::Basic else Thor::Shell::Color @@ -23,7 +23,7 @@ class Thor end module Shell - SHELL_DELEGATED_METHODS = [:ask, :yes?, :no?, :say, :say_status, :print_table] + SHELL_DELEGATED_METHODS = [:ask, :error, :set_color, :yes?, :no?, :say, :say_status, :print_in_columns, :print_table, :print_wrapped, :file_collision, :terminal_width] autoload :Basic, 'thor/shell/basic' autoload :Color, 'thor/shell/color' @@ -62,8 +62,8 @@ class Thor # Common methods that are delegated to the shell. SHELL_DELEGATED_METHODS.each do |method| module_eval <<-METHOD, __FILE__, __LINE__ - def #{method}(*args) - shell.#{method}(*args) + def #{method}(*args,&block) + shell.#{method}(*args,&block) end METHOD end diff --git a/lib/bundler/vendor/thor/shell/basic.rb b/lib/bundler/vendor/thor/shell/basic.rb index c8411d3d..3c5904b2 100644 --- a/lib/bundler/vendor/thor/shell/basic.rb +++ b/lib/bundler/vendor/thor/shell/basic.rb @@ -3,12 +3,13 @@ require 'tempfile' class Thor module Shell class Basic - attr_accessor :base, :padding + attr_accessor :base + attr_reader :padding - # Initialize base and padding to nil. + # Initialize base, mute and padding to nil. # def initialize #:nodoc: - @base, @padding = nil, 0 + @base, @mute, @padding = nil, false, 0 end # Mute everything that's inside given block @@ -32,14 +33,22 @@ class Thor @padding = [0, value].max end - # Ask something to the user and receives a response. + # Asks something to the user and receives a response. + # + # If asked to limit the correct responses, you can pass in an + # array of acceptable answers. If one of those is not supplied, + # they will be shown a message stating that one of those answers + # must be given and re-asked the question. # # ==== Example # ask("What is your name?") # - def ask(statement, color=nil) - say("#{statement} ", color) - stdin.gets.strip + # ask("What is your favorite Neopolitan flavor?", :limited_to => ["strawberry", "chocolate", "vanilla"]) + # + def ask(statement, *args) + options = args.last.is_a?(Hash) ? args.pop : {} + + options[:limited_to] ? ask_filtered(statement, options[:limited_to], *args) : ask_simply(statement, *args) end # Say (print) something to the user. If the sentence ends with a whitespace @@ -51,7 +60,8 @@ class Thor # def say(message="", color=nil, force_new_line=(message.to_s !~ /( |\t)$/)) message = message.to_s - message = set_color(message, color) if color + + message = set_color(message, *color) if color spaces = " " * padding @@ -94,37 +104,77 @@ class Thor !yes?(statement, color) end + # Prints values in columns + # + # ==== Parameters + # Array[String, String, ...] + # + def print_in_columns(array) + return if array.empty? + colwidth = (array.map{|el| el.to_s.size}.max || 0) + 2 + array.each_with_index do |value, index| + # Don't output trailing spaces when printing the last column + if ((((index + 1) % (terminal_width / colwidth))).zero? && !index.zero?) || index + 1 == array.length + stdout.puts value + else + stdout.printf("%-#{colwidth}s", value) + end + end + end + # Prints a table. # # ==== Parameters # Array[Array[String, String, ...]] # # ==== Options - # ident<Integer>:: Indent the first column by ident value. + # indent<Integer>:: Indent the first column by indent value. # colwidth<Integer>:: Force the first column to colwidth spaces wide. # - def print_table(table, options={}) - return if table.empty? + def print_table(array, options={}) + return if array.empty? - formats, ident, colwidth = [], options[:ident].to_i, options[:colwidth] + formats, indent, colwidth = [], options[:indent].to_i, options[:colwidth] options[:truncate] = terminal_width if options[:truncate] == true formats << "%-#{colwidth + 2}s" if colwidth start = colwidth ? 1 : 0 - start.upto(table.first.length - 2) do |i| - maxima ||= table.max{|a,b| a[i].size <=> b[i].size }[i].size - formats << "%-#{maxima + 2}s" + colcount = array.max{|a,b| a.size <=> b.size }.size + + maximas = [] + + start.upto(colcount - 1) do |index| + maxima = array.map {|row| row[index] ? row[index].to_s.size : 0 }.max + maximas << maxima + if index == colcount - 1 + # Don't output 2 trailing spaces when printing the last column + formats << "%-s" + else + formats << "%-#{maxima + 2}s" + end end - formats[0] = formats[0].insert(0, " " * ident) + formats[0] = formats[0].insert(0, " " * indent) formats << "%s" - table.each do |row| + array.each do |row| sentence = "" - row.each_with_index do |column, i| - sentence << formats[i] % column.to_s + row.each_with_index do |column, index| + maxima = maximas[index] + + if column.is_a?(Numeric) + if index == row.size - 1 + # Don't output 2 trailing spaces when printing the last column + f = "%#{maxima}s" + else + f = "%#{maxima}s " + end + else + f = formats[index] + end + sentence << f % column.to_s end sentence = truncate(sentence, options[:truncate]) if options[:truncate] @@ -139,11 +189,11 @@ class Thor # String # # ==== Options - # ident<Integer>:: Indent each line of the printed paragraph by ident value. + # indent<Integer>:: Indent each line of the printed paragraph by indent value. # def print_wrapped(message, options={}) - ident = options[:ident] || 0 - width = terminal_width - ident + indent = options[:indent] || 0 + width = terminal_width - indent paras = message.split("\n\n") paras.map! do |unwrapped| @@ -154,14 +204,14 @@ class Thor paras.each do |para| para.split("\n").each do |line| - stdout.puts line.insert(0, " " * ident) + stdout.puts line.insert(0, " " * indent) end stdout.puts unless para == paras.last end end # Deals with file collision and returns true if the file should be - # overwriten and false otherwise. If a block is given, it uses the block + # overwritten and false otherwise. If a block is given, it uses the block # response as the content for the diff. # # ==== Parameters @@ -194,6 +244,19 @@ class Thor end end + # This code was copied from Rake, available under MIT-LICENSE + # Copyright (c) 2003, 2004 Jim Weirich + def terminal_width + if ENV['THOR_COLUMNS'] + result = ENV['THOR_COLUMNS'].to_i + else + result = unix? ? dynamic_width : 80 + end + (result < 10) ? 80 : result + rescue + 80 + end + # Called if something goes wrong during the execution. This is used by Thor # internally and should not be used inside your scripts. If something went # wrong, you can always raise an exception. If you raise a Thor::Error, it @@ -206,35 +269,40 @@ class Thor # Apply color to the given string with optional bold. Disabled in the # Thor::Shell::Basic class. # - def set_color(string, color, bold=false) #:nodoc: + def set_color(string, *args) #:nodoc: string end - protected + protected - def stdout - $stdout - end + def lookup_color(color) + return color unless color.is_a?(Symbol) + self.class.const_get(color.to_s.upcase) + end - def stdin - $stdin - end + def stdout + $stdout + end - def stderr - $stderr - end + def stdin + $stdin + end + + def stderr + $stderr + end - def is?(value) #:nodoc: - value = value.to_s + def is?(value) #:nodoc: + value = value.to_s - if value.size == 1 - /\A#{value}\z/i - else - /\A(#{value}|#{value[0,1]})\z/i - end + if value.size == 1 + /\A#{value}\z/i + else + /\A(#{value}|#{value[0,1]})\z/i end + end - def file_collision_help #:nodoc: + def file_collision_help #:nodoc: <<HELP Y - yes, overwrite n - no, do not overwrite @@ -243,59 +311,78 @@ q - quit, abort d - diff, show the differences between the old and the new h - help, show this help HELP - end + end - def show_diff(destination, content) #:nodoc: - diff_cmd = ENV['THOR_DIFF'] || ENV['RAILS_DIFF'] || 'diff -u' + def show_diff(destination, content) #:nodoc: + diff_cmd = ENV['THOR_DIFF'] || ENV['RAILS_DIFF'] || 'diff -u' - Tempfile.open(File.basename(destination), File.dirname(destination)) do |temp| - temp.write content - temp.rewind - system %(#{diff_cmd} "#{destination}" "#{temp.path}") - end + Tempfile.open(File.basename(destination), File.dirname(destination)) do |temp| + temp.write content + temp.rewind + system %(#{diff_cmd} "#{destination}" "#{temp.path}") end + end - def quiet? #:nodoc: - mute? || (base && base.options[:quiet]) - end + def quiet? #:nodoc: + mute? || (base && base.options[:quiet]) + end + + # Calculate the dynamic width of the terminal + def dynamic_width + @dynamic_width ||= (dynamic_width_stty.nonzero? || dynamic_width_tput) + end + + def dynamic_width_stty + %x{stty size 2>/dev/null}.split[1].to_i + end - # This code was copied from Rake, available under MIT-LICENSE - # Copyright (c) 2003, 2004 Jim Weirich - def terminal_width - if ENV['THOR_COLUMNS'] - result = ENV['THOR_COLUMNS'].to_i + def dynamic_width_tput + %x{tput cols 2>/dev/null}.to_i + end + + def unix? + RUBY_PLATFORM =~ /(aix|darwin|linux|(net|free|open)bsd|cygwin|solaris|irix|hpux)/i + end + + def truncate(string, width) + as_unicode do + chars = string.chars.to_a + if chars.length <= width + chars.join else - result = unix? ? dynamic_width : 80 + ( chars[0, width-3].join ) + "..." end - (result < 10) ? 80 : result - rescue - 80 - end - - # Calculate the dynamic width of the terminal - def dynamic_width - @dynamic_width ||= (dynamic_width_stty.nonzero? || dynamic_width_tput) end + end - def dynamic_width_stty - %x{stty size 2>/dev/null}.split[1].to_i + if "".respond_to?(:encode) + def as_unicode + yield end - - def dynamic_width_tput - %x{tput cols 2>/dev/null}.to_i + else + def as_unicode + old, $KCODE = $KCODE, "U" + yield + ensure + $KCODE = old end + end - def unix? - RUBY_PLATFORM =~ /(aix|darwin|linux|(net|free|open)bsd|cygwin|solaris|irix|hpux)/i - end + def ask_simply(statement, color=nil) + say("#{statement} ", color) + stdin.gets.strip + end - def truncate(string, width) - if string.length <= width - string - else - ( string[0, width-3] || "" ) + "..." - end + def ask_filtered(statement, answer_set, *args) + correct_answer = nil + until correct_answer + answer = ask_simply("#{statement} #{answer_set.inspect}", *args) + correct_answer = answer_set.include?(answer) ? answer : nil + answers = answer_set.map(&:inspect).join(", ") + say("Your response must be one of: [#{answers}]. Please try again.") unless correct_answer end + correct_answer + end end end diff --git a/lib/bundler/vendor/thor/shell/color.rb b/lib/bundler/vendor/thor/shell/color.rb index b2bc66df..f24ab6cc 100644 --- a/lib/bundler/vendor/thor/shell/color.rb +++ b/lib/bundler/vendor/thor/shell/color.rb @@ -50,10 +50,46 @@ class Thor # on Highline implementation and it automatically appends CLEAR to the end # of the returned String. # - def set_color(string, color, bold=false) - color = self.class.const_get(color.to_s.upcase) if color.is_a?(Symbol) - bold = bold ? BOLD : "" - "#{bold}#{color}#{string}#{CLEAR}" + # Pass foreground, background and bold options to this method as + # symbols. + # + # Example: + # + # set_color "Hi!", :red, :on_white, :bold + # + # The available colors are: + # + # :bold + # :black + # :red + # :green + # :yellow + # :blue + # :magenta + # :cyan + # :white + # :on_black + # :on_red + # :on_green + # :on_yellow + # :on_blue + # :on_magenta + # :on_cyan + # :on_white + def set_color(string, *colors) + if colors.all? { |color| color.is_a?(Symbol) || color.is_a?(String) } + ansi_colors = colors.map { |color| lookup_color(color) } + "#{ansi_colors.join}#{string}#{CLEAR}" + else + # The old API was `set_color(color, bold=boolean)`. We + # continue to support the old API because you should never + # break old APIs unnecessarily :P + foreground, bold = colors + foreground = self.class.const_get(foreground.to_s.upcase) if foreground.is_a?(Symbol) + + bold = bold ? BOLD : "" + "#{bold}#{foreground}#{string}#{CLEAR}" + end end protected diff --git a/lib/bundler/vendor/thor/shell/html.rb b/lib/bundler/vendor/thor/shell/html.rb index d1952862..678bc89b 100644 --- a/lib/bundler/vendor/thor/shell/html.rb +++ b/lib/bundler/vendor/thor/shell/html.rb @@ -7,56 +7,58 @@ class Thor # class HTML < Basic # The start of an HTML bold sequence. - BOLD = "<strong>" - # The end of an HTML bold sequence. - END_BOLD = "</strong>" - - # Embed in a String to clear previous color selection. - CLEAR = "</span>" + BOLD = "font-weight: bold" # Set the terminal's foreground HTML color to black. - BLACK = '<span style="color: black;">' + BLACK = 'color: black' # Set the terminal's foreground HTML color to red. - RED = '<span style="color: red;">' + RED = 'color: red' # Set the terminal's foreground HTML color to green. - GREEN = '<span style="color: green;">' + GREEN = 'color: green' # Set the terminal's foreground HTML color to yellow. - YELLOW = '<span style="color: yellow;">' + YELLOW = 'color: yellow' # Set the terminal's foreground HTML color to blue. - BLUE = '<span style="color: blue;">' + BLUE = 'color: blue' # Set the terminal's foreground HTML color to magenta. - MAGENTA = '<span style="color: magenta;">' + MAGENTA = 'color: magenta' # Set the terminal's foreground HTML color to cyan. - CYAN = '<span style="color: cyan;">' + CYAN = 'color: cyan' # Set the terminal's foreground HTML color to white. - WHITE = '<span style="color: white;">' + WHITE = 'color: white' # Set the terminal's background HTML color to black. - ON_BLACK = '<span style="background-color: black">' + ON_BLACK = 'background-color: black' # Set the terminal's background HTML color to red. - ON_RED = '<span style="background-color: red">' + ON_RED = 'background-color: red' # Set the terminal's background HTML color to green. - ON_GREEN = '<span style="background-color: green">' + ON_GREEN = 'background-color: green' # Set the terminal's background HTML color to yellow. - ON_YELLOW = '<span style="background-color: yellow">' + ON_YELLOW = 'background-color: yellow' # Set the terminal's background HTML color to blue. - ON_BLUE = '<span style="background-color: blue">' + ON_BLUE = 'background-color: blue' # Set the terminal's background HTML color to magenta. - ON_MAGENTA = '<span style="background-color: magenta">' + ON_MAGENTA = 'background-color: magenta' # Set the terminal's background HTML color to cyan. - ON_CYAN = '<span style="background-color: cyan">' + ON_CYAN = 'background-color: cyan' # Set the terminal's background HTML color to white. - ON_WHITE = '<span style="background-color: white">' + ON_WHITE = 'background-color: white' # Set color by using a string or one of the defined constants. If a third # option is set to true, it also adds bold to the string. This is based # on Highline implementation and it automatically appends CLEAR to the end # of the returned String. # - def set_color(string, color, bold=false) - color = self.class.const_get(color.to_s.upcase) if color.is_a?(Symbol) - bold, end_bold = bold ? [BOLD, END_BOLD] : ['', ''] - "#{bold}#{color}#{string}#{CLEAR}#{end_bold}" + def set_color(string, *colors) + if colors.all? { |color| color.is_a?(Symbol) || color.is_a?(String) } + html_colors = colors.map { |color| lookup_color(color) } + "<span style=\"#{html_colors.join("; ")};\">#{string}</span>" + else + color, bold = colors + html_color = self.class.const_get(color.to_s.upcase) if color.is_a?(Symbol) + styles = [html_color] + styles << BOLD if bold + "<span style=\"#{styles.join("; ")};\">#{string}</span>" + end end # Ask something to the user and receives a response. diff --git a/lib/bundler/vendor/thor/task.rb b/lib/bundler/vendor/thor/task.rb index 6db3b608..02daa1a2 100644 --- a/lib/bundler/vendor/thor/task.rb +++ b/lib/bundler/vendor/thor/task.rb @@ -18,11 +18,21 @@ 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=[]) - public_method?(instance) ? - instance.send(name, *args) : instance.class.handle_no_task_error(name) + arity = nil + + if private_method?(instance) + instance.class.handle_no_task_error(name) + elsif public_method?(instance) + arity = instance.method(name).arity + instance.send(name, *args) + elsif local_method?(instance, :method_missing) + instance.send(:method_missing, name.to_sym, *args) + else + instance.class.handle_no_task_error(name) + end rescue ArgumentError => e handle_argument_error?(instance, e, caller) ? - instance.class.handle_argument_error(self, e) : (raise e) + instance.class.handle_argument_error(self, e, arity) : (raise e) rescue NoMethodError => e handle_no_method_error?(instance, e, caller) ? instance.class.handle_no_task_error(name) : (raise e) @@ -34,8 +44,8 @@ class Thor if namespace namespace = klass.namespace formatted = "#{namespace.gsub(/^(default)/,'')}:" - formatted.sub!(/.$/, ' ') if subcommand end + formatted = "#{klass.namespace.split(':').last} " if subcommand formatted ||= "" @@ -70,8 +80,17 @@ class Thor !(instance.public_methods & [name.to_s, name.to_sym]).empty? end + def private_method?(instance) + !(instance.private_methods & [name.to_s, name.to_sym]).empty? + end + + def local_method?(instance, name) + methods = instance.public_methods(false) + instance.private_methods(false) + instance.protected_methods(false) + !(methods & [name.to_s, name.to_sym]).empty? + end + def sans_backtrace(backtrace, caller) #:nodoc: - saned = backtrace.reject { |frame| frame =~ FILE_REGEXP } + saned = backtrace.reject { |frame| frame =~ FILE_REGEXP || (frame =~ /\.java:/ && RUBY_PLATFORM =~ /java/) } saned -= caller end diff --git a/lib/bundler/vendor/thor/util.rb b/lib/bundler/vendor/thor/util.rb index 275a30bf..d45843dd 100644 --- a/lib/bundler/vendor/thor/util.rb +++ b/lib/bundler/vendor/thor/util.rb @@ -153,11 +153,11 @@ class Thor begin Thor::Sandbox.class_eval(content, path) rescue Exception => e - $stderr.puts "WARNING: unable to load thorfile #{path.inspect}: #{e.message}" + $stderr.puts("WARNING: unable to load thorfile #{path.inspect}: #{e.message}") if debug - $stderr.puts *e.backtrace + $stderr.puts(*e.backtrace) else - $stderr.puts e.backtrace.first + $stderr.puts(e.backtrace.first) end end end @@ -184,7 +184,7 @@ class Thor end end - # Returns the root where thor files are located, dependending on the OS. + # Returns the root where thor files are located, depending on the OS. # def self.thor_root File.join(user_home, ".thor").gsub(/\\/, '/') @@ -198,7 +198,7 @@ class Thor # If we don't #gsub the \ character, Dir.glob will fail. # def self.thor_root_glob - files = Dir["#{thor_root}/*"] + files = Dir["#{escape_globs(thor_root)}/*"] files.map! do |file| File.directory?(file) ? File.join(file, "main.thor") : file @@ -208,6 +208,7 @@ class Thor # Where to look for Thor files. # def self.globs_for(path) + path = escape_globs(path) ["#{path}/Thorfile", "#{path}/*.thor", "#{path}/tasks/*.thor", "#{path}/lib/tasks/*.thor"] end @@ -216,14 +217,50 @@ class Thor # def self.ruby_command @ruby_command ||= begin - ruby = File.join(RbConfig::CONFIG['bindir'], RbConfig::CONFIG['ruby_install_name']) + ruby_name = RbConfig::CONFIG['ruby_install_name'] + ruby = File.join(RbConfig::CONFIG['bindir'], ruby_name) ruby << RbConfig::CONFIG['EXEEXT'] + # avoid using different name than ruby (on platforms supporting links) + if ruby_name != 'ruby' && File.respond_to?(:readlink) + begin + alternate_ruby = File.join(RbConfig::CONFIG['bindir'], 'ruby') + alternate_ruby << RbConfig::CONFIG['EXEEXT'] + + # ruby is a symlink + if File.symlink? alternate_ruby + linked_ruby = File.readlink alternate_ruby + + # symlink points to 'ruby_install_name' + ruby = alternate_ruby if linked_ruby == ruby_name || linked_ruby == ruby + end + rescue NotImplementedError + # just ignore on windows + end + end + # escape string in case path to ruby executable contain spaces. ruby.sub!(/.*\s.*/m, '"\&"') ruby end end + # Returns a string that has had any glob characters escaped. + # The glob characters are `* ? { } [ ]`. + # + # ==== Examples + # + # Thor::Util.escape_globs('[apps]') # => '\[apps\]' + # + # ==== Parameters + # String + # + # ==== Returns + # String + # + def self.escape_globs(path) + path.to_s.gsub(/[*?{}\[\]]/, '\\\\\\&') + end + end end diff --git a/lib/bundler/vendor/thor/version.rb b/lib/bundler/vendor/thor/version.rb index 7de92f16..7e888f89 100644 --- a/lib/bundler/vendor/thor/version.rb +++ b/lib/bundler/vendor/thor/version.rb @@ -1,3 +1,3 @@ class Thor - VERSION = "0.14.6".freeze + VERSION = "0.15.2" end |