thor 1.1.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
 - data/README.md +3 -9
 - data/lib/thor/actions/create_file.rb +3 -2
 - data/lib/thor/actions/directory.rb +1 -1
 - data/lib/thor/actions/empty_directory.rb +1 -1
 - data/lib/thor/actions/file_manipulation.rb +58 -26
 - data/lib/thor/actions/inject_into_file.rb +16 -6
 - data/lib/thor/actions.rb +21 -17
 - data/lib/thor/base.rb +140 -14
 - data/lib/thor/command.rb +13 -4
 - data/lib/thor/core_ext/hash_with_indifferent_access.rb +10 -0
 - data/lib/thor/error.rb +16 -20
 - data/lib/thor/group.rb +12 -1
 - data/lib/thor/invocation.rb +1 -1
 - data/lib/thor/nested_context.rb +2 -2
 - data/lib/thor/parser/argument.rb +17 -1
 - data/lib/thor/parser/arguments.rb +33 -17
 - data/lib/thor/parser/option.rb +28 -9
 - data/lib/thor/parser/options.rb +65 -8
 - data/lib/thor/rake_compat.rb +2 -2
 - data/lib/thor/runner.rb +41 -31
 - data/lib/thor/shell/basic.rb +59 -169
 - data/lib/thor/shell/color.rb +4 -46
 - data/lib/thor/shell/column_printer.rb +29 -0
 - data/lib/thor/shell/html.rb +4 -46
 - data/lib/thor/shell/lcs_diff.rb +49 -0
 - data/lib/thor/shell/table_printer.rb +118 -0
 - data/lib/thor/shell/terminal.rb +42 -0
 - data/lib/thor/shell/wrapped_printer.rb +38 -0
 - data/lib/thor/shell.rb +2 -2
 - data/lib/thor/util.rb +9 -8
 - data/lib/thor/version.rb +1 -1
 - data/lib/thor.rb +166 -8
 - data/thor.gemspec +19 -14
 - metadata +14 -12
 - data/CHANGELOG.md +0 -228
 
| 
         @@ -0,0 +1,49 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module LCSDiff
         
     | 
| 
      
 2 
     | 
    
         
            +
            protected
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
              # Overwrite show_diff to show diff with colors if Diff::LCS is
         
     | 
| 
      
 5 
     | 
    
         
            +
              # available.
         
     | 
| 
      
 6 
     | 
    
         
            +
              def show_diff(destination, content) #:nodoc:
         
     | 
| 
      
 7 
     | 
    
         
            +
                if diff_lcs_loaded? && ENV["THOR_DIFF"].nil? && ENV["RAILS_DIFF"].nil?
         
     | 
| 
      
 8 
     | 
    
         
            +
                  actual  = File.binread(destination).to_s.split("\n")
         
     | 
| 
      
 9 
     | 
    
         
            +
                  content = content.to_s.split("\n")
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                  Diff::LCS.sdiff(actual, content).each do |diff|
         
     | 
| 
      
 12 
     | 
    
         
            +
                    output_diff_line(diff)
         
     | 
| 
      
 13 
     | 
    
         
            +
                  end
         
     | 
| 
      
 14 
     | 
    
         
            +
                else
         
     | 
| 
      
 15 
     | 
    
         
            +
                  super
         
     | 
| 
      
 16 
     | 
    
         
            +
                end
         
     | 
| 
      
 17 
     | 
    
         
            +
              end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
            private
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
              def output_diff_line(diff) #:nodoc:
         
     | 
| 
      
 22 
     | 
    
         
            +
                case diff.action
         
     | 
| 
      
 23 
     | 
    
         
            +
                when "-"
         
     | 
| 
      
 24 
     | 
    
         
            +
                  say "- #{diff.old_element.chomp}", :red, true
         
     | 
| 
      
 25 
     | 
    
         
            +
                when "+"
         
     | 
| 
      
 26 
     | 
    
         
            +
                  say "+ #{diff.new_element.chomp}", :green, true
         
     | 
| 
      
 27 
     | 
    
         
            +
                when "!"
         
     | 
| 
      
 28 
     | 
    
         
            +
                  say "- #{diff.old_element.chomp}", :red, true
         
     | 
| 
      
 29 
     | 
    
         
            +
                  say "+ #{diff.new_element.chomp}", :green, true
         
     | 
| 
      
 30 
     | 
    
         
            +
                else
         
     | 
| 
      
 31 
     | 
    
         
            +
                  say "  #{diff.old_element.chomp}", nil, true
         
     | 
| 
      
 32 
     | 
    
         
            +
                end
         
     | 
| 
      
 33 
     | 
    
         
            +
              end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
              # Check if Diff::LCS is loaded. If it is, use it to create pretty output
         
     | 
| 
      
 36 
     | 
    
         
            +
              # for diff.
         
     | 
| 
      
 37 
     | 
    
         
            +
              def diff_lcs_loaded? #:nodoc:
         
     | 
| 
      
 38 
     | 
    
         
            +
                return true if defined?(Diff::LCS)
         
     | 
| 
      
 39 
     | 
    
         
            +
                return @diff_lcs_loaded unless @diff_lcs_loaded.nil?
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                @diff_lcs_loaded = begin
         
     | 
| 
      
 42 
     | 
    
         
            +
                  require "diff/lcs"
         
     | 
| 
      
 43 
     | 
    
         
            +
                  true
         
     | 
| 
      
 44 
     | 
    
         
            +
                rescue LoadError
         
     | 
| 
      
 45 
     | 
    
         
            +
                  false
         
     | 
| 
      
 46 
     | 
    
         
            +
                end
         
     | 
| 
      
 47 
     | 
    
         
            +
              end
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,118 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require_relative "column_printer"
         
     | 
| 
      
 2 
     | 
    
         
            +
            require_relative "terminal"
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            class Thor
         
     | 
| 
      
 5 
     | 
    
         
            +
              module Shell
         
     | 
| 
      
 6 
     | 
    
         
            +
                class TablePrinter < ColumnPrinter
         
     | 
| 
      
 7 
     | 
    
         
            +
                  BORDER_SEPARATOR = :separator
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                  def initialize(stdout, options = {})
         
     | 
| 
      
 10 
     | 
    
         
            +
                    super
         
     | 
| 
      
 11 
     | 
    
         
            +
                    @formats = []
         
     | 
| 
      
 12 
     | 
    
         
            +
                    @maximas = []
         
     | 
| 
      
 13 
     | 
    
         
            +
                    @colwidth = options[:colwidth]
         
     | 
| 
      
 14 
     | 
    
         
            +
                    @truncate = options[:truncate] == true ? Terminal.terminal_width : options[:truncate]
         
     | 
| 
      
 15 
     | 
    
         
            +
                    @padding = 1
         
     | 
| 
      
 16 
     | 
    
         
            +
                  end
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                  def print(array)
         
     | 
| 
      
 19 
     | 
    
         
            +
                    return if array.empty?
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                    prepare(array)
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                    print_border_separator if options[:borders]
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                    array.each do |row|
         
     | 
| 
      
 26 
     | 
    
         
            +
                      if options[:borders] && row == BORDER_SEPARATOR
         
     | 
| 
      
 27 
     | 
    
         
            +
                        print_border_separator
         
     | 
