Module: Mixlib::CLI

Defined in:
lib/mixlib/cli.rb,
lib/mixlib/cli/version.rb

Overview

Mixlib::CLI

Adds a DSL for defining command line options and methods for parsing those options to the including class.

Mixlib::CLI does some setup in #initialize, so the including class must call `super()` if it defines a custom initializer.

DSL

When included, Mixlib::CLI also extends the including class with its ClassMethods, which define the DSL. The primary methods of the DSL are ClassMethods#option, which defines a command line option, and ClassMethods#banner, which defines the “usage” banner.

Parsing

Command line options are parsed by calling the instance method #parse_options. After calling this method, the attribute #config will contain a hash of `:option_name => value` pairs.

Defined Under Namespace

Modules: ClassMethods, InheritMethods

Constant Summary collapse

VERSION =
"2.0.1".freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

Banner for the option parser. If the option parser is printed, e.g., by `puts opt_parser`, this string will be used as the first line.


174
175
176
# File 'lib/mixlib/cli.rb', line 174

def banner
  @banner
end

#cli_argumentsObject

Any arguments which were not parsed and placed in “config”–the leftovers.


170
171
172
# File 'lib/mixlib/cli.rb', line 170

def cli_arguments
  @cli_arguments
end

#configObject

A Hash containing the values supplied by command line options.

The behavior and contents of this Hash vary depending on whether ClassMethods#use_separate_default_options is enabled.

use_separate_default_options disabled

After initialization, config will contain any default values defined via the mixlib-config DSL. When #parse_options is called, user-supplied values (from ARGV) will be merged in.

use_separate_default_options enabled

After initialization, this will be an empty hash. When #parse_options is called, config is populated only with user-supplied values.


159
160
161
# File 'lib/mixlib/cli.rb', line 159

def config
  @config
end

#default_configObject

If ClassMethods#use_separate_default_options is enabled, this will be a Hash containing key value pairs of `:option_name => default_value` (populated during object initialization).

If use_separate_default_options is disabled, it will always be an empty hash.


167
168
169
# File 'lib/mixlib/cli.rb', line 167

def default_config
  @default_config
end

#optionsObject

Gives the command line options definition as configured in the DSL. These are used by #parse_options to generate the option parsing code. To get the values supplied by the user, see #config.


146
147
148
# File 'lib/mixlib/cli.rb', line 146

def options
  @options
end

Class Method Details

.included(receiver) ⇒ Object


324
325
326
327
# File 'lib/mixlib/cli.rb', line 324

def self.included(receiver)
  receiver.extend(Mixlib::CLI::ClassMethods)
  receiver.extend(Mixlib::CLI::InheritMethods)
end

Instance Method Details

#build_option_arguments(opt_setting) ⇒ Object


308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
# File 'lib/mixlib/cli.rb', line 308

def build_option_arguments(opt_setting)
  arguments = Array.new

  arguments << opt_setting[:short] if opt_setting.key?(:short)
  arguments << opt_setting[:long] if opt_setting.key?(:long)
  if opt_setting.key?(:description)
    description = opt_setting[:description].dup
    description << " (required)" if opt_setting[:required]
    description << " (included in ['#{opt_setting[:in].join("', '")}'])" if opt_setting[:in]
    opt_setting[:description] = description
    arguments << description
  end

  arguments
end

#initialize(*args) ⇒ Object

Create a new Mixlib::CLI class. If you override this, make sure you call super!

Parameters

*args<Array>

The array of arguments passed to the initializer

Returns

object<Mixlib::Config>

Returns an instance of whatever you wanted :)


183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
# File 'lib/mixlib/cli.rb', line 183

def initialize(*args)
  @options = Hash.new
  @config  = Hash.new
  @default_config = Hash.new
  @opt_parser = nil

  # Set the banner
  @banner = self.class.banner

  # Dupe the class options for this instance
  klass_options = self.class.options
  klass_options.keys.inject(@options) { |memo, key| memo[key] = klass_options[key].dup; memo }

  # If use_separate_defaults? is on, default values go in @default_config
  defaults_container = if self.class.use_separate_defaults?
                         @default_config
                       else
                         @config
                       end

  # Set the default configuration values for this instance
  @options.each do |config_key, config_opts|
    config_opts[:on] ||= :on
    config_opts[:boolean] ||= false
    config_opts[:required] ||= false
    config_opts[:proc] ||= nil
    config_opts[:show_options] ||= false
    config_opts[:exit] ||= nil
    config_opts[:in] ||= nil

    if config_opts.key?(:default)
      defaults_container[config_key] = config_opts[:default]
    end
  end

  super(*args)
end

#opt_parserObject

The option parser generated from the mixlib-cli DSL. opt_parser can be used to print a help message including the banner and any CLI options via `puts opt_parser`.

Returns

opt_parser<OptionParser>

The option parser object.


262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
# File 'lib/mixlib/cli.rb', line 262

def opt_parser
  @opt_parser ||= OptionParser.new do |opts|
    # Set the banner
    opts.banner = banner

    # Create new options
    options.sort { |a, b| a[0].to_s <=> b[0].to_s }.each do |opt_key, opt_val|
      opt_args = build_option_arguments(opt_val)

      opt_method = case opt_val[:on]
                   when :on
                     :on
                   when :tail
                     :on_tail
                   when :head
                     :on_head
                   else
                     raise ArgumentError, "You must pass :on, :tail, or :head to :on"
                   end

      parse_block =
        Proc.new() do |c|
          config[opt_key] = if opt_val[:proc]
                              if opt_val[:proc].arity == 2
                                # New hotness to allow for reducer-style procs.
                                opt_val[:proc].call(c, config[opt_key])
                              else
                                # Older single-argument proc.
                                opt_val[:proc].call(c)
                              end
                            else
                              # No proc.
                              c
                            end
          puts opts if opt_val[:show_options]
          exit opt_val[:exit] if opt_val[:exit]
        end

      full_opt = [ opt_method ]
      opt_args.inject(full_opt) { |memo, arg| memo << arg; memo }
      full_opt << parse_block
      opts.send(*full_opt)
    end
  end
end

#parse_options(argv = ARGV) ⇒ Object

Parses an array, by default ARGV, for command line options (as configured at the class level).

Parameters

argv<Array>

The array of arguments to parse; defaults to ARGV

Returns

argv<Array>

Returns any un-parsed elements.


228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
# File 'lib/mixlib/cli.rb', line 228

def parse_options(argv = ARGV)
  argv = argv.dup
  opt_parser.parse!(argv)

  # Deal with any required values
  options.each do |opt_key, opt_value|
    if opt_value[:required] && !config.key?(opt_key)
      reqarg = opt_value[:short] || opt_value[:long]
      puts "You must supply #{reqarg}!"
      puts @opt_parser
      exit 2
    end
    if opt_value[:in]
      unless opt_value[:in].kind_of?(Array)
        raise(ArgumentError, "Options config key :in must receive an Array")
      end
      if config[opt_key] && !opt_value[:in].include?(config[opt_key])
        reqarg = opt_value[:short] || opt_value[:long]
        puts "#{reqarg}: #{config[opt_key]} is not included in the list ['#{opt_value[:in].join("', '")}'] "
        puts @opt_parser
        exit 2
      end
    end
  end

  @cli_arguments = argv
  argv
end