clive 0.6.2 → 0.7.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.
- data/README.md +129 -126
- data/lib/clive.rb +30 -119
- data/lib/clive/bool.rb +32 -34
- data/lib/clive/command.rb +171 -54
- data/lib/clive/exceptions.rb +2 -2
- data/lib/clive/ext.rb +21 -3
- data/lib/clive/flag.rb +80 -67
- data/lib/clive/formatter.rb +180 -0
- data/lib/clive/option.rb +41 -25
- data/lib/clive/output.rb +14 -18
- data/lib/clive/parser.rb +79 -16
- data/lib/clive/switch.rb +8 -17
- data/lib/clive/tokens.rb +1 -1
- data/lib/clive/version.rb +2 -2
- data/spec/clive/bool_spec.rb +54 -0
- data/spec/clive/command_spec.rb +260 -0
- data/spec/clive/exceptions_spec.rb +1 -0
- data/spec/clive/ext_spec.rb +1 -0
- data/spec/clive/flag_spec.rb +84 -0
- data/spec/clive/formatter_spec.rb +108 -0
- data/spec/clive/option_spec.rb +34 -0
- data/spec/clive/output_spec.rb +5 -0
- data/spec/clive/parser_spec.rb +106 -0
- data/spec/clive/switch_spec.rb +14 -0
- data/spec/clive/tokens_spec.rb +38 -0
- data/spec/shared_specs.rb +16 -0
- data/spec/spec_helper.rb +12 -0
- metadata +34 -8
    
        data/lib/clive/flag.rb
    CHANGED
    
    | @@ -1,4 +1,4 @@ | |
| 1 | 
            -
             | 
| 1 | 
            +
            module Clive
         | 
| 2 2 |  | 
| 3 3 | 
             
              # A switch that takes one or more arguments.
         | 
| 4 4 | 
             
              #   eg. wget --tries=10
         | 
| @@ -10,68 +10,58 @@ class Clive | |
| 10 10 | 
             
                # Creates a new Flag instance. A flag is a switch that can take one or more
         | 
| 11 11 | 
             
                # arguments.
         | 
| 12 12 | 
             
                #
         | 
| 13 | 
            -
                #  | 
| 14 | 
            -
                #  | 
| 13 | 
            +
                # @param names [Array[Symbol]]
         | 
| 14 | 
            +
                #   An array of names the flag can be invoked by. Can contain a long name
         | 
| 15 | 
            +
                #   and/or a short name.
         | 
| 15 16 | 
             
                #
         | 
| 16 | 
            -
                # @ | 
| 17 | 
            -
                #    | 
| 18 | 
            -
                #   @param [Symbol] long longer switch to be used, eg. +:tries+ => +--tries=10+
         | 
| 19 | 
            -
                #   @param [String, Array] args
         | 
| 20 | 
            -
                #     either a string showing the arguments to be given, eg.
         | 
| 21 | 
            -
                #    
         | 
| 22 | 
            -
                #       "FROM"    # single arg, or
         | 
| 23 | 
            -
                #       "FROM TO" # two args, or
         | 
| 24 | 
            -
                #       "[VIA]"   # optional arg surrounded by square brackets
         | 
| 17 | 
            +
                # @param desc [String]
         | 
| 18 | 
            +
                #   A description of the flag.
         | 
| 25 19 | 
             
                #
         | 
| 26 | 
            -
                # | 
| 20 | 
            +
                # @param args [String, Array, Range]
         | 
| 21 | 
            +
                #   Either, a string showing the arguments to be given, eg.
         | 
| 22 | 
            +
                #     
         | 
| 23 | 
            +
                #     "FROM"          # single argument required, or
         | 
| 24 | 
            +
                #     "[FROM]"        # single optional argument, or
         | 
| 25 | 
            +
                #     "FROM TO"       # multiple arguments required, or
         | 
| 26 | 
            +
                #     "FROM [VIA] TO" # multiple arguments with optional argument
         | 
| 27 27 | 
             
                #
         | 
| 28 | 
            -
                # | 
| 28 | 
            +
                #   OR an array of acceptable inputs, eg.
         | 
| 29 29 | 
             
                #
         | 