| 
      
 28 
     | 
    
         
            +
                        next
         
     | 
| 
      
 29 
     | 
    
         
            +
                      end
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                      sentence = "".dup
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                      row.each_with_index do |column, index|
         
     | 
| 
      
 34 
     | 
    
         
            +
                        sentence << format_cell(column, row.size, index)
         
     | 
| 
      
 35 
     | 
    
         
            +
                      end
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                      sentence = truncate(sentence)
         
     | 
| 
      
 38 
     | 
    
         
            +
                      sentence << "|" if options[:borders]
         
     | 
| 
      
 39 
     | 
    
         
            +
                      stdout.puts indentation + sentence
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                    end
         
     | 
| 
      
 42 
     | 
    
         
            +
                    print_border_separator if options[:borders]
         
     | 
| 
      
 43 
     | 
    
         
            +
                  end
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                private
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                  def prepare(array)
         
     | 
| 
      
 48 
     | 
    
         
            +
                    array = array.reject{|row| row == BORDER_SEPARATOR }
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                    @formats << "%-#{@colwidth + 2}s".dup if @colwidth
         
     | 
| 
      
 51 
     | 
    
         
            +
                    start = @colwidth ? 1 : 0
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
                    colcount = array.max { |a, b| a.size <=> b.size }.size
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
                    start.upto(colcount - 1) do |index|
         
     | 
| 
      
 56 
     | 
    
         
            +
                      maxima = array.map { |row| row[index] ? row[index].to_s.size : 0 }.max
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
                      @maximas << maxima
         
     | 
| 
      
 59 
     | 
    
         
            +
                      @formats << if options[:borders]
         
     | 
| 
      
 60 
     | 
    
         
            +
                         "%-#{maxima}s".dup
         
     | 
| 
      
 61 
     | 
    
         
            +
                      elsif index == colcount - 1
         
     | 
| 
      
 62 
     | 
    
         
            +
                        # Don't output 2 trailing spaces when printing the last column
         
     | 
| 
      
 63 
     | 
    
         
            +
                        "%-s".dup
         
     | 
| 
      
 64 
     | 
    
         
            +
                      else
         
     | 
| 
      
 65 
     | 
    
         
            +
                        "%-#{maxima + 2}s".dup
         
     | 
| 
      
 66 
     | 
    
         
            +
                      end
         
     | 
| 
      
 67 
     | 
    
         
            +
                    end
         
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
      
 69 
     | 
    
         
            +
                    @formats << "%s"
         
     | 
| 
      
 70 
     | 
    
         
            +
                  end
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
                  def format_cell(column, row_size, index)
         
     | 
| 
      
 73 
     | 
    
         
            +
                    maxima = @maximas[index]
         
     | 
| 
      
 74 
     | 
    
         
            +
             
     | 
| 
      
 75 
     | 
    
         
            +
                    f = if column.is_a?(Numeric)
         
     | 
| 
      
 76 
     | 
    
         
            +
                      if options[:borders]
         
     | 
| 
      
 77 
     | 
    
         
            +
                        # With borders we handle padding separately
         
     | 
| 
      
 78 
     | 
    
         
            +
                        "%#{maxima}s"
         
     | 
| 
      
 79 
     | 
    
         
            +
                      elsif index == row_size - 1
         
     | 
| 
      
 80 
     | 
    
         
            +
                        # Don't output 2 trailing spaces when printing the last column
         
     | 
| 
      
 81 
     | 
    
         
            +
                        "%#{maxima}s"
         
     | 
| 
      
 82 
     | 
    
         
            +
                      else
         
     | 
| 
      
 83 
     | 
    
         
            +
                        "%#{maxima}s  "
         
     | 
| 
      
 84 
     | 
    
         
            +
                      end
         
     | 
| 
      
 85 
     | 
    
         
            +
                    else
         
     | 
| 
      
 86 
     | 
    
         
            +
                      @formats[index]
         
     | 
| 
      
 87 
     | 
    
         
            +
                    end
         
     | 
| 
      
 88 
     | 
    
         
            +
             
     | 
| 
      
 89 
     | 
    
         
            +
                    cell = "".dup
         
     | 
| 
      
 90 
     | 
    
         
            +
                    cell << "|" + " " * @padding if options[:borders]
         
     | 
| 
      
 91 
     | 
    
         
            +
                    cell << f % column.to_s
         
     | 
| 
      
 92 
     | 
    
         
            +
                    cell << " " * @padding if options[:borders]
         
     | 
| 
      
 93 
     | 
    
         
            +
                    cell
         
     | 
| 
      
 94 
     | 
    
         
            +
                  end
         
     | 
| 
      
 95 
     | 
    
         
            +
             
     | 
| 
      
 96 
     | 
    
         
            +
                  def print_border_separator
         
     | 
| 
      
 97 
     | 
    
         
            +
                    separator = @maximas.map do |maxima|
         
     | 
| 
      
 98 
     | 
    
         
            +
                      "+" + "-" * (maxima + 2 * @padding)
         
     | 
| 
      
 99 
     | 
    
         
            +
                    end
         
     | 
| 
      
 100 
     | 
    
         
            +
                    stdout.puts indentation + separator.join + "+"
         
     | 
| 
      
 101 
     | 
    
         
            +
                  end
         
     | 
| 
      
 102 
     | 
    
         
            +
             
     | 
| 
      
 103 
     | 
    
         
            +
                  def truncate(string)
         
     | 
| 
      
 104 
     | 
    
         
            +
                    return string unless @truncate
         
     | 
| 
      
 105 
     | 
    
         
            +
                    chars = string.chars.to_a
         
     | 
| 
      
 106 
     | 
    
         
            +
                    if chars.length <= @truncate
         
     | 
| 
      
 107 
     | 
    
         
            +
                      chars.join
         
     | 
| 
      
 108 
     | 
    
         
            +
                    else
         
     | 
| 
      
 109 
     | 
    
         
            +
                      chars[0, @truncate - 3 - @indent].join + "..."
         
     | 
| 
      
 110 
     | 
    
         
            +
                    end
         
     | 
| 
      
 111 
     | 
    
         
            +
                  end
         
     | 
| 
      
 112 
     | 
    
         
            +
             
     | 
| 
      
 113 
     | 
    
         
            +
                  def indentation
         
     | 
| 
      
 114 
     | 
    
         
            +
                    " " * @indent
         
     | 
| 
      
 115 
     | 
    
         
            +
                  end
         
     | 
| 
      
 116 
     | 
    
         
            +
                end
         
     | 
| 
      
 117 
     | 
    
         
            +
              end
         
     | 
| 
      
 118 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,42 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            class Thor
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Shell
         
     | 
| 
      
 3 
     | 
    
         
            +
                module Terminal
         
     | 
| 
      
 4 
     | 
    
         
            +
                  DEFAULT_TERMINAL_WIDTH = 80
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
                  class << self
         
     | 
| 
      
 7 
     | 
    
         
            +
                    # This code was copied from Rake, available under MIT-LICENSE
         
     | 
| 
      
 8 
     | 
    
         
            +
                    # Copyright (c) 2003, 2004 Jim Weirich
         
     | 
