hammer_cli 2.5.0 → 3.1.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/bin/hammer +1 -1
- data/doc/commands_extension.md +8 -6
- data/doc/creating_commands.md +17 -0
- data/doc/release_notes.md +23 -0
- data/lib/hammer_cli/abstract.rb +75 -60
- data/lib/hammer_cli/apipie/command.rb +1 -1
- data/lib/hammer_cli/apipie/option_builder.rb +16 -11
- data/lib/hammer_cli/apipie/option_definition.rb +1 -8
- data/lib/hammer_cli/command_extensions.rb +47 -34
- data/lib/hammer_cli/help/builder.rb +10 -6
- data/lib/hammer_cli/options/normalizers.rb +126 -18
- data/lib/hammer_cli/options/option_definition.rb +17 -22
- data/lib/hammer_cli/options/option_family.rb +44 -8
- data/lib/hammer_cli/output/adapter/abstract.rb +6 -0
- data/lib/hammer_cli/output/adapter/base.rb +1 -1
- data/lib/hammer_cli/output/adapter/tree_structure.rb +1 -1
- data/lib/hammer_cli/output/definition.rb +1 -1
- data/lib/hammer_cli/output/field_filter.rb +2 -2
- data/lib/hammer_cli/utils.rb +6 -0
- data/lib/hammer_cli/version.rb +1 -1
- data/locale/ca/LC_MESSAGES/hammer-cli.mo +0 -0
- data/locale/de/LC_MESSAGES/hammer-cli.mo +0 -0
- data/locale/en/LC_MESSAGES/hammer-cli.mo +0 -0
- data/locale/en_GB/LC_MESSAGES/hammer-cli.mo +0 -0
- data/locale/es/LC_MESSAGES/hammer-cli.mo +0 -0
- data/locale/fr/LC_MESSAGES/hammer-cli.mo +0 -0
- data/locale/it/LC_MESSAGES/hammer-cli.mo +0 -0
- data/locale/ja/LC_MESSAGES/hammer-cli.mo +0 -0
- data/locale/ko/LC_MESSAGES/hammer-cli.mo +0 -0
- data/locale/pt_BR/LC_MESSAGES/hammer-cli.mo +0 -0
- data/locale/ru/LC_MESSAGES/hammer-cli.mo +0 -0
- data/locale/zh_CN/LC_MESSAGES/hammer-cli.mo +0 -0
- data/locale/zh_TW/LC_MESSAGES/hammer-cli.mo +0 -0
- data/man/hammer.1.gz +0 -0
- data/test/unit/abstract_test.rb +7 -0
- data/test/unit/apipie/option_builder_test.rb +8 -3
- data/test/unit/command_extensions_test.rb +10 -2
- data/test/unit/help/builder_test.rb +20 -2
- data/test/unit/options/option_definition_test.rb +12 -1
- data/test/unit/output/definition_test.rb +3 -3
- metadata +22 -22
| @@ -29,7 +29,11 @@ module HammerCLI | |
| 29 29 |  | 
| 30 30 | 
             
                    label_width = DEFAULT_LABEL_INDENT
         | 
| 31 31 | 
             
                    items.each do |item|
         | 
| 32 | 
            -
                      label = item. | 
| 32 | 
            +
                      label = if !HammerCLI.context[:full_help] && item.respond_to?(:family) && item.family && !item.child?
         | 
| 33 | 
            +
                                item.family.help.first
         | 
| 34 | 
            +
                              else
         | 
| 35 | 
            +
                                item.help.first
         | 
| 36 | 
            +
                              end
         | 
| 33 37 | 
             
                      label_width = label.size if label.size > label_width
         | 
| 34 38 | 
             
                    end
         | 
| 35 39 |  | 
| @@ -38,11 +42,11 @@ module HammerCLI | |
| 38 42 | 
             
                        next unless HammerCLI.context[:full_help]
         | 
| 39 43 | 
             
                      end
         | 
| 40 44 | 
             
                      label, description = if !HammerCLI.context[:full_help] && item.respond_to?(:family) && item.family
         | 
| 41 | 
            -
             | 
| 42 | 
            -
             | 
| 43 | 
            -
             | 
| 44 | 
            -
             | 