| 30 | 
            -
                # | 
| 30 | 
            +
                #     %w(large small medium) # will only accept these arguments
         | 
| 31 | 
            +
                #   
         | 
| 32 | 
            +
                #   OR a range, showing the acceptable inputs, eg.
         | 
| 33 | 
            +
                #     1..10 #=> means 1, 2, 3, ..., 8, 9, 10
         | 
| 31 34 | 
             
                #
         | 
| 32 | 
            -
                # @yield [String]  | 
| 35 | 
            +
                # @yield [String] 
         | 
| 36 | 
            +
                #   A block to be run if switch is triggered, will always be passed a string
         | 
| 33 37 | 
             
                #
         | 
| 34 | 
            -
                def initialize( | 
| 35 | 
            -
                  @names =  | 
| 36 | 
            -
                  @args  =  | 
| 38 | 
            +
                def initialize(names, desc, args, &block)
         | 
| 39 | 
            +
                  @names = Clive::Array.new(names.map(&:to_s))
         | 
| 40 | 
            +
                  @args  = Clive::Array.new
         | 
| 37 41 |  | 
| 38 42 | 
             
                  # Need to be able to make each arg_name optional or not
         | 
| 39 43 | 
             
                  # and allow for type in future
         | 
| 40 44 | 
             
                  args.each do |i|
         | 
| 41 | 
            -
                     | 
| 42 | 
            -
             | 
| 43 | 
            -
             | 
| 44 | 
            -
             | 
| 45 | 
            -
             | 
| 46 | 
            -
             | 
| 47 | 
            -
             | 
| 48 | 
            -
                              :optional => true,
         | 
| 49 | 
            -
                              :type => type
         | 
| 50 | 
            -
                            }
         | 
| 51 | 
            -
                          else
         | 
| 52 | 
            -
                            @args << {
         | 
| 53 | 
            -
                              :name => arg, 
         | 
| 54 | 
            -
                              :optional => false, 
         | 
| 55 | 
            -
                              :type => type
         | 
| 56 | 
            -
                            }
         | 
| 57 | 
            -
                          end
         | 
| 45 | 
            +
                    case i
         | 
| 46 | 
            +
                    when String
         | 
| 47 | 
            +
                      i.split(' ').each do |arg|
         | 
| 48 | 
            +
                        optional = false
         | 
| 49 | 
            +
                        if arg[0] == "["
         | 
| 50 | 
            +
                          optional = true
         | 
| 51 | 
            +
                          arg = arg[1..-2]
         | 
| 58 52 | 
             
                        end
         | 
| 59 | 
            -
             | 
| 60 | 
            -
                        @desc = i
         | 
| 53 | 
            +
                        @args << {:name => arg, :optional => optional}
         | 
| 61 54 | 
             
                      end
         | 
| 62 55 | 
             
                    else
         | 
| 63 | 
            -
                       | 
| 64 | 
            -
                        @names << i.to_s 
         | 
| 65 | 
            -
                      else
         | 
| 66 | 
            -
                        @args = i
         | 
| 67 | 
            -
                      end
         | 
| 56 | 
            +
                      @args = i
         | 
| 68 57 | 
             
                    end
         | 
| 69 58 | 
             
                  end
         | 
| 70 | 
            -
                  
         | 
| 71 | 
            -
                  if @args == []
         | 
| 72 | 
            -
                    @args = [{:name => "ARG", :optional => false, :type => String}]
         | 
| 73 | 
            -
                  end
         | 
| 74 59 |  | 
| 60 | 
            +
                  if @args.empty?
         | 
| 61 | 
            +
                    @args = [{:name => "ARG", :optional => false}]
         | 
| 62 | 
            +
                  end
         | 
| 63 | 
            +
                  
         | 
| 64 | 
            +
                  @desc  = desc
         | 
| 75 65 | 
             
                  @block = block
         | 
| 76 66 | 
             
                end
         | 
| 77 67 |  | 
| @@ -81,10 +71,10 @@ class Clive | |
| 81 71 | 
             
                # @raise [InvalidArgument] only if +args+ is an array of acceptable inputs
         | 
| 82 72 | 
             
                #   and a match is not found.
         | 