| 
      
 9 
     | 
    
         
            +
                    def terminal_width
         
     | 
| 
      
 10 
     | 
    
         
            +
                      result = if ENV["THOR_COLUMNS"]
         
     | 
| 
      
 11 
     | 
    
         
            +
                        ENV["THOR_COLUMNS"].to_i
         
     | 
| 
      
 12 
     | 
    
         
            +
                      else
         
     | 
| 
      
 13 
     | 
    
         
            +
                        unix? ? dynamic_width : DEFAULT_TERMINAL_WIDTH
         
     | 
| 
      
 14 
     | 
    
         
            +
                      end
         
     | 
| 
      
 15 
     | 
    
         
            +
                      result < 10 ? DEFAULT_TERMINAL_WIDTH : result
         
     | 
| 
      
 16 
     | 
    
         
            +
                    rescue
         
     | 
| 
      
 17 
     | 
    
         
            +
                      DEFAULT_TERMINAL_WIDTH
         
     | 
| 
      
 18 
     | 
    
         
            +
                    end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                    def unix?
         
     | 
| 
      
 21 
     | 
    
         
            +
                      RUBY_PLATFORM =~ /(aix|darwin|linux|(net|free|open)bsd|cygwin|solaris)/i
         
     | 
| 
      
 22 
     | 
    
         
            +
                    end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                  private
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                    # Calculate the dynamic width of the terminal
         
     | 
| 
      
 27 
     | 
    
         
            +
                    def dynamic_width
         
     | 
| 
      
 28 
     | 
    
         
            +
                      @dynamic_width ||= (dynamic_width_stty.nonzero? || dynamic_width_tput)
         
     | 
| 
      
 29 
     | 
    
         
            +
                    end
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                    def dynamic_width_stty
         
     | 
| 
      
 32 
     | 
    
         
            +
                      `stty size 2>/dev/null`.split[1].to_i
         
     | 
| 
      
 33 
     | 
    
         
            +
                    end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                    def dynamic_width_tput
         
     | 
| 
      
 36 
     | 
    
         
            +
                      `tput cols 2>/dev/null`.to_i
         
     | 
| 
      
 37 
     | 
    
         
            +
                    end
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                  end
         
     | 
| 
      
 40 
     | 
    
         
            +
                end
         
     | 
| 
      
 41 
     | 
    
         
            +
              end
         
     | 
| 
      
 42 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,38 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require_relative "column_printer"
         
     | 
| 
      
 2 
     | 
    
         
            +
            require_relative "terminal"
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            class Thor
         
     | 
| 
      
 5 
     | 
    
         
            +
              module Shell
         
     | 
| 
      
 6 
     | 
    
         
            +
                class WrappedPrinter < ColumnPrinter
         
     | 
| 
      
 7 
     | 
    
         
            +
                  def print(message)
         
     | 
| 
      
 8 
     | 
    
         
            +
                    width = Terminal.terminal_width - @indent
         
     | 
| 
      
 9 
     | 
    
         
            +
                    paras = message.split("\n\n")
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                    paras.map! do |unwrapped|
         
     | 
| 
      
 12 
     | 
    
         
            +
                      words = unwrapped.split(" ")
         
     | 
| 
      
 13 
     | 
    
         
            +
                      counter = words.first.length
         
     | 
| 
      
 14 
     | 
    
         
            +
                      words.inject do |memo, word|
         
     | 
| 
      
 15 
     | 
    
         
            +
                        word = word.gsub(/\n\005/, "\n").gsub(/\005/, "\n")
         
     | 
| 
      
 16 
     | 
    
         
            +
                        counter = 0 if word.include? "\n"
         
     | 
| 
      
 17 
     | 
    
         
            +
                        if (counter + word.length + 1) < width
         
     | 
| 
      
 18 
     | 
    
         
            +
                          memo = "#{memo} #{word}"
         
     | 
| 
      
 19 
     | 
    
         
            +
                          counter += (word.length + 1)
         
     | 
| 
      
 20 
     | 
    
         
            +
                        else
         
     | 
| 
      
 21 
     | 
    
         
            +
                          memo = "#{memo}\n#{word}"
         
     | 
| 
      
 22 
     | 
    
         
            +
                          counter = word.length
         
     | 
| 
      
 23 
     | 
    
         
            +
                        end
         
     | 
| 
      
 24 
     | 
    
         
            +
                        memo
         
     | 
| 
      
 25 
     | 
    
         
            +
                      end
         
     | 
| 
      
 26 
     | 
    
         
            +
                    end.compact!
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                    paras.each do |para|
         
     | 
| 
      
 29 
     | 
    
         
            +
                      para.split("\n").each do |line|
         
     | 
| 
      
 30 
     | 
    
         
            +
                        stdout.puts line.insert(0, " " * @indent)
         
     | 
| 
      
 31 
     | 
    
         
            +
                      end
         
     | 
| 
      
 32 
     | 
    
         
            +
                      stdout.puts unless para == paras.last
         
     | 
| 
      
 33 
     | 
    
         
            +
                    end
         
     | 
| 
      
 34 
     | 
    
         
            +
                  end
         
     | 
| 
      
 35 
     | 
    
         
            +
                end
         
     | 
| 
      
 36 
     | 
    
         
            +
              end
         
     | 
| 
      
 37 
     | 
    
         
            +
            end
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
    
        data/lib/thor/shell.rb
    CHANGED
    
    | 
         @@ -21,7 +21,7 @@ class Thor 
     | 
|
| 
       21 
21 
     | 
    
         
             
              end
         
     | 
| 
       22 
22 
     | 
    
         | 
| 
       23 
23 
     | 
    
         
             
              module Shell
         
     | 
| 
       24 
     | 
    
         
            -
                SHELL_DELEGATED_METHODS = [:ask, :error, :set_color, :yes?, :no?, :say, :say_status, :print_in_columns, :print_table, :print_wrapped, :file_collision, :terminal_width]
         
     | 
| 
      
 24 
     | 
    
         
            +
                SHELL_DELEGATED_METHODS = [:ask, :error, :set_color, :yes?, :no?, :say, :say_error, :say_status, :print_in_columns, :print_table, :print_wrapped, :file_collision, :terminal_width]
         
     | 
| 
       25 
25 
     | 
    
         
             
                attr_writer :shell
         
     | 
| 
       26 
26 
     | 
    
         | 
| 
       27 
27 
     | 
    
         
             
                autoload :Basic, File.expand_path("shell/basic", __dir__)
         
     | 
| 
         @@ -75,7 +75,7 @@ class Thor 
     | 
|
| 
       75 
75 
     | 
    
         
             
                # Allow shell to be shared between invocations.
         
     | 
| 
       76 
76 
     | 
    
         
             
                #
         
     | 
| 
       77 
77 
     | 
    
         
             
                def _shared_configuration #:nodoc:
         
     | 