| 45 | 
            -
                      description.gsub(/^(.)/) { Unicode | 
| 45 | 
            +
                                             item.family.help
         | 
| 46 | 
            +
                                           else
         | 
| 47 | 
            +
                                             item.help
         | 
| 48 | 
            +
                                           end
         | 
| 49 | 
            +
                      description.gsub(/^(.)/) { Unicode.capitalize(Regexp.last_match(1)) }.wrap.each_line do |line|
         | 
| 46 50 | 
             
                        puts " %-#{label_width}s %s" % [label, line]
         | 
| 47 51 | 
             
                        label = ''
         | 
| 48 52 | 
             
                      end
         | 
| @@ -4,8 +4,28 @@ require 'hammer_cli/csv_parser' | |
| 4 4 | 
             
            module HammerCLI
         | 
| 5 5 | 
             
              module Options
         | 
| 6 6 | 
             
                module Normalizers
         | 
| 7 | 
            +
                  def self.available
         | 
| 8 | 
            +
                    AbstractNormalizer.available
         | 
| 9 | 
            +
                  end
         | 
| 7 10 |  | 
| 8 11 | 
             
                  class AbstractNormalizer
         | 
| 12 | 
            +
                    class << self
         | 
| 13 | 
            +
                      attr_reader :available
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                      def inherited(subclass)
         | 
| 16 | 
            +
                        @available ||= []
         | 
| 17 | 
            +
                        @available << subclass
         | 
| 18 | 
            +
                      end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                      def completion_type
         | 
| 21 | 
            +
                        :value
         | 
| 22 | 
            +
                      end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                      def common_description
         | 
| 25 | 
            +
                        _("Value described in the option's description. Mostly simple string")
         | 
| 26 | 
            +
                      end
         | 
| 27 | 
            +
                    end
         | 
| 28 | 
            +
             | 
| 9 29 | 
             
                    def description
         | 
| 10 30 | 
             
                      ""
         | 
| 11 31 | 
             
                    end
         | 
| @@ -17,6 +37,10 @@ module HammerCLI | |
| 17 37 | 
             
                    def complete(val)
         | 
| 18 38 | 
             
                      []
         | 
| 19 39 | 
             
                    end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                    def completion_type
         | 
| 42 | 
            +
                      { type: self.class.completion_type }
         | 
| 43 | 
            +
                    end
         | 
| 20 44 | 
             
                  end
         | 
| 21 45 |  | 
| 22 46 | 
             
                  class Default < AbstractNormalizer
         | 
| @@ -30,9 +54,15 @@ module HammerCLI | |
| 30 54 | 
             
                    PAIR_RE = '([^,=]+)=([^,\{\[]+|[\{\[][^\{\}\[\]]*[\}\]])'
         | 
| 31 55 | 
             
                    FULL_RE = "^((%s)[,]?)+$" % PAIR_RE
         | 
| 32 56 |  | 
| 33 | 
            -
                     | 
| 34 | 
            -
                       | 
| 35 | 
            -
             | 
| 57 | 
            +
                    class << self
         | 
| 58 | 
            +
                      def completion_type
         | 
| 59 | 
            +
                        :key_value_list
         | 
| 60 | 
            +
                      end
         | 
| 61 | 
            +
             | 
| 62 | 
            +
                      def common_description
         | 
| 63 | 
            +
                        _('Comma-separated list of key=value.') + "\n" +
         | 
| 64 | 
            +
                          _('JSON is acceptable and preferred way for such parameters')
         | 
| 65 | 
            +
                      end
         | 
| 36 66 | 
             
                    end
         | 
| 37 67 |  | 
| 38 68 | 
             
                    def format(val)
         | 
| @@ -94,9 +124,16 @@ module HammerCLI | |
| 94 124 |  | 
| 95 125 |  | 
| 96 126 | 
             
                  class List < AbstractNormalizer
         | 
| 97 | 
            -
                     | 
| 98 | 
            -
                       | 
| 99 | 
            -
             | 
| 127 | 
            +
                    class << self
         | 
| 128 | 
            +
                      def completion_type
         | 
| 129 | 
            +
                        :list
         | 
| 130 | 
            +
                      end
         | 
| 131 | 
            +
             | 
| 132 | 
            +
                      def common_description
         | 
| 133 | 
            +
                        _('Comma separated list of values. Values containing comma should be quoted or escaped with backslash.') +
         | 
| 134 | 
            +
                          "\n" +
         | 
| 135 | 
            +
                          _('JSON is acceptable and preferred way for such parameters')
         | 
| 136 | 
            +
                      end
         | 
| 100 137 | 
             
                    end
         | 
| 101 138 |  | 
| 102 139 | 
             
                    def format(val)
         | 
| @@ -110,6 +147,18 @@ module HammerCLI | |
| 110 147 | 
             
                  end
         | 
| 111 148 |  | 
| 112 149 | 
             
                  class ListNested < AbstractNormalizer
         | 
| 150 | 
            +
                    class << self
         | 
| 151 | 
            +
                      def completion_type
         | 
| 152 | 
            +
                        :schema
         | 
| 153 | 
            +
                      end
         | 
| 154 | 
            +
             | 
| 155 | 
            +
                      def common_description
         | 
| 156 | 
            +
                        _('Comma separated list of values defined by a schema.') +
         | 
| 157 | 
            +
                          "\n" +
         | 
| 158 | 
            +
                          _('JSON is acceptable and preferred way for such parameters')
         | 
| 159 | 
            +
                      end
         | 
| 160 | 
            +
                    end
         | 
| 161 | 
            +
             | 
| 113 162 | 
             
                    class Schema < Array
         | 
| 114 163 | 
             
                      def description(richtext: true)
         | 
| 115 164 | 
             
                        '"' + reduce([]) do |schema, nested_param|
         | 
| @@ -135,11 +184,6 @@ module HammerCLI | |
| 135 184 | 
             
                      @schema = Schema.new(schema)
         | 
| 136 185 | 
             
                    end
         | 
| 137 186 |  | 
| 138 | 
            -
                    def description
         | 
| 139 | 
            -
                      _("Comma separated list of values defined by a schema. See Option details section below.") + "\n" +
         | 
| 140 | 
            -
                      _("JSON is acceptable and preferred way for complex parameters")
         | 
| 141 | 
            -
                    end
         | 
| 142 | 
            -
             | 
| 143 187 | 
             
                    def format(val)
         | 
| 144 188 | 
             
                      return [] unless val.is_a?(String) && !val.empty?
         | 
| 145 189 | 
             
                      begin
         | 
| @@ -152,9 +196,22 @@ module HammerCLI | |
| 152 196 | 
             
                        end
         | 
| 153 197 | 
             
                      end
         | 
| 154 198 | 
             
                    end
         | 
| 199 | 
            +
             | 
| 200 | 
            +
                    def completion_type
         | 
| 201 | 
            +
                      super.merge({ schema: schema.description(richtext: false) })
         | 
| 202 | 
            +
                    end
         | 
| 155 203 | 
             
                  end
         | 
| 156 204 |  | 
| 157 205 | 
             
                  class Number < AbstractNormalizer
         | 
| 206 | 
            +
                    class << self
         | 
| 207 | 
            +
                      def completion_type
         | 
| 208 | 
            +
                        :number
         | 
| 209 | 
            +
                      end
         | 
| 210 | 
            +
             | 
| 211 | 
            +
                      def common_description
         | 
| 212 | 
            +
                        _('Numeric value. Integer')
         | 
| 213 | 
            +
                      end
         | 
| 214 | 
            +
                    end
         | 
| 158 215 |  | 
| 159 216 | 
             
                    def format(val)
         | 
| 160 217 | 
             
                      if numeric?(val)
         | 
| @@ -167,17 +224,22 @@ module HammerCLI | |
| 167 224 | 
             
                    def numeric?(val)
         | 
| 168 225 | 
             
                      Integer(val) != nil rescue false
         | 
| 169 226 | 
             
                    end
         | 
| 170 | 
            -
             | 
| 171 227 | 
             
                  end
         | 
| 172 228 |  | 
| 173 229 |  | 
| 174 230 | 
             
                  class Bool < AbstractNormalizer
         | 
| 175 | 
            -
                     | 
| 176 | 
            -
                       | 
| 231 | 
            +
                    class << self
         | 
| 232 | 
            +
                      def completion_type
         | 
| 233 | 
            +
                        :boolean
         | 
| 234 | 
            +
                      end
         | 
| 235 | 
            +
             | 
| 236 | 
            +
                      def common_description
         | 
| 237 | 
            +
                        _('One of %s') % ['true/false', 'yes/no', '1/0'].join(', ')
         | 
| 238 | 
            +
                      end
         | 
| 177 239 | 
             
                    end
         | 
| 178 240 |  | 
| 179 | 
            -
                    def  | 
| 180 | 
            -
                       | 
| 241 | 
            +
                    def allowed_values
         | 
| 242 | 
            +
                      ['yes', 'no', 'true', 'false', '1', '0']
         | 
| 181 243 | 
             
                    end
         | 
| 182 244 |  | 
| 183 245 | 
             
                    def format(bool)
         | 
| @@ -194,10 +256,23 @@ module HammerCLI | |
| 194 256 | 
             
                    def complete(value)
         | 
| 195 257 | 
             
                      allowed_values.map { |v| v + ' ' }
         | 
| 196 258 | 
             
                    end
         | 
| 259 | 
            +
             | 
| 260 | 
            +
                    def completion_type
         | 
| 261 | 
            +
                      super.merge({ values: allowed_values })
         | 
| 262 | 
            +
                    end
         | 
| 197 263 | 
             
                  end
         | 
| 198 264 |  | 
| 199 265 |  | 
| 200 266 | 
             
                  class File < AbstractNormalizer
         | 
| 267 | 
            +
                    class << self
         | 
| 268 | 
            +
                      def completion_type
         | 
| 269 | 
            +
                        :file
         | 
| 270 | 
            +
                      end
         | 
| 271 | 
            +
             | 
| 272 | 
            +
                      def common_description
         | 
| 273 | 
            +
                        _('Path to a file')
         | 
| 274 | 
            +
                      end
         | 
| 275 | 
            +
                    end
         | 
| 201 276 |  | 
| 202 277 | 
             
                    def format(path)
         | 
| 203 278 | 
             
                      ::File.read(::File.expand_path(path))
         | 
| @@ -233,6 +308,16 @@ module HammerCLI | |
| 233 308 |  | 
| 234 309 |  | 
| 235 310 | 
             
                  class Enum < AbstractNormalizer
         | 
| 311 | 
            +
                    class << self
         | 
| 312 | 
            +
                      def completion_type
         | 
| 313 | 
            +
                        :enum
         | 
| 314 | 
            +
                      end
         | 
| 315 | 
            +
             | 
| 316 | 
            +
                      def common_description
         | 
| 317 | 
            +
                        _("Possible values are described in the option's description")
         | 
| 318 | 
            +
                      end
         | 
| 319 | 
            +
                    end
         | 
| 320 | 
            +
             | 
| 236 321 | 
             
                    attr_reader :allowed_values
         | 
| 237 322 |  | 
| 238 323 | 
             
                    def initialize(allowed_values)
         | 
| @@ -260,6 +345,10 @@ module HammerCLI | |
| 260 345 | 
             
                      Completer::finalize_completions(@allowed_values)
         | 
| 261 346 | 
             
                    end
         | 
| 262 347 |  | 
| 348 | 
            +
                    def completion_type
         | 
| 349 | 
            +
                      super.merge({ values: allowed_values })
         | 
| 350 | 
            +
                    end
         | 
| 351 | 
            +
             | 
| 263 352 | 
             
                    private
         | 
| 264 353 |  | 
| 265 354 | 
             
                    def quoted_values
         | 
| @@ -269,9 +358,14 @@ module HammerCLI | |
| 269 358 |  | 
| 270 359 |  | 
| 271 360 | 
             
                  class DateTime < AbstractNormalizer
         | 
| 361 | 
            +
                    class << self
         | 
| 362 | 
            +
                      def completion_type
         | 
| 363 | 
            +
                        :datetime
         | 
| 364 | 
            +
                      end
         | 
| 272 365 |  | 
| 273 | 
            -
             | 
| 274 | 
            -
             | 
| 366 | 
            +
                      def common_description
         | 
| 367 | 
            +
                        _('Date and time in YYYY-MM-DD HH:MM:SS or ISO 8601 format')
         | 
| 368 | 
            +
                      end
         | 
| 275 369 | 
             
                    end
         | 
| 276 370 |  | 
| 277 371 | 
             
                    def format(date)
         | 
| @@ -283,6 +377,16 @@ module HammerCLI | |
| 283 377 | 
             
                  end
         | 
| 284 378 |  | 
| 285 379 | 
             
                  class EnumList < AbstractNormalizer
         | 
| 380 | 
            +
                    class << self
         | 
| 381 | 
            +
                      def completion_type
         | 
| 382 | 
            +
                        :multienum
         | 
| 383 | 
            +
                      end
         | 
| 384 | 
            +
             | 
| 385 | 
            +
                      def common_description
         | 
| 386 | 
            +
                        _("Any combination of possible values described in the option's description")
         | 
| 387 | 
            +
                      end
         | 
| 388 | 
            +
                    end
         | 
| 389 | 
            +
             | 
| 286 390 | 
             
                    attr_reader :allowed_values
         | 
| 287 391 |  | 
| 288 392 | 
             
                    def initialize(allowed_values)
         | 
| @@ -301,6 +405,10 @@ module HammerCLI | |
| 301 405 | 
             
                      Completer::finalize_completions(@allowed_values)
         | 
| 302 406 | 
             
                    end
         | 
| 303 407 |  | 
| 408 | 
            +
                    def completion_type
         | 
| 409 | 
            +
                      super.merge({ values: allowed_values })
         | 
| 410 | 
            +
                    end
         | 
| 411 | 
            +
             | 
| 304 412 | 
             
                    private
         | 
| 305 413 |  | 
| 306 414 | 
             
                    def quoted_values
         | 
| @@ -22,12 +22,14 @@ module HammerCLI | |
| 22 22 |  | 
| 23 23 | 
             
                class OptionDefinition < Clamp::Option::Definition
         | 
| 24 24 |  | 
| 25 | 
            -
                  attr_accessor :value_formatter, :context_target, :deprecated_switches
         | 
| 25 | 
            +
                  attr_accessor :value_formatter, :context_target, :deprecated_switches,
         | 
| 26 | 
            +
                                :family
         | 
| 26 27 |  | 
| 27 28 | 
             
                  def initialize(switches, type, description, options = {})
         | 
| 28 29 | 
             
                    @value_formatter = options[:format] || HammerCLI::Options::Normalizers::Default.new
         | 
| 29 30 | 
             
                    @context_target = options[:context_target]
         | 
| 30 31 | 
             
                    @deprecated_switches = options[:deprecated]
         | 
| 32 | 
            +
                    @family = options[:family]
         | 
| 31 33 | 
             
                    super
         | 
| 32 34 | 
             
                  end
         | 
| 33 35 |  | 
| @@ -36,7 +38,9 @@ module HammerCLI | |
| 36 38 | 
             
                  end
         | 
| 37 39 |  | 
| 38 40 | 
             
                  def help_lhs
         | 
| 39 | 
            -
                     | 
| 41 | 
            +
                    lhs = switches.join(', ')
         | 
| 42 | 
            +
                    lhs += " #{completion_type[:type]}".upcase unless flag?
         | 
| 43 | 
            +
                    lhs
         | 
| 40 44 | 
             
                  end
         | 
| 41 45 |  | 
| 42 46 | 
             
                  def help_rhs
         | 
| @@ -50,14 +54,14 @@ module HammerCLI | |
| 50 54 | 
             
                    rhs.empty? ? " " : rhs
         | 
| 51 55 | 
             
                  end
         | 
| 52 56 |  | 
| 53 | 
            -
                  def  | 
| 57 | 
            +
                  def extract_value(switch, arguments)
         | 
| 54 58 | 
             
                    message = _("Warning: Option %{option} is deprecated. %{message}")
         | 
| 55 59 | 
             
                    if deprecated_switches.class <= String && switches.include?(switch)
         | 
| 56 | 
            -
                      warn(message % { : | 
| 60 | 
            +
                      warn(message % { option: switch, message: deprecated_switches })
         | 
| 57 61 | 
             
                    elsif deprecated_switches.class <= Hash && deprecated_switches.keys.include?(switch)
         | 
| 58 | 
            -
                      warn(message % { : | 
| 62 | 
            +
                      warn(message % { option: switch, message: deprecated_switches[switch] })
         | 
| 59 63 | 
             
                    end
         | 
| 60 | 
            -
                    super(switch)
         | 
| 64 | 
            +
                    super(switch, arguments)
         | 
| 61 65 | 
             
                  end
         | 
| 62 66 |  | 
| 63 67 | 
             
                  def deprecation_message(switch)
         | 
| @@ -140,22 +144,13 @@ module HammerCLI | |
| 140 144 | 
             
                    return { type: :flag } if @type == :flag
         | 
| 141 145 |  | 
| 142 146 | 
             
                    formatter ||= value_formatter
         | 
| 143 | 
            -
                    completion_type | 
| 144 | 
            -
             | 
| 145 | 
            -
             | 
| 146 | 
            -
             | 
| 147 | 
            -
             | 
| 148 | 
            -
             | 
| 149 | 
            -
             | 
| 150 | 
            -
                                        { type: :schema, schema: value_formatter.schema.description(richtext: false) }
         | 
| 151 | 
            -
                                      when HammerCLI::Options::Normalizers::List
         | 
| 152 | 
            -
                                        { type: :list }
         | 
| 153 | 
            -
                                      when HammerCLI::Options::Normalizers::KeyValueList
         | 
| 154 | 
            -
                                        { type: :key_value_list }
         | 
| 155 | 
            -
                                      when HammerCLI::Options::Normalizers::File
         | 
| 156 | 
            -
                                        { type: :file }
         | 
| 157 | 
            -
                                      end
         | 
| 158 | 
            -
                    completion_type || { type: :value }
         | 
| 147 | 
            +
                    formatter.completion_type
         | 
| 148 | 
            +
                  end
         | 
| 149 | 
            +
             | 
| 150 | 
            +
                  def child?
         | 
| 151 | 
            +
                    return unless @family
         | 
| 152 | 
            +
             | 
| 153 | 
            +
                    @family.children.include?(self)
         | 
| 159 154 | 
             
                  end
         | 
| 160 155 |  | 
| 161 156 | 
             
                  private
         | 
| @@ -2,25 +2,33 @@ | |
| 2 2 |  | 
| 3 3 | 
             
            module HammerCLI
         | 
| 4 4 | 
             
              module Options
         | 
| 5 | 
            +
                class OptionFamilyRegistry < Array
         | 
| 6 | 
            +
                  # rubocop:disable Style/Alias
         | 
| 7 | 
            +
                  alias_method :register, :push
         | 
| 8 | 
            +
                  alias_method :unregister, :delete
         | 
| 9 | 
            +
                  # rubocop:enable Style/Alias
         | 
| 10 | 
            +
                end
         | 
| 11 | 
            +
             | 
| 5 12 | 
             
                class OptionFamily
         | 
| 6 13 | 
             
                  attr_reader :children
         | 
| 7 14 |  | 
| 8 | 
            -
                  IDS_REGEX = /(\A[Ii][Dd][s]?)|\s([Ii][Dd][s]?)\W|([Ii][Dd][s]?\Z) | 
| 15 | 
            +
                  IDS_REGEX = /(\A[Ii][Dd][s]?)|\s([Ii][Dd][s]?)\W|([Ii][Dd][s]?\Z)|(numeric identifier|identifier)/.freeze
         | 
| 9 16 |  | 
| 10 17 | 
             
                  def initialize(options = {})
         | 
| 11 18 | 
             
                    @all = []
         | 
| 12 19 | 
             
                    @children = []
         | 
| 13 20 | 
             
                    @options = options
         | 
| 14 | 
            -
                    @creator = options[:creator] ||  | 
| 21 | 
            +
                    @creator = options[:creator] || self
         | 
| 15 22 | 
             
                    @prefix = options[:prefix]
         | 
| 16 23 | 
             
                    @root = options[:root] || options[:aliased_resource] || options[:referenced_resource]
         | 
| 24 | 
            +
                    @creator.family_registry.register(self) if @creator != self
         | 
| 17 25 | 
             
                  end
         | 
| 18 26 |  | 
| 19 27 | 
             
                  def description
         | 
| 20 28 | 
             
                    types = all.map(&:type).map { |s| s.split('_').last.to_s }
         | 
| 21 29 | 
             
                               .map(&:downcase).join('/')
         | 
| 22 | 
            -
                    parent_desc = @parent.help[1].gsub(IDS_REGEX) { |w| w.gsub(/\ | 
| 23 | 
            -
                    desc = parent_desc.strip.empty? ? @options[:description] : parent_desc
         | 
| 30 | 
            +
                    parent_desc = @parent.help[1].gsub(IDS_REGEX) { |w| w.gsub(/\b.+\b/, types) }
         | 
| 31 | 
            +
                    desc = @options[:description] || parent_desc.strip.empty? ? @options[:description] : parent_desc
         | 
| 24 32 | 
             
                    if @options[:deprecation].class <= String
         | 
| 25 33 | 
             
                      format_deprecation_msg(desc, _('Deprecated: %{deprecated_msg}') % { deprecated_msg: @options[:deprecation] })
         | 
| 26 34 | 
             
                    elsif @options[:deprecation].class <= Hash
         | 
| @@ -33,6 +41,21 @@ module HammerCLI | |
| 33 41 | 
             
                    end
         | 
| 34 42 | 
             
                  end
         | 
| 35 43 |  | 
| 44 | 
            +
                  def help
         | 
| 45 | 
            +
                    [help_lhs, help_rhs]
         | 
| 46 | 
            +
                  end
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                  def help_lhs
         | 
| 49 | 
            +
                    return @parent&.help_lhs if @children.empty?
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                    types = all.map(&:value_formatter).map { |f| f.completion_type[:type].to_s.upcase }
         | 
| 52 | 
            +
                    switch + ' ' + types.uniq.join('/')
         | 
| 53 | 
            +
                  end
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                  def help_rhs
         | 
| 56 | 
            +
                    description || @parent.help[1]
         | 
| 57 | 
            +
                  end
         | 
| 58 | 
            +
             | 
| 36 59 | 
             
                  def formats
         | 
| 37 60 | 
             
                    return [@options[:format].class] if @options[:format]
         | 
| 38 61 |  | 
| @@ -41,7 +64,7 @@ module HammerCLI | |
| 41 64 |  | 
| 42 65 | 
             
                  def switch
         | 
| 43 66 | 
             
                    return if @parent.nil? && @children.empty?
         | 
| 44 | 
            -
                    return @parent. | 
| 67 | 
            +
                    return @parent.switches.join(', ').strip if @children.empty?
         | 
| 45 68 |  | 
| 46 69 | 
             
                    switch_start = main_switch.each_char
         | 
| 47 70 | 
             
                                              .zip(*all.map(&:switches).flatten.map(&:each_char))
         | 
| @@ -68,6 +91,8 @@ module HammerCLI | |
| 68 91 |  | 
| 69 92 | 
             
                  def child(switches, type, description, opts = {}, &block)
         | 
| 70 93 | 
             
                    child = new_member(switches, type, description, opts, &block)
         | 
| 94 | 
            +
                    return unless child
         | 
| 95 | 
            +
             | 
| 71 96 | 
             
                    @children << child
         | 
| 72 97 | 
             
                    child
         | 
| 73 98 | 
             
                  end
         | 
| @@ -80,6 +105,18 @@ module HammerCLI | |
| 80 105 | 
             
                    @children << child
         | 
| 81 106 | 
             
                  end
         | 
| 82 107 |  | 
| 108 | 
            +
                  def root
         | 
| 109 | 
            +
                    @root || @parent&.aliased_resource || @parent&.referenced_resource || common_root
         | 
| 110 | 
            +
                  end
         | 
| 111 | 
            +
             | 
| 112 | 
            +
                  def option(*args)
         | 
| 113 | 
            +
                    HammerCLI::Apipie::OptionDefinition.new(*args)
         | 
| 114 | 
            +
                  end
         | 
| 115 | 
            +
             | 
| 116 | 
            +
                  def find_option(switch)
         | 
| 117 | 
            +
                    all.find { |m| m.handles?(switch) }
         | 
| 118 | 
            +
                  end
         | 
| 119 | 
            +
             | 
| 83 120 | 
             
                  private
         | 
| 84 121 |  | 
| 85 122 | 
             
                  def format_deprecation_msg(option_desc, deprecation_msg)
         | 
| @@ -90,18 +127,17 @@ module HammerCLI | |
| 90 127 | 
             
                    opts = opts.merge(@options)
         | 
| 91 128 | 
             
                    opts[:family] = self
         | 
| 92 129 | 
             
                    if opts[:deprecated]
         | 
| 93 | 
            -
                      handles =  | 
| 130 | 
            +
                      handles = Array(switches)
         | 
| 94 131 | 
             
                      opts[:deprecated] = opts[:deprecated].select do |switch, _msg|
         | 
| 95 132 | 
             
                        handles.include?(switch)
         | 
| 96 133 | 
             
                      end
         | 
| 97 134 | 
             
                    end
         | 
| 98 135 | 
             
                    @creator.instance_eval do
         | 
| 99 | 
            -
                      option(switches, type, description, opts, &block)
         | 
| 136 | 
            +
                      option(switches, type, description, opts, &block) unless Array(switches).any? { |s| find_option(s) }
         | 
| 100 137 | 
             
                    end
         | 
| 101 138 | 
             
                  end
         | 
| 102 139 |  | 
| 103 140 | 
             
                  def main_switch
         | 
| 104 | 
            -
                    root = @root || @parent.aliased_resource || @parent.referenced_resource || common_root
         | 
| 105 141 | 
             
                    "--#{@prefix}#{root}".tr('_', '-')
         | 
| 106 142 | 
             
                  end
         | 
| 107 143 |  | 
| @@ -76,7 +76,7 @@ module HammerCLI::Output::Adapter | |
| 76 76 | 
             
                def render_value(field, data)
         | 
| 77 77 | 
             
                  formatter = @formatters.formatter_for_type(field.class)
         | 
| 78 78 | 
             
                  parameters = field.parameters
         | 
| 79 | 
            -
                  parameters[:context] =  | 
| 79 | 
            +
                  parameters[:context] = context_for_fields
         | 
| 80 80 | 
             
                  data = formatter.format(data, field.parameters) if formatter
         | 
| 81 81 | 
             
                  data.to_s
         | 
| 82 82 | 
             
                end
         | 
| @@ -55,7 +55,7 @@ module HammerCLI::Output::Adapter | |
| 55 55 | 
             
                  else
         | 
| 56 56 | 
             
                    formatter = @formatters.formatter_for_type(field.class)
         | 
| 57 57 | 
             
                    parameters = field.parameters
         | 
| 58 | 
            -
                    parameters[:context] =  | 
| 58 | 
            +
                    parameters[:context] = context_for_fields
         | 
| 59 59 | 
             
                    if formatter
         | 
| 60 60 | 
             
                      data = formatter.format(data, field.parameters)
         | 
| 61 61 | 
             
                    end
         | 
| @@ -73,7 +73,7 @@ module HammerCLI::Output | |
| 73 73 |  | 
| 74 74 | 
             
                    data << sets.each_with_object({}) do |set, res|
         | 
| 75 75 | 
             
                      mark = field.sets.include?(set) ? 'x' : ''
         | 
| 76 | 
            -
                      value = set == sets.first ? field.full_label : mark
         | 
| 76 | 
            +
                      value = set == sets.first ? field.full_label.capitalize : mark
         | 
| 77 77 | 
             
                      res.update(set => value)
         | 
| 78 78 | 
             
                    end
         | 
| 79 79 | 
             
                  end
         | 
| @@ -11,7 +11,7 @@ module HammerCLI::Output | |
| 11 11 |  | 
| 12 12 | 
             
                def fields=(fields)
         | 
| 13 13 | 
             
                  @fields = fields || []
         | 
| 14 | 
            -
                  @filtered_fields = @fields | 
| 14 | 
            +
                  @filtered_fields = Marshal.load(Marshal.dump(@fields))
         | 
| 15 15 | 
             
                end
         | 
| 16 16 |  | 
| 17 17 | 
             
                def filter_by_classes(classes = nil)
         | 
| @@ -66,7 +66,7 @@ module HammerCLI::Output | |
| 66 66 |  | 
| 67 67 | 
             
                def include_by_label?(labels, label)
         | 
| 68 68 | 
             
                  labels.any? do |l|
         | 
| 69 | 
            -
                    l.start_with?("#{label}/") || label.match(%r{^#{l.gsub(/\*/, '.*')}(|\/.*)$})
         | 
| 69 | 
            +
                    l.start_with?("#{label}/") || label.match(%r{^#{l.gsub(/\*/, '.*')}(|\/.*)$}) || l == label
         | 
| 70 70 | 
             
                  end
         | 
| 71 71 | 
             
                end
         | 
| 72 72 |  | 
    
        data/lib/hammer_cli/utils.rb
    CHANGED
    
    | @@ -40,6 +40,12 @@ class String | |
| 40 40 | 
             
                HammerCLI.constant_path(self)[-1]
         | 
| 41 41 | 
             
              end
         | 
| 42 42 |  | 
| 43 | 
            +
              # Rails implementation: https://github.com/rails/rails/blob/main/actionview/lib/action_view/helpers/text_helper.rb#L260
         | 
| 44 | 
            +
              def wrap(line_width: 80, break_sequence: "\n")
         | 
| 45 | 
            +
                split("\n").collect! do |line|
         | 
| 46 | 
            +
                  line.length > line_width ? line.gsub(/(.{1,#{line_width}})(\s+|$)/, "\\1#{break_sequence}").strip : line
         | 
| 47 | 
            +
                end * break_sequence
         | 
| 48 | 
            +
              end
         | 
| 43 49 | 
             
            end
         | 
| 44 50 |  | 
| 45 51 | 
             
            class Hash
         | 
    
        data/lib/hammer_cli/version.rb
    CHANGED
    
    
| Binary file | 
| Binary file | 
| Binary file | 
| Binary file | 
| Binary file | 
| Binary file | 
| Binary file | 
| Binary file | 
| Binary file | 
| Binary file | 
| Binary file | 
| Binary file | 
| Binary file | 
    
        data/man/hammer.1.gz
    CHANGED
    
    | Binary file | 
    
        data/test/unit/abstract_test.rb
    CHANGED
    
    | @@ -308,6 +308,13 @@ describe HammerCLI::AbstractCommand do | |
| 308 308 | 
             
                  opt = TestOptionCmd.find_option('--fields')
         | 
| 309 309 | 
             
                  opt.is_a?(HammerCLI::Options::OptionDefinition).must_equal true
         | 
| 310 310 | 
             
                end
         | 
| 311 | 
            +
             | 
| 312 | 
            +
                it 'should add option type and accepted value' do
         | 
| 313 | 
            +
                  help_str = TestOptionCmd.help('')
         | 
| 314 | 
            +
                  help_str.must_match(
         | 
| 315 | 
            +
                    /LIST                Comma separated list of values. Values containing comma should be quoted or escaped with backslash./
         | 
| 316 | 
            +
                  )
         | 
| 317 | 
            +
                end
         | 
| 311 318 | 
             
              end
         | 
| 312 319 |  | 
| 313 320 | 
             
              describe "#options" do
         | 
| @@ -17,7 +17,7 @@ describe HammerCLI::Apipie::OptionBuilder do | |
| 17 17 | 
             
              let(:resource) {api.resource(:documented)}
         | 
| 18 18 | 
             
              let(:action) {resource.action(:index)}
         | 
| 19 19 | 
             
              let(:builder) { HammerCLI::Apipie::OptionBuilder.new(resource, action) }
         | 
| 20 | 
            -
              let(:builder_options) { {} }
         | 
| 20 | 
            +
              let(:builder_options) { { command: Class.new(HammerCLI::Apipie::Command) } }
         | 
| 21 21 | 
             
              let(:options) { builder.build(builder_options) }
         | 
| 22 22 |  | 
| 23 23 | 
             
              context "with one simple param" do
         | 
| @@ -51,7 +51,7 @@ describe HammerCLI::Apipie::OptionBuilder do | |
| 51 51 | 
             
              context "required options" do
         | 
| 52 52 |  | 
| 53 53 | 
             
                let(:action) {resource.action(:create)}
         | 
| 54 | 
            -
                let(:required_options) { builder.build.reject{|opt| !opt.required?} }
         | 
| 54 | 
            +
                let(:required_options) { builder.build(builder_options).reject{|opt| !opt.required?} }
         | 
| 55 55 |  | 
| 56 56 | 
             
                it "should set required flag for the required options" do
         | 
| 57 57 | 
             
                  required_options.map(&:attribute_name).sort.must_equal [HammerCLI.option_accessor_name("array_param")]
         | 
| @@ -146,7 +146,12 @@ describe HammerCLI::Apipie::OptionBuilder do | |
| 146 146 |  | 
| 147 147 | 
             
              context "aliasing resources" do
         | 
| 148 148 | 
             
                let(:action) {resource.action(:action_with_ids)}
         | 
| 149 | 
            -
                let(:builder_options)  | 
| 149 | 
            +
                let(:builder_options) do
         | 
| 150 | 
            +
                  {
         | 
| 151 | 
            +
                    resource_mapping: { organization: 'company', 'compute_resource' => :compute_provider },
         | 
| 152 | 
            +
                    command: Class.new(HammerCLI::Apipie::Command)
         | 
| 153 | 
            +
                  }
         | 
| 154 | 
            +
                end
         | 
| 150 155 |  | 
| 151 156 | 
             
                it "renames options" do
         | 
| 152 157 | 
             
                  # builder_options[:resource_mapping] = {:organization => 'company', 'compute_resource' => :compute_provider}
         | 
| @@ -118,7 +118,7 @@ describe HammerCLI::CommandExtensions do | |
| 118 118 | 
             
                it 'should extend option family only' do
         | 
| 119 119 | 
             
                  cmd.extend_with(CmdExtensions.new(only: :option_family))
         | 
| 120 120 | 
             
                  cmd.output_definition.empty?.must_equal true
         | 
| 121 | 
            -
                  cmd.recognised_options.map(&:switches).flatten.must_equal [' | 
| 121 | 
            +
                  cmd.recognised_options.map(&:switches).flatten.must_equal ['-h', '--help', '--test-one', '--test-two']
         | 
| 122 122 | 
             
                end
         | 
| 123 123 | 
             
              end
         | 
| 124 124 |  | 
| @@ -203,5 +203,13 @@ describe HammerCLI::CommandExtensions do | |
| 203 203 | 
             
                end
         | 
| 204 204 | 
             
              end
         | 
| 205 205 |  | 
| 206 | 
            -
             | 
| 206 | 
            +
              context 'associate family' do
         | 
| 207 | 
            +
                it 'should associate option family' do
         | 
| 208 | 
            +
                  cmd.extend_with(CmdExtensions.new(only: :option_family))
         | 
| 209 | 
            +
                  cmd.option_family associate: 'test' do
         | 
| 210 | 
            +
                    child '--test-three', '', ''
         | 
| 211 | 
            +
                  end
         | 
| 212 | 
            +
                  cmd.recognised_options.map(&:switches).flatten.must_equal ['-h', '--help', '--test-one', '--test-two', '--test-three']
         | 
| 213 | 
            +
                end
         | 
| 214 | 
            +
              end
         | 
| 207 215 | 
             
            end
         |