| 83 73 | 
             
                def run(args)
         | 
| 84 | 
            -
                  if @args[0].is_a? | 
| 74 | 
            +
                  if @args.is_a?(Array) && @args[0].is_a?(Hash)
         | 
| 85 75 | 
             
                    args = Clive::Array.new(@args.collect {|i| !i[:optional]}).optimise_fill(args)
         | 
| 86 76 | 
             
                  else # list
         | 
| 87 | 
            -
                    unless @args.include? args[0]
         | 
| 77 | 
            +
                    unless @args.to_a.map(&:to_s).include? args[0]
         | 
| 88 78 | 
             
                      raise InvalidArgument.new(args)
         | 
| 89 79 | 
             
                    end
         | 
| 90 80 | 
             
                  end
         | 
| @@ -94,33 +84,56 @@ class Clive | |
| 94 84 | 
             
                # @param [Boolean] optional whether to include optional arguments
         | 
| 95 85 | 
             
                # @return [Integer] number of arguments this takes
         | 
| 96 86 | 
             
                def arg_num(optional)
         | 
| 97 | 
            -
                  if @args[0].is_a? | 
| 87 | 
            +
                  if @args.is_a?(Array) && @args[0].is_a?(Hash)
         | 
| 98 88 | 
             
                    @args.find_all {|i| i[:optional] == optional }.size
         | 
| 99 89 | 
             
                  else
         | 
| 100 90 | 
             
                    1
         | 
| 101 91 | 
             
                  end
         | 
| 102 92 | 
             
                end
         | 
| 103 93 |  | 
| 104 | 
            -
                 | 
| 105 | 
            -
             | 
| 106 | 
            -
             | 
| 107 | 
            -
                   | 
| 108 | 
            -
             | 
| 109 | 
            -
                     | 
| 110 | 
            -
             | 
| 111 | 
            -
             | 
| 112 | 
            -
             | 
| 113 | 
            -
             | 
| 94 | 
            +
                def args_to_strings
         | 
| 95 | 
            +
                  if @args.is_a? Range
         | 
| 96 | 
            +
                    [""]
         | 
| 97 | 
            +
                  elsif @args[0].is_a? Hash
         | 
| 98 | 
            +
                    r = []
         | 
| 99 | 
            +
                    @args.each do |arg|
         | 
| 100 | 
            +
                      if arg[:optional]
         | 
| 101 | 
            +
                        r << "[" + arg[:name] + "]"
         | 
| 102 | 
            +
                      else
         | 
| 103 | 
            +
                        r << arg[:name]
         | 
| 104 | 
            +
                      end
         | 
| 114 105 | 
             
                    end
         | 
| 106 | 
            +
                    r
         | 
| 115 107 | 
             
                  else
         | 
| 116 | 
            -
                     | 
| 108 | 
            +
                    [""]
         | 
| 117 109 | 
             
                  end
         | 
| 118 | 
            -
             | 
| 119 | 
            -
             | 
| 120 | 
            -
             | 
| 121 | 
            -
                   | 
| 122 | 
            -
             | 
| 123 | 
            -
                   | 
| 110 | 
            +
                end
         | 
| 111 | 
            +
                
         | 
| 112 | 
            +
                def arg_size
         | 
| 113 | 
            +
                  if @args.is_a?(Range) || @args.is_a?(Array)
         | 
| 114 | 
            +
                    1
         | 
| 115 | 
            +
                  else
         | 
| 116 | 
            +
                    @args.size
         | 
| 117 | 
            +
                  end
         | 
| 118 | 
            +
                end
         | 
| 119 | 
            +
                
         | 
| 120 | 
            +
                def options_to_strings
         | 
| 121 | 
            +
                  if @args.is_a? Range
         | 
| 122 | 
            +
                    [@args.to_s]
         | 
| 123 | 
            +
                  elsif @args[0].is_a? Hash
         | 
| 124 | 
            +
                    ['']
         | 
| 125 | 
            +
                  else
         | 
| 126 | 
            +
                    @args
         | 
| 127 | 
            +
                  end
         | 
| 128 | 
            +
                end
         | 
| 129 | 
            +
                
         | 
| 130 | 
            +
                def to_h
         | 
| 131 | 
            +
                  {
         | 
| 132 | 
            +
                    'names'   => Clive::Array.new(names_to_strings),
         | 
| 133 | 
            +
                    'desc'    => @desc,
         | 
| 134 | 
            +
                    'args'    => Clive::Array.new(args_to_strings),
         | 
| 135 | 
            +
                    'options' => Clive::Array.new(options_to_strings)
         | 
| 136 | 
            +
                  }
         | 
| 124 137 | 
             
                end
         | 
| 125 138 |  | 
| 126 139 | 
             
              end
         | 
| @@ -0,0 +1,180 @@ | |
| 1 | 
            +
            require 'strscan'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Clive
         | 
| 4 | 
            +
              
         | 
| 5 | 
            +
              # The formatter controls formatting of help. It can be configured
         | 
| 6 | 
            +
              # using Clive::Command#help_formatter.
         | 
| 7 | 
            +
              class Formatter
         | 
| 8 | 
            +
              
         | 
| 9 | 
            +
                class Obj
         | 
| 10 | 
            +
                  def initialize(args)
         | 
| 11 | 
            +
                    args.each do |k, v|
         | 
| 12 | 
            +
                      self.class.send(:define_method, k) { v }
         | 
| 13 | 
            +
                    end
         | 
| 14 | 
            +
                  end
         | 
| 15 | 
            +
                  
         | 
| 16 | 
            +
                  # Evaluate the code given within the Obj created.
         | 
| 17 | 
            +
                  def evaluate(code)
         | 
| 18 | 
            +
                    eval(code)
         | 
| 19 | 
            +
                  end
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
              
         | 
| 22 | 
            +
                # Sizes
         | 
| 23 | 
            +
                attr_accessor :width, :prepend
         | 
| 24 | 
            +
              
         | 
| 25 | 
            +
                def initialize(width, prepend, &block)
         | 
| 26 | 
            +
                  @width = width
         | 
| 27 | 
            +
                  @prepend = prepend
         | 
| 28 | 
            +
                end
         | 
| 29 | 
            +
                
         | 
| 30 | 
            +
                
         | 
| 31 | 
            +
                def format(header, footer, commands, options)
         | 
| 32 | 
            +
                  result = ""
         | 
| 33 | 
            +
                
         | 
| 34 | 
            +
                  switches = options.find_all {|i| i.class == Clive::Switch }.map(&:to_h)
         | 
| 35 | 
            +
                  bools    = options.find_all {|i| i.class == Clive::Bool }.map(&:to_h).compact
         | 
| 36 | 
            +
                  flags    = options.find_all {|i| i.class == Clive::Flag }.map(&:to_h)
         | 
| 37 | 
            +
                  commands = commands.map(&:to_h)
         | 
| 38 | 
            +
                  
         | 
| 39 | 
            +
                  result << header << "\n" if header
         | 
| 40 | 
            +
                  
         | 
| 41 | 
            +
                  unless commands.empty?
         | 
| 42 | 
            +
                    result << "\n  Commands: \n"
         | 
| 43 | 
            +
                    
         | 
| 44 | 
            +
                    commands.each do |hash|
         | 
| 45 | 
            +
                      hash['prepend'] = " " * @prepend
         | 
| 46 | 
            +
                      result << parse(@command, hash) << "\n"
         | 
| 47 | 
            +
                    end
         | 
| 48 | 
            +
                  end
         | 
| 49 | 
            +
                  
         | 
| 50 | 
            +
                  
         | 
| 51 | 
            +
                  unless options.empty?
         | 
| 52 | 
            +
                    result << "\n  Options: \n"
         | 
| 53 | 
            +
                  
         | 
| 54 | 
            +
                    switches.each do |hash|
         | 
| 55 | 
            +
                      hash['prepend'] = " " * @prepend
         | 
| 56 | 
            +
                      result << parse(@switch, hash) << "\n"
         | 
| 57 | 
            +
                    end
         | 
| 58 | 
            +
                    
         | 
| 59 | 
            +
                    bools.each do |hash|
         | 
| 60 | 
            +
                      hash['prepend'] = " " * @prepend
         | 
| 61 | 
            +
                      result << parse(@bool, hash) << "\n"
         | 
| 62 | 
            +
                    end
         | 
| 63 | 
            +
                    
         | 
| 64 | 
            +
                    flags.each do |hash|
         | 
| 65 | 
            +
                      hash['prepend'] = " " * @prepend
         | 
| 66 | 
            +
                      result << parse(@flag, hash) << "\n"
         | 
| 67 | 
            +
                    end
         | 
| 68 | 
            +
                  end
         | 
| 69 | 
            +
                  
         | 
| 70 | 
            +
                  result << "\n" << footer << "\n" if footer
         | 
| 71 | 
            +
                  
         | 
| 72 | 
            +
                  result
         | 
| 73 | 
            +
                end
         | 
| 74 | 
            +
                
         | 
| 75 | 
            +
                
         | 
| 76 | 
            +
                def switch(format)
         | 
| 77 | 
            +
                  @switch = format
         | 
| 78 | 
            +
                end
         | 
| 79 | 
            +
                
         | 
| 80 | 
            +
                def bool(format)
         | 
| 81 | 
            +
                  @bool = format
         | 
| 82 | 
            +
                end
         | 
| 83 | 
            +
                
         | 
| 84 | 
            +
                def flag(format)
         | 
| 85 | 
            +
                  @flag = format
         | 
| 86 | 
            +
                end
         | 
| 87 | 
            +
                
         | 
| 88 | 
            +
                def command(format)
         | 
| 89 | 
            +
                  @command = format
         | 
| 90 | 
            +
                end
         | 
| 91 | 
            +
                
         | 
| 92 | 
            +
                def help(format)
         | 
| 93 | 
            +
                  @help = format
         | 
| 94 | 
            +
                end
         | 
| 95 | 
            +
                
         | 
| 96 | 
            +
                def summary(format)
         | 
| 97 | 
            +
                  @summary = format
         | 
| 98 | 
            +
                end
         | 
| 99 | 
            +
                
         | 
| 100 | 
            +
                
         | 
| 101 | 
            +
                def parse(format, args)
         | 
| 102 | 
            +
                  front, back = format.split('{spaces}')
         | 
| 103 | 
            +
                  
         | 
| 104 | 
            +
                  front_p = parse_format(front, args)
         | 
| 105 | 
            +
                  back_p  = parse_format(back, args) 
         | 
| 106 | 
            +
                  
         | 
| 107 | 
            +
                  s = @width - front_p.length
         | 
| 108 | 
            +
                  s = 0 if s < 0 # can't have negative spaces!
         | 
| 109 | 
            +
                  spaces = " " * s
         | 
| 110 | 
            +
                  
         | 
| 111 | 
            +
                  front_p << spaces << back_p
         | 
| 112 | 
            +
                end
         | 
| 113 | 
            +
                
         | 
| 114 | 
            +
                def parse_format(format, args)
         | 
| 115 | 
            +
                  if format
         | 
| 116 | 
            +
                    @scanner = StringScanner.new(format)
         | 
| 117 | 
            +
                    result = []
         | 
| 118 | 
            +
              
         | 
| 119 | 
            +
                    # Create object to eval in
         | 
| 120 | 
            +
                    obj = Obj.new(args)
         | 
| 121 | 
            +
                    
         | 
| 122 | 
            +
                    until @scanner.eos?
         | 
| 123 | 
            +
                      a = scan_block || a = scan_text
         | 
| 124 | 
            +
                      result << a
         | 
| 125 | 
            +
                    end
         | 
| 126 | 
            +
                    
         | 
| 127 | 
            +
                    r = ""
         | 
| 128 | 
            +
                    result.each do |(t, v)|
         | 
| 129 | 
            +
                      case t
         | 
| 130 | 
            +
                      when :block # contains ruby to eval
         | 
| 131 | 
            +
                        r << obj.evaluate(v)
         | 
| 132 | 
            +
                      when :text # add this with no adjustment
         | 
| 133 | 
            +
                        r << v
         | 
| 134 | 
            +
                      end
         | 
| 135 | 
            +
                    end
         | 
| 136 | 
            +
                    r
         | 
| 137 | 
            +
                  else
         | 
| 138 | 
            +
                    ""
         | 
| 139 | 
            +
                  end
         | 
| 140 | 
            +
                end
         | 
| 141 | 
            +
                
         | 
| 142 | 
            +
                
         | 
| 143 | 
            +
                # @group Scanning     
         | 
| 144 | 
            +
                  def scan_block
         | 
| 145 | 
            +
                    return unless @scanner.scan /\{/
         | 
| 146 | 
            +
                    
         | 
| 147 | 
            +
                    pos = @scanner.pos
         | 
| 148 | 
            +
                    if @scanner.scan_until /\}/
         | 
| 149 | 
            +
                      @scanner.pos -= @scanner.matched.size
         | 
| 150 | 
            +
                      [:block, @scanner.pre_match[pos..-1]]
         | 
| 151 | 
            +
                    end
         | 
| 152 | 
            +
                  end
         | 
| 153 | 
            +
                  
         | 
| 154 | 
            +
                  def scan_text
         | 
| 155 | 
            +
                    text = nil
         | 
| 156 | 
            +
                    
         | 
| 157 | 
            +
                    pos = @scanner.pos
         | 
| 158 | 
            +
                    if @scanner.scan_until /(?<=[^\\])\{/
         | 
| 159 | 
            +
                      @scanner.pos -= @scanner.matched.size
         | 
| 160 | 
            +
                      text = @scanner.pre_match[pos..-1]
         | 
| 161 | 
            +
                    end
         | 
| 162 | 
            +
                    
         | 
| 163 | 
            +
                    if text.nil?
         | 
| 164 | 
            +
                      text = @scanner.rest
         | 
| 165 | 
            +
                      @scanner.clear
         | 
| 166 | 
            +
                    end
         | 
| 167 | 
            +
                    
         | 
| 168 | 
            +
                    # Remove }s from text
         | 
| 169 | 
            +
                    if text[0] == "}"
         | 
| 170 | 
            +
                      text = text[1..-1]
         | 
| 171 | 
            +
                    end
         | 
| 172 | 
            +
                    
         | 
| 173 | 
            +
                    text.gsub!(/\\(.)/) {|m| m[1] }
         | 
| 174 | 
            +
                            
         | 
| 175 | 
            +
                    [:text, text]
         | 
| 176 | 
            +
                  end
         | 
| 177 | 
            +
                # @endgroup
         | 
| 178 | 
            +
              
         | 
| 179 | 
            +
              end
         | 
| 180 | 
            +
            end
         | 
    
        data/lib/clive/option.rb
    CHANGED
    
    | @@ -1,32 +1,44 @@ | |
| 1 | 
            -
             | 
| 1 | 
            +
            module Clive
         | 
| 2 2 |  | 
| 3 | 
            -
              # @abstract Subclass and override {#initialize} and {#run} to create a  | 
| 3 | 
            +
              # @abstract Subclass and override {#initialize} and {#run} to create a 
         | 
| 4 | 
            +
              #   new Option class. {#to_h} can also be overriden to provide information
         | 
| 5 | 
            +
              #   when building the help.
         | 
| 6 | 
            +
              #
         | 
| 7 | 
            +
              # Option is the base class for switches, flags, commands, etc. It should be
         | 
| 8 | 
            +
              # used as a template for the way options (or whatever) are initialized, and
         | 
| 9 | 
            +
              # the other methods that may need implementing.
         | 
| 10 | 
            +
              #
         | 
| 4 11 | 
             
              class Option
         | 
| 5 12 | 
             
                attr_accessor :names, :desc, :block
         | 
| 6 13 |  | 
| 7 | 
            -
                 | 
| 8 | 
            -
             | 
| 9 | 
            -
             | 
| 14 | 
            +
                # Create a new Option instance. 
         | 
| 15 | 
            +
                #
         | 
| 16 | 
            +
                # For subclasses the method call should take the form:
         | 
| 17 | 
            +
                # +initialize(names, desc, [special args], &block)+.
         | 
| 18 | 
            +
                #
         | 
| 19 | 
            +
                # @param names [Array[Symbol]]
         | 
| 20 | 
            +
                #   An array of names the option can be invoked by.
         | 
| 21 | 
            +
                #
         | 
| 22 | 
            +
                # @param desc [String]
         | 
| 23 | 
            +
                #   A description of what the option does.
         | 
| 24 | 
            +
                #
         | 
| 25 | 
            +
                # @yield A block to run if the switch is triggered
         | 
| 26 | 
            +
                #
         | 
| 27 | 
            +
                def initialize(names, desc, &block)
         | 
| 28 | 
            +
                  @names = names.map(&:to_s)
         | 
| 29 | 
            +
                  @desc  = desc
         | 
| 30 | 
            +
                  @block = block
         | 
| 10 31 | 
             
                end
         | 
| 11 32 |  | 
| 33 | 
            +
                # Calls the block.
         | 
| 12 34 | 
             
                def run
         | 
| 13 | 
            -
                   | 
| 14 | 
            -
                  # @block.call
         | 
| 15 | 
            -
                end
         | 
| 16 | 
            -
                
         | 
| 17 | 
            -
                def summary(width=30, prepend=5)
         | 
| 18 | 
            -
                  n = names_to_strings.join(', ')
         | 
| 19 | 
            -
                  spaces = width-n.length
         | 
| 20 | 
            -
                  spaces = 1 if spaces < 1
         | 
| 21 | 
            -
                  s = spaces(spaces)
         | 
| 22 | 
            -
                  p = spaces(prepend)
         | 
| 23 | 
            -
                  "#{p}#{n}#{s}#{@desc}"
         | 
| 35 | 
            +
                  @block.call
         | 
| 24 36 | 
             
                end
         | 
| 25 37 |  | 
| 26 38 | 
             
                # Convert the names to strings, if name is single character appends
         | 
| 27 39 | 
             
                # +-+, else appends +--+.
         | 
| 28 40 | 
             
                #
         | 
| 29 | 
            -
                # @param [Boolean]  | 
| 41 | 
            +
                # @param bool [Boolean] whether to add [no-] to long
         | 
| 30 42 | 
             
                #
         | 
| 31 43 | 
             
                # @example
         | 
| 32 44 | 
             
                #
         | 
| @@ -51,16 +63,10 @@ class Clive | |
| 51 63 | 
             
                  r
         | 
| 52 64 | 
             
                end
         | 
| 53 65 |  | 
| 54 | 
            -
                #  | 
| 55 | 
            -
                def spaces(n)
         | 
| 56 | 
            -
                  s = ''
         | 
| 57 | 
            -
                  (0...n).each {s << ' '}
         | 
| 58 | 
            -
                  s
         | 
| 59 | 
            -
                end
         | 
| 60 | 
            -
                
         | 
| 61 | 
            -
                # Tries to get the short name, if not choose lowest alphabetically
         | 
| 66 | 
            +
                # Tries to get the short name, if not chooses lowest alphabetically.
         | 
| 62 67 | 
             
                #
         | 
| 63 68 | 
             
                # @return [String] name to sort by
         | 
| 69 | 
            +
                #
         | 
| 64 70 | 
             
                def sort_name
         | 
| 65 71 | 
             
                  r = @names.sort[0]
         | 
| 66 72 | 
             
                  @names.each do |i|
         | 
| @@ -75,6 +81,16 @@ class Clive | |
| 75 81 | 
             
                def <=>(other)
         | 
| 76 82 | 
             
                  self.sort_name <=> other.sort_name
         | 
| 77 83 | 
             
                end
         | 
| 84 | 
            +
                
         | 
| 85 | 
            +
                # @return [Hash{String=>Object}]
         | 
| 86 | 
            +
                #   Returns a hash which can be passed to the help formatter.
         | 
| 87 | 
            +
                #
         | 
| 88 | 
            +
                def to_h
         | 
| 89 | 
            +
                  {
         | 
| 90 | 
            +
                    "names" => names_to_strings,
         | 
| 91 | 
            +
                    "desc"  => @desc
         | 
| 92 | 
            +
                  }
         | 
| 93 | 
            +
                end
         | 
| 78 94 |  | 
| 79 95 | 
             
              end
         | 
| 80 96 | 
             
            end
         |