| 
       78 
     | 
    
         
            -
                  super.merge!(: 
     | 
| 
      
 78 
     | 
    
         
            +
                  super.merge!(shell: shell)
         
     | 
| 
       79 
79 
     | 
    
         
             
                end
         
     | 
| 
       80 
80 
     | 
    
         
             
              end
         
     | 
| 
       81 
81 
     | 
    
         
             
            end
         
     | 
    
        data/lib/thor/util.rb
    CHANGED
    
    | 
         @@ -90,7 +90,7 @@ class Thor 
     | 
|
| 
       90 
90 
     | 
    
         
             
                  def snake_case(str)
         
     | 
| 
       91 
91 
     | 
    
         
             
                    return str.downcase if str =~ /^[A-Z_]+$/
         
     | 
| 
       92 
92 
     | 
    
         
             
                    str.gsub(/\B[A-Z]/, '_\&').squeeze("_") =~ /_*(.*)/
         
     | 
| 
       93 
     | 
    
         
            -
                     
     | 
| 
      
 93 
     | 
    
         
            +
                    Regexp.last_match(-1).downcase
         
     | 
| 
       94 
94 
     | 
    
         
             
                  end
         
     | 
| 
       95 
95 
     | 
    
         | 
| 
       96 
96 
     | 
    
         
             
                  # Receives a string and convert it to camel case. camel_case returns CamelCase.
         
     | 
| 
         @@ -130,9 +130,10 @@ class Thor 
     | 
|
| 
       130 
130 
     | 
    
         
             
                  #
         
     | 
| 
       131 
131 
     | 
    
         
             
                  def find_class_and_command_by_namespace(namespace, fallback = true)
         
     | 
| 
       132 
132 
     | 
    
         
             
                    if namespace.include?(":") # look for a namespaced command
         
     | 
| 
       133 
     | 
    
         
            -
                      pieces  = namespace.split(":")
         
     | 
| 
       134 
     | 
    
         
            -
                       
     | 
| 
       135 
     | 
    
         
            -
                       
     | 
| 
      
 133 
     | 
    
         
            +
                      *pieces, command  = namespace.split(":")
         
     | 
| 
      
 134 
     | 
    
         
            +
                      namespace = pieces.join(":")
         
     | 
| 
      
 135 
     | 
    
         
            +
                      namespace = "default" if namespace.empty?
         
     | 
| 
      
 136 
     | 
    
         
            +
                      klass = Thor::Base.subclasses.detect { |thor| thor.namespace == namespace && thor.command_exists?(command) }
         
     | 
| 
       136 
137 
     | 
    
         
             
                    end
         
     | 
| 
       137 
138 
     | 
    
         
             
                    unless klass # look for a Thor::Group with the right name
         
     | 
| 
       138 
139 
     | 
    
         
             
                      klass = Thor::Util.find_by_namespace(namespace)
         
     | 
| 
         @@ -150,7 +151,7 @@ class Thor 
     | 
|
| 
       150 
151 
     | 
    
         
             
                  # inside the sandbox to avoid namespacing conflicts.
         
     | 
| 
       151 
152 
     | 
    
         
             
                  #
         
     | 
| 
       152 
153 
     | 
    
         
             
                  def load_thorfile(path, content = nil, debug = false)
         
     | 
| 
       153 
     | 
    
         
            -
                    content ||= File. 
     | 
| 
      
 154 
     | 
    
         
            +
                    content ||= File.read(path)
         
     | 
| 
       154 
155 
     | 
    
         | 
| 
       155 
156 
     | 
    
         
             
                    begin
         
     | 
| 
       156 
157 
     | 
    
         
             
                      Thor::Sandbox.class_eval(content, path)
         
     | 
| 
         @@ -189,7 +190,7 @@ class Thor 
     | 
|
| 
       189 
190 
     | 
    
         
             
                  # Returns the root where thor files are located, depending on the OS.
         
     | 
| 
       190 
191 
     | 
    
         
             
                  #
         
     | 
| 
       191 
192 
     | 
    
         
             
                  def thor_root
         
     | 
| 
       192 
     | 
    
         
            -
                    File.join(user_home, ".thor").tr( 
     | 
| 
      
 193 
     | 
    
         
            +
                    File.join(user_home, ".thor").tr("\\", "/")
         
     | 
| 
       193 
194 
     | 
    
         
             
                  end
         
     | 
| 
       194 
195 
     | 
    
         | 
| 
       195 
196 
     | 
    
         
             
                  # Returns the files in the thor root. On Windows thor_root will be something
         
     | 
| 
         @@ -211,7 +212,7 @@ class Thor 
     | 
|
| 
       211 
212 
     | 
    
         
             
                  #
         
     | 
| 
       212 
213 
     | 
    
         
             
                  def globs_for(path)
         
     | 
| 
       213 
214 
     | 
    
         
             
                    path = escape_globs(path)
         
     | 
| 
       214 
     | 
    
         
            -
                    ["#{path}/Thorfile", "#{path}/*.thor", "#{path}/tasks/*.thor", "#{path}/lib/tasks 
     | 
| 
      
 215 
     | 
    
         
            +
                    ["#{path}/Thorfile", "#{path}/*.thor", "#{path}/tasks/*.thor", "#{path}/lib/tasks/**/*.thor"]
         
     | 
| 
       215 
216 
     | 
    
         
             
                  end
         
     | 
| 
       216 
217 
     | 
    
         | 
| 
       217 
218 
     | 
    
         
             
                  # Return the path to the ruby interpreter taking into account multiple
         
     | 
| 
         @@ -236,7 +237,7 @@ class Thor 
     | 
|
| 
       236 
237 
     | 
    
         
             
                            # symlink points to 'ruby_install_name'
         
     | 
| 
       237 
238 
     | 
    
         
             
                            ruby = alternate_ruby if linked_ruby == ruby_name || linked_ruby == ruby
         
     | 
| 
       238 
239 
     | 
    
         
             
                          end
         
     | 
| 
       239 
     | 
    
         
            -
                        rescue NotImplementedError # rubocop:disable HandleExceptions
         
     | 
| 
      
 240 
     | 
    
         
            +
                        rescue NotImplementedError # rubocop:disable Lint/HandleExceptions
         
     | 
| 
       240 
241 
     | 
    
         
             
                          # just ignore on windows
         
     | 
| 
       241 
242 
     | 
    
         
             
                        end
         
     | 
| 
       242 
243 
     | 
    
         
             
                      end
         
     | 
    
        data/lib/thor/version.rb
    CHANGED
    
    
    
        data/lib/thor.rb
    CHANGED
    
    | 
         @@ -65,8 +65,15 @@ class Thor 
     | 
|
| 
       65 
65 
     | 
    
         | 
| 
       66 
66 
     | 
    
         
             
                # Defines the long description of the next command.
         
     | 
| 
       67 
67 
     | 
    
         
             
                #
         
     | 
| 
      
 68 
     | 
    
         
            +
                # Long description is by default indented, line-wrapped and repeated whitespace merged.
         
     | 
| 
      
 69 
     | 
    
         
            +
                # In order to print long description verbatim, with indentation and spacing exactly
         
     | 
| 
      
 70 
     | 
    
         
            +
                # as found in the code, use the +wrap+ option
         
     | 
| 
      
 71 
     | 
    
         
            +
                #
         
     | 
| 
      
 72 
     | 
    
         
            +
                #   long_desc 'your very long description', wrap: false
         
     | 
| 
      
 73 
     | 
    
         
            +
                #
         
     | 
| 
       68 
74 
     | 
    
         
             
                # ==== Parameters
         
     | 
| 
       69 
75 
     | 
    
         
             
                # long description<String>
         
     | 
| 
      
 76 
     | 
    
         
            +
                # options<Hash>
         
     | 
| 
       70 
77 
     | 
    
         
             
                #
         
     | 
| 
       71 
78 
     | 
    
         
             
                def long_desc(long_description, options = {})
         
     | 
| 
       72 
79 
     | 
    
         
             
                  if options[:for]
         
     | 
| 
         @@ -74,6 +81,7 @@ class Thor 
     | 
|
| 
       74 
81 
     | 
    
         
             
                    command.long_description = long_description if long_description
         
     | 
| 
       75 
82 
     | 
    
         
             
                  else
         
     | 
| 
       76 
83 
     | 
    
         
             
                    @long_desc = long_description
         
     | 
| 
      
 84 
     | 
    
         
            +
                    @long_desc_wrap = options[:wrap] != false
         
     | 
| 
       77 
85 
     | 
    
         
             
                  end
         
     | 
| 
       78 
86 
     | 
    
         
             
                end
         
     | 
| 
       79 
87 
     | 
    
         | 
| 
         @@ -133,7 +141,7 @@ class Thor 
     | 
|
| 
       133 
141 
     | 
    
         
             
                #     # magic
         
     | 
| 
       134 
142 
     | 
    
         
             
                #   end
         
     | 
| 
       135 
143 
     | 
    
         
             
                #
         
     | 
| 
       136 
     | 
    
         
            -
                #   method_option :foo 
     | 
| 
      
 144 
     | 
    
         
            +
                #   method_option :foo, :for => :previous_command
         
     | 
| 
       137 
145 
     | 
    
         
             
                #
         
     | 
| 
       138 
146 
     | 
    
         
             
                #   def next_command
         
     | 
| 
       139 
147 
     | 
    
         
             
                #     # magic
         
     | 
| 
         @@ -153,6 +161,9 @@ class Thor 
     | 
|
| 
       153 
161 
     | 
    
         
             
                # :hide     - If you want to hide this option from the help.
         
     | 
| 
       154 
162 
     | 
    
         
             
                #
         
     | 
| 
       155 
163 
     | 
    
         
             
                def method_option(name, options = {})
         
     | 
| 
      
 164 
     | 
    
         
            +
                  unless [ Symbol, String ].any? { |klass| name.is_a?(klass) }
         
     | 
| 
      
 165 
     | 
    
         
            +
                    raise ArgumentError, "Expected a Symbol or String, got #{name.inspect}"
         
     | 
| 
      
 166 
     | 
    
         
            +
                  end
         
     | 
| 
       156 
167 
     | 
    
         
             
                  scope = if options[:for]
         
     | 
| 
       157 
168 
     | 
    
         
             
                    find_and_refresh_command(options[:for]).options
         
     | 
| 
       158 
169 
     | 
    
         
             
                  else
         
     | 
| 
         @@ -163,6 +174,81 @@ class Thor 
     | 
|
| 
       163 
174 
     | 
    
         
             
                end
         
     | 
| 
       164 
175 
     | 
    
         
             
                alias_method :option, :method_option
         
     | 
| 
       165 
176 
     | 
    
         | 
| 
      
 177 
     | 
    
         
            +
                # Adds and declares option group for exclusive options in the
         
     | 
| 
      
 178 
     | 
    
         
            +
                # block and arguments. You can declare options as the outside of the block.
         
     | 
| 
      
 179 
     | 
    
         
            +
                #
         
     | 
| 
      
 180 
     | 
    
         
            +
                # If :for is given as option, it allows you to change the options from
         
     | 
| 
      
 181 
     | 
    
         
            +
                # a previous defined command.
         
     | 
| 
      
 182 
     | 
    
         
            +
                #
         
     | 
| 
      
 183 
     | 
    
         
            +
                # ==== Parameters
         
     | 
| 
      
 184 
     | 
    
         
            +
                # Array[Thor::Option.name]
         
     | 
| 
      
 185 
     | 
    
         
            +
                # options<Hash>:: :for is applied for previous defined command.
         
     | 
| 
      
 186 
     | 
    
         
            +
                #
         
     | 
| 
      
 187 
     | 
    
         
            +
                # ==== Examples
         
     | 
| 
      
 188 
     | 
    
         
            +
                #
         
     | 
| 
      
 189 
     | 
    
         
            +
                #   exclusive do
         
     | 
| 
      
 190 
     | 
    
         
            +
                #     option :one
         
     | 
| 
      
 191 
     | 
    
         
            +
                #     option :two
         
     | 
| 
      
 192 
     | 
    
         
            +
                #   end
         
     | 
| 
      
 193 
     | 
    
         
            +
                #
         
     | 
| 
      
 194 
     | 
    
         
            +
                # Or
         
     | 
| 
      
 195 
     | 
    
         
            +
                #
         
     | 
| 
      
 196 
     | 
    
         
            +
                #   option :one
         
     | 
| 
      
 197 
     | 
    
         
            +
                #   option :two
         
     | 
| 
      
 198 
     | 
    
         
            +
                #   exclusive :one, :two
         
     | 
| 
      
 199 
     | 
    
         
            +
                #
         
     | 
| 
      
 200 
     | 
    
         
            +
                # If you give "--one" and "--two" at the same time ExclusiveArgumentsError
         
     | 
| 
      
 201 
     | 
    
         
            +
                # will be raised.
         
     | 
| 
      
 202 
     | 
    
         
            +
                #
         
     | 
| 
      
 203 
     | 
    
         
            +
                def method_exclusive(*args, &block)
         
     | 
| 
      
 204 
     | 
    
         
            +
                  register_options_relation_for(:method_options,
         
     | 
| 
      
 205 
     | 
    
         
            +
                                                :method_exclusive_option_names, *args, &block)
         
     | 
| 
      
 206 
     | 
    
         
            +
                end
         
     | 
| 
      
 207 
     | 
    
         
            +
                alias_method :exclusive, :method_exclusive
         
     | 
| 
      
 208 
     | 
    
         
            +
             
     | 
| 
      
 209 
     | 
    
         
            +
                # Adds and declares option group for required at least one of options in the
         
     | 
| 
      
 210 
     | 
    
         
            +
                # block of arguments. You can declare options as the outside of the block.
         
     | 
| 
      
 211 
     | 
    
         
            +
                #
         
     | 
| 
      
 212 
     | 
    
         
            +
                # If :for is given as option, it allows you to change the options from
         
     | 
| 
      
 213 
     | 
    
         
            +
                # a previous defined command.
         
     | 
| 
      
 214 
     | 
    
         
            +
                #
         
     | 
| 
      
 215 
     | 
    
         
            +
                # ==== Parameters
         
     | 
| 
      
 216 
     | 
    
         
            +
                # Array[Thor::Option.name]
         
     | 
| 
      
 217 
     | 
    
         
            +
                # options<Hash>:: :for is applied for previous defined command.
         
     | 
| 
      
 218 
     | 
    
         
            +
                #
         
     | 
| 
      
 219 
     | 
    
         
            +
                # ==== Examples
         
     | 
| 
      
 220 
     | 
    
         
            +
                #
         
     | 
| 
      
 221 
     | 
    
         
            +
                #   at_least_one do
         
     | 
| 
      
 222 
     | 
    
         
            +
                #     option :one
         
     | 
| 
      
 223 
     | 
    
         
            +
                #     option :two
         
     | 
| 
      
 224 
     | 
    
         
            +
                #   end
         
     | 
| 
      
 225 
     | 
    
         
            +
                #
         
     | 
| 
      
 226 
     | 
    
         
            +
                # Or
         
     | 
| 
      
 227 
     | 
    
         
            +
                #
         
     | 
| 
      
 228 
     | 
    
         
            +
                #   option :one
         
     | 
| 
      
 229 
     | 
    
         
            +
                #   option :two
         
     | 
| 
      
 230 
     | 
    
         
            +
                #   at_least_one :one, :two
         
     | 
| 
      
 231 
     | 
    
         
            +
                #
         
     | 
| 
      
 232 
     | 
    
         
            +
                # If you do not give "--one" and "--two" AtLeastOneRequiredArgumentError
         
     | 
| 
      
 233 
     | 
    
         
            +
                # will be raised.
         
     | 
| 
      
 234 
     | 
    
         
            +
                #
         
     | 
| 
      
 235 
     | 
    
         
            +
                # You can use at_least_one and exclusive at the same time.
         
     | 
| 
      
 236 
     | 
    
         
            +
                #
         
     | 
| 
      
 237 
     | 
    
         
            +
                #    exclusive do
         
     | 
| 
      
 238 
     | 
    
         
            +
                #      at_least_one do
         
     | 
| 
      
 239 
     | 
    
         
            +
                #        option :one
         
     | 
| 
      
 240 
     | 
    
         
            +
                #        option :two
         
     | 
| 
      
 241 
     | 
    
         
            +
                #      end
         
     | 
| 
      
 242 
     | 
    
         
            +
                #    end
         
     | 
| 
      
 243 
     | 
    
         
            +
                #
         
     | 
| 
      
 244 
     | 
    
         
            +
                # Then it is required either only one of "--one" or "--two".
         
     | 
| 
      
 245 
     | 
    
         
            +
                #
         
     | 
| 
      
 246 
     | 
    
         
            +
                def method_at_least_one(*args, &block)
         
     | 
| 
      
 247 
     | 
    
         
            +
                  register_options_relation_for(:method_options,
         
     | 
| 
      
 248 
     | 
    
         
            +
                                                :method_at_least_one_option_names, *args, &block)
         
     | 
| 
      
 249 
     | 
    
         
            +
                end
         
     | 
| 
      
 250 
     | 
    
         
            +
                alias_method :at_least_one, :method_at_least_one
         
     | 
| 
      
 251 
     | 
    
         
            +
             
     | 
| 
       166 
252 
     | 
    
         
             
                # Prints help information for the given command.
         
     | 
| 
       167 
253 
     | 
    
         
             
                #
         
     | 
| 
       168 
254 
     | 
    
         
             
                # ==== Parameters
         
     | 
| 
         @@ -178,9 +264,16 @@ class Thor 
     | 
|
| 
       178 
264 
     | 
    
         
             
                  shell.say "  #{banner(command).split("\n").join("\n  ")}"
         
     | 
| 
       179 
265 
     | 
    
         
             
                  shell.say
         
     | 
| 
       180 
266 
     | 
    
         
             
                  class_options_help(shell, nil => command.options.values)
         
     | 
| 
      
 267 
     | 
    
         
            +
                  print_exclusive_options(shell, command)
         
     | 
| 
      
 268 
     | 
    
         
            +
                  print_at_least_one_required_options(shell, command)
         
     | 
| 
      
 269 
     | 
    
         
            +
             
     | 
| 
       181 
270 
     | 
    
         
             
                  if command.long_description
         
     | 
| 
       182 
271 
     | 
    
         
             
                    shell.say "Description:"
         
     | 
| 
       183 
     | 
    
         
            -
                     
     | 
| 
      
 272 
     | 
    
         
            +
                    if command.wrap_long_description
         
     | 
| 
      
 273 
     | 
    
         
            +
                      shell.print_wrapped(command.long_description, indent: 2)
         
     | 
| 
      
 274 
     | 
    
         
            +
                    else
         
     | 
| 
      
 275 
     | 
    
         
            +
                      shell.say command.long_description
         
     | 
| 
      
 276 
     | 
    
         
            +
                    end
         
     | 
| 
       184 
277 
     | 
    
         
             
                  else
         
     | 
| 
       185 
278 
     | 
    
         
             
                    shell.say command.description
         
     | 
| 
       186 
279 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -197,7 +290,7 @@ class Thor 
     | 
|
| 
       197 
290 
     | 
    
         
             
                  Thor::Util.thor_classes_in(self).each do |klass|
         
     | 
| 
       198 
291 
     | 
    
         
             
                    list += klass.printable_commands(false)
         
     | 
| 
       199 
292 
     | 
    
         
             
                  end
         
     | 
| 
       200 
     | 
    
         
            -
                  list 
     | 
| 
      
 293 
     | 
    
         
            +
                  sort_commands!(list)
         
     | 
| 
       201 
294 
     | 
    
         | 
| 
       202 
295 
     | 
    
         
             
                  if defined?(@package_name) && @package_name
         
     | 
| 
       203 
296 
     | 
    
         
             
                    shell.say "#{@package_name} commands:"
         
     | 
| 
         @@ -205,9 +298,11 @@ class Thor 
     | 
|
| 
       205 
298 
     | 
    
         
             
                    shell.say "Commands:"
         
     | 
| 
       206 
299 
     | 
    
         
             
                  end
         
     | 
| 
       207 
300 
     | 
    
         | 
| 
       208 
     | 
    
         
            -
                  shell.print_table(list, : 
     | 
| 
      
 301 
     | 
    
         
            +
                  shell.print_table(list, indent: 2, truncate: true)
         
     | 
| 
       209 
302 
     | 
    
         
             
                  shell.say
         
     | 
| 
       210 
303 
     | 
    
         
             
                  class_options_help(shell)
         
     | 
| 
      
 304 
     | 
    
         
            +
                  print_exclusive_options(shell)
         
     | 
| 
      
 305 
     | 
    
         
            +
                  print_at_least_one_required_options(shell)
         
     | 
| 
       211 
306 
     | 
    
         
             
                end
         
     | 
| 
       212 
307 
     | 
    
         | 
| 
       213 
308 
     | 
    
         
             
                # Returns commands ready to be printed.
         
     | 
| 
         @@ -238,7 +333,7 @@ class Thor 
     | 
|
| 
       238 
333 
     | 
    
         | 
| 
       239 
334 
     | 
    
         
             
                  define_method(subcommand) do |*args|
         
     | 
| 
       240 
335 
     | 
    
         
             
                    args, opts = Thor::Arguments.split(args)
         
     | 
| 
       241 
     | 
    
         
            -
                    invoke_args = [args, opts, {: 
     | 
| 
      
 336 
     | 
    
         
            +
                    invoke_args = [args, opts, {invoked_via_subcommand: true, class_options: options}]
         
     | 
| 
       242 
337 
     | 
    
         
             
                    invoke_args.unshift "help" if opts.delete("--help") || opts.delete("-h")
         
     | 
| 
       243 
338 
     | 
    
         
             
                    invoke subcommand_class, *invoke_args
         
     | 
| 
       244 
339 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -344,8 +439,37 @@ class Thor 
     | 
|
| 
       344 
439 
     | 
    
         
             
                  command && disable_required_check.include?(command.name.to_sym)
         
     | 
| 
       345 
440 
     | 
    
         
             
                end
         
     | 
| 
       346 
441 
     | 
    
         | 
| 
      
 442 
     | 
    
         
            +
                # Checks if a specified command exists.
         
     | 
| 
      
 443 
     | 
    
         
            +
                #
         
     | 
| 
      
 444 
     | 
    
         
            +
                # ==== Parameters
         
     | 
| 
      
 445 
     | 
    
         
            +
                # command_name<String>:: The name of the command to check for existence.
         
     | 
| 
      
 446 
     | 
    
         
            +
                #
         
     | 
| 
      
 447 
     | 
    
         
            +
                # ==== Returns
         
     | 
| 
      
 448 
     | 
    
         
            +
                # Boolean:: +true+ if the command exists, +false+ otherwise.
         
     | 
| 
      
 449 
     | 
    
         
            +
                def command_exists?(command_name) #:nodoc:
         
     | 
| 
      
 450 
     | 
    
         
            +
                  commands.keys.include?(normalize_command_name(command_name))
         
     | 
| 
      
 451 
     | 
    
         
            +
                end
         
     | 
| 
      
 452 
     | 
    
         
            +
             
     | 
| 
       347 
453 
     | 
    
         
             
              protected
         
     | 
| 
       348 
454 
     | 
    
         | 
| 
      
 455 
     | 
    
         
            +
                # Returns this class exclusive options array set.
         
     | 
| 
      
 456 
     | 
    
         
            +
                #
         
     | 
| 
      
 457 
     | 
    
         
            +
                # ==== Returns
         
     | 
| 
      
 458 
     | 
    
         
            +
                # Array[Array[Thor::Option.name]]
         
     | 
| 
      
 459 
     | 
    
         
            +
                #
         
     | 
| 
      
 460 
     | 
    
         
            +
                def method_exclusive_option_names #:nodoc:
         
     | 
| 
      
 461 
     | 
    
         
            +
                  @method_exclusive_option_names ||= []
         
     | 
| 
      
 462 
     | 
    
         
            +
                end
         
     | 
| 
      
 463 
     | 
    
         
            +
             
     | 
| 
      
 464 
     | 
    
         
            +
                # Returns this class at least one of required options array set.
         
     | 
| 
      
 465 
     | 
    
         
            +
                #
         
     | 
| 
      
 466 
     | 
    
         
            +
                # ==== Returns
         
     | 
| 
      
 467 
     | 
    
         
            +
                # Array[Array[Thor::Option.name]]
         
     | 
| 
      
 468 
     | 
    
         
            +
                #
         
     | 
| 
      
 469 
     | 
    
         
            +
                def method_at_least_one_option_names #:nodoc:
         
     | 
| 
      
 470 
     | 
    
         
            +
                  @method_at_least_one_option_names ||= []
         
     | 
| 
      
 471 
     | 
    
         
            +
                end
         
     | 
| 
      
 472 
     | 
    
         
            +
             
     | 
| 
       349 
473 
     | 
    
         
             
                def stop_on_unknown_option #:nodoc:
         
     | 
| 
       350 
474 
     | 
    
         
             
                  @stop_on_unknown_option ||= []
         
     | 
| 
       351 
475 
     | 
    
         
             
                end
         
     | 
| 
         @@ -355,8 +479,30 @@ class Thor 
     | 
|
| 
       355 
479 
     | 
    
         
             
                  @disable_required_check ||= [:help]
         
     | 
| 
       356 
480 
     | 
    
         
             
                end
         
     | 
| 
       357 
481 
     | 
    
         | 
| 
      
 482 
     | 
    
         
            +
                def print_exclusive_options(shell, command = nil) # :nodoc:
         
     | 
| 
      
 483 
     | 
    
         
            +
                  opts = []
         
     | 
| 
      
 484 
     | 
    
         
            +
                  opts  = command.method_exclusive_option_names unless command.nil?
         
     | 
| 
      
 485 
     | 
    
         
            +
                  opts += class_exclusive_option_names
         
     | 
| 
      
 486 
     | 
    
         
            +
                  unless opts.empty?
         
     | 
| 
      
 487 
     | 
    
         
            +
                    shell.say "Exclusive Options:"
         
     | 
| 
      
 488 
     | 
    
         
            +
                    shell.print_table(opts.map{ |ex| ex.map{ |e| "--#{e}"}}, indent: 2 )
         
     | 
| 
      
 489 
     | 
    
         
            +
                    shell.say
         
     | 
| 
      
 490 
     | 
    
         
            +
                  end
         
     | 
| 
      
 491 
     | 
    
         
            +
                end
         
     | 
| 
      
 492 
     | 
    
         
            +
             
     | 
| 
      
 493 
     | 
    
         
            +
                def print_at_least_one_required_options(shell, command = nil) # :nodoc:
         
     | 
| 
      
 494 
     | 
    
         
            +
                  opts = []
         
     | 
| 
      
 495 
     | 
    
         
            +
                  opts = command.method_at_least_one_option_names unless command.nil?
         
     | 
| 
      
 496 
     | 
    
         
            +
                  opts += class_at_least_one_option_names
         
     | 
| 
      
 497 
     | 
    
         
            +
                  unless opts.empty?
         
     | 
| 
      
 498 
     | 
    
         
            +
                    shell.say "Required At Least One:"
         
     | 
| 
      
 499 
     | 
    
         
            +
                    shell.print_table(opts.map{ |ex| ex.map{ |e| "--#{e}"}}, indent: 2 )
         
     | 
| 
      
 500 
     | 
    
         
            +
                    shell.say
         
     | 
| 
      
 501 
     | 
    
         
            +
                  end
         
     | 
| 
      
 502 
     | 
    
         
            +
                end
         
     | 
| 
      
 503 
     | 
    
         
            +
             
     | 
| 
       358 
504 
     | 
    
         
             
                # The method responsible for dispatching given the args.
         
     | 
| 
       359 
     | 
    
         
            -
                def dispatch(meth, given_args, given_opts, config) #:nodoc: 
     | 
| 
      
 505 
     | 
    
         
            +
                def dispatch(meth, given_args, given_opts, config) #:nodoc:
         
     | 
| 
       360 
506 
     | 
    
         
             
                  meth ||= retrieve_command_name(given_args)
         
     | 
| 
       361 
507 
     | 
    
         
             
                  command = all_commands[normalize_command_name(meth)]
         
     | 
| 
       362 
508 
     | 
    
         | 
| 
         @@ -415,12 +561,16 @@ class Thor 
     | 
|
| 
       415 
561 
     | 
    
         
             
                  @usage ||= nil
         
     | 
| 
       416 
562 
     | 
    
         
             
                  @desc ||= nil
         
     | 
| 
       417 
563 
     | 
    
         
             
                  @long_desc ||= nil
         
     | 
| 
      
 564 
     | 
    
         
            +
                  @long_desc_wrap ||= nil
         
     | 
| 
       418 
565 
     | 
    
         
             
                  @hide ||= nil
         
     | 
| 
       419 
566 
     | 
    
         | 
| 
       420 
567 
     | 
    
         
             
                  if @usage && @desc
         
     | 
| 
       421 
568 
     | 
    
         
             
                    base_class = @hide ? Thor::HiddenCommand : Thor::Command
         
     | 
| 
       422 
     | 
    
         
            -
                     
     | 
| 
       423 
     | 
    
         
            -
             
     | 
| 
      
 569 
     | 
    
         
            +
                    relations = {exclusive_option_names: method_exclusive_option_names,
         
     | 
| 
      
 570 
     | 
    
         
            +
                      at_least_one_option_names: method_at_least_one_option_names}
         
     | 
| 
      
 571 
     | 
    
         
            +
                    commands[meth] = base_class.new(meth, @desc, @long_desc, @long_desc_wrap, @usage, method_options, relations)
         
     | 
| 
      
 572 
     | 
    
         
            +
                    @usage, @desc, @long_desc, @long_desc_wrap, @method_options, @hide = nil
         
     | 
| 
      
 573 
     | 
    
         
            +
                    @method_exclusive_option_names, @method_at_least_one_option_names = nil
         
     | 
| 
       424 
574 
     | 
    
         
             
                    true
         
     | 
| 
       425 
575 
     | 
    
         
             
                  elsif all_commands[meth] || meth == "method_missing"
         
     | 
| 
       426 
576 
     | 
    
         
             
                    true
         
     | 
| 
         @@ -495,6 +645,14 @@ class Thor 
     | 
|
| 
       495 
645 
     | 
    
         
             
            "
         
     | 
| 
       496 
646 
     | 
    
         
             
                end
         
     | 
| 
       497 
647 
     | 
    
         
             
                alias_method :subtask_help, :subcommand_help
         
     | 
| 
      
 648 
     | 
    
         
            +
             
     | 
| 
      
 649 
     | 
    
         
            +
                # Sort the commands, lexicographically by default.
         
     | 
| 
      
 650 
     | 
    
         
            +
                #
         
     | 
| 
      
 651 
     | 
    
         
            +
                # Can be overridden in the subclass to change the display order of the
         
     | 
| 
      
 652 
     | 
    
         
            +
                # commands.
         
     | 
| 
      
 653 
     | 
    
         
            +
                def sort_commands!(list)
         
     | 
| 
      
 654 
     | 
    
         
            +
                  list.sort! { |a, b| a[0] <=> b[0] }
         
     | 
| 
      
 655 
     | 
    
         
            +
                end
         
     | 
| 
       498 
656 
     | 
    
         
             
              end
         
     | 
| 
       499 
657 
     | 
    
         | 
| 
       500 
658 
     | 
    
         
             
              include Thor::Base
         
     | 
    
        data/thor.gemspec
    CHANGED
    
    | 
         @@ -4,25 +4,30 @@ $LOAD_PATH.unshift lib unless $LOAD_PATH.include?(lib) 
     | 
|
| 
       4 
4 
     | 
    
         
             
            require "thor/version"
         
     | 
| 
       5 
5 
     | 
    
         | 
| 
       6 
6 
     | 
    
         
             
            Gem::Specification.new do |spec|
         
     | 
| 
       7 
     | 
    
         
            -
              spec. 
     | 
| 
      
 7 
     | 
    
         
            +
              spec.name = "thor"
         
     | 
| 
      
 8 
     | 
    
         
            +
              spec.version = Thor::VERSION
         
     | 
| 
      
 9 
     | 
    
         
            +
              spec.licenses = %w(MIT)
         
     | 
| 
       8 
10 
     | 
    
         
             
              spec.authors = ["Yehuda Katz", "José Valim"]
         
     | 
| 
       9 
     | 
    
         
            -
              spec.description = "Thor is a toolkit for building powerful command-line interfaces."
         
     | 
| 
       10 
11 
     | 
    
         
             
              spec.email = "ruby-thor@googlegroups.com"
         
     | 
| 
       11 
     | 
    
         
            -
              spec.executables = %w(thor)
         
     | 
| 
       12 
     | 
    
         
            -
              spec.files = %w(.document thor.gemspec) + Dir["*.md", "bin/*", "lib/**/*.rb"]
         
     | 
| 
       13 
12 
     | 
    
         
             
              spec.homepage = "http://whatisthor.com/"
         
     | 
| 
       14 
     | 
    
         
            -
              spec. 
     | 
| 
       15 
     | 
    
         
            -
              spec. 
     | 
| 
      
 13 
     | 
    
         
            +
              spec.description = "Thor is a toolkit for building powerful command-line interfaces."
         
     | 
| 
      
 14 
     | 
    
         
            +
              spec.summary = spec.description
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
       16 
16 
     | 
    
         
             
              spec.metadata = {
         
     | 
| 
       17 
     | 
    
         
            -
                "bug_tracker_uri" => "https://github.com/ 
     | 
| 
       18 
     | 
    
         
            -
                "changelog_uri" => "https://github.com/ 
     | 
| 
      
 17 
     | 
    
         
            +
                "bug_tracker_uri" => "https://github.com/rails/thor/issues",
         
     | 
| 
      
 18 
     | 
    
         
            +
                "changelog_uri" => "https://github.com/rails/thor/releases/tag/v#{Thor::VERSION}",
         
     | 
| 
       19 
19 
     | 
    
         
             
                "documentation_uri" => "http://whatisthor.com/",
         
     | 
| 
       20 
     | 
    
         
            -
                "source_code_uri" => "https://github.com/ 
     | 
| 
       21 
     | 
    
         
            -
                "wiki_uri" => "https://github.com/ 
     | 
| 
      
 20 
     | 
    
         
            +
                "source_code_uri" => "https://github.com/rails/thor/tree/v#{Thor::VERSION}",
         
     | 
| 
      
 21 
     | 
    
         
            +
                "wiki_uri" => "https://github.com/rails/thor/wiki",
         
     | 
| 
      
 22 
     | 
    
         
            +
                "rubygems_mfa_required" => "true",
         
     | 
| 
       22 
23 
     | 
    
         
             
              }
         
     | 
| 
       23 
     | 
    
         
            -
             
     | 
| 
       24 
     | 
    
         
            -
              spec.required_ruby_version = ">= 2. 
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
              spec.required_ruby_version = ">= 2.6.0"
         
     | 
| 
       25 
26 
     | 
    
         
             
              spec.required_rubygems_version = ">= 1.3.5"
         
     | 
| 
       26 
     | 
    
         
            -
             
     | 
| 
       27 
     | 
    
         
            -
              spec. 
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
              spec.files = %w(.document thor.gemspec) + Dir["*.md", "bin/*", "lib/**/*.rb"]
         
     | 
| 
      
 29 
     | 
    
         
            +
              spec.executables = %w(thor)
         
     | 
| 
      
 30 
     | 
    
         
            +
              spec.require_paths = %w(lib)
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
              spec.add_development_dependency "bundler", ">= 1.0", "< 3"
         
     | 
| 
       28 
33 
     | 
    
         
             
            end
         
     |