Class: OctocatalogDiff::Cli::Options

Inherits:
Object
  • Object
show all
Defined in:
lib/octocatalog-diff/cli/options.rb

Overview

This class contains the option parser. ‘parse_options’ is the external entry point.

Defined Under Namespace

Classes: DocBuildError, Option

Constant Summary collapse

'Usage: catalog-diff -n <hostname>[,<hostname>...] [-f <from environment>] [-t <to environment>]'.freeze

Class Method Summary collapse

Class Method Details

.classesObject

List of classes



20
21
22
# File 'lib/octocatalog-diff/cli/options.rb', line 20

def self.classes
  @classes ||= []
end

.option_classesArray<Class>

Read in *.rb files in the ‘options’ directory and create classes from them. Sort the classes according to weight and name and return the list of sorted classes.

Returns:

  • (Array<Class>)

    Sorted classes



83
84
85
86
87
88
89
90
91
92
93
# File 'lib/octocatalog-diff/cli/options.rb', line 83

def self.option_classes
  files = Dir.glob(File.join(File.dirname(__FILE__), 'options', '*.rb'))
  files.each { |file| load file } # Populates self.classes
  classes.sort do |a, b|
    [
      a.weight <=> b.weight,
      a.name.downcase <=> b.name.downcase,
      a.object_id <=> b.object_id
    ].find(&:nonzero?)
  end
end

.option_globally_or_per_branch(opts = {}) ⇒ Object

Sets up options that can be defined globally or for just one branch. For example, with a CLI name of ‘puppet-binary’ this will acknowledge 3 options: –puppet-binary (global), –from-puppet-binary (for the from branch only), and –to-puppet-binary (for the to branch only). The only options that will be created are the ‘to’ and ‘from’ variants, but the global option will populate any of the ‘to’ and ‘from’ variants that are missing.

Parameters:

  • :datatype (?)

    Expected data type

Raises:

  • (ArgumentError)


101
102
103
104
105
106
107
108
# File 'lib/octocatalog-diff/cli/options.rb', line 101

def self.option_globally_or_per_branch(opts = {})
  opts[:filename] = caller[0].split(':').first
  datatype = opts.fetch(:datatype, '')
  return option_globally_or_per_branch_string(opts) if datatype.is_a?(String)
  return option_globally_or_per_branch_array(opts) if datatype.is_a?(Array)
  return option_globally_or_per_branch_boolean(opts) if datatype.is_a?(TrueClass) || datatype.is_a?(FalseClass)
  raise ArgumentError, "option_globally_or_per_branch not equipped to handle #{datatype.class}"
end

.option_globally_or_per_branch_array(opts = {}) ⇒ Object

See description of ‘option_globally_or_per_branch`. This implements the logic for an array.

Parameters:

  • :parser (OptionParser object)

    The OptionParser argument

  • :options (Hash)

    Options hash being constructed; this is modified in this method.

  • :cli_name (String)

    Name of option on command line (e.g. puppet-binary)

  • :option_name (Symbol)

    Name of option in the options hash (e.g. :puppet_binary)

  • :desc (String)

    Description of option on the command line; will have “for the XX branch” appended



151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
# File 'lib/octocatalog-diff/cli/options.rb', line 151

def self.option_globally_or_per_branch_array(opts = {})
  parser = opts.fetch(:parser)
  options = opts.fetch(:options)
  cli_name = opts.fetch(:cli_name)
  option_name = opts.fetch(:option_name)
  desc = opts.fetch(:desc)

  flag = "#{cli_name} STRING1[,STRING2[,...]]"
  from_option = "from_#{option_name}".to_sym
  to_option = "to_#{option_name}".to_sym
  parser.on("--#{flag}", Array, "#{desc} globally") do |x|
    validate_option(opts, x)
    translated = translate_option(opts[:translator], x)
    options[to_option] ||= []
    options[to_option].concat translated
    options[from_option] ||= []
    options[from_option].concat translated
  end
  parser.on("--to-#{flag}", Array, "#{desc} for the to branch") do |x|
    validate_option(opts, x)
    options[to_option] ||= []
    options[to_option].concat translate_option(opts[:translator], x)
  end
  parser.on("--from-#{flag}", Array, "#{desc} for the from branch") do |x|
    validate_option(opts, x)
    options[from_option] ||= []
    options[from_option].concat translate_option(opts[:translator], x)
  end
end

.option_globally_or_per_branch_boolean(opts) ⇒ Object

See description of ‘option_globally_or_per_branch`. This implements the logic for a boolean value.

Parameters:

  • :parser (OptionParser object)

    The OptionParser argument

  • :options (Hash)

    Options hash being constructed; this is modified in this method.

  • :cli_name (String)

    Name of option on command line (e.g. puppet-binary)

  • :option_name (Symbol)

    Name of option in the options hash (e.g. :puppet_binary)

  • :desc (String)

    Description of option on the command line; will have “for the XX branch” appended



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
# File 'lib/octocatalog-diff/cli/options.rb', line 187

def self.option_globally_or_per_branch_boolean(opts)
  parser = opts.fetch(:parser)
  options = opts.fetch(:options)
  cli_name = opts.fetch(:cli_name)
  option_name = opts.fetch(:option_name)
  desc = opts.fetch(:desc)

  flag = cli_name
  from_option = "from_#{option_name}".to_sym
  to_option = "to_#{option_name}".to_sym
  parser.on("--[no-]#{flag}", "#{desc} globally") do |x|
    translated = translate_option(opts[:translator], x)
    options[to_option] = translated
    options[from_option] = translated
    post_process(opts[:post_process], options)
  end
  parser.on("--[no-]to-#{flag}", "#{desc} for the to branch") do |x|
    translated = translate_option(opts[:translator], x)
    options[to_option] = translated
    post_process(opts[:post_process], options)
  end
  parser.on("--[no-]from-#{flag}", "#{desc} for the from branch") do |x|
    translated = translate_option(opts[:translator], x)
    options[from_option] = translated
    post_process(opts[:post_process], options)
  end
end

.option_globally_or_per_branch_string(opts) ⇒ Object

See description of ‘option_globally_or_per_branch`. This implements the logic for a string value.

Parameters:

  • :parser (OptionParser object)

    The OptionParser argument

  • :options (Hash)

    Options hash being constructed; this is modified in this method.

  • :cli_name (String)

    Name of option on command line (e.g. puppet-binary)

  • :option_name (Symbol)

    Name of option in the options hash (e.g. :puppet_binary)

  • :desc (String)

    Description of option on the command line; will have “for the XX branch” appended



116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/octocatalog-diff/cli/options.rb', line 116

def self.option_globally_or_per_branch_string(opts)
  parser = opts.fetch(:parser)
  options = opts.fetch(:options)
  cli_name = opts.fetch(:cli_name)
  option_name = opts.fetch(:option_name)
  desc = opts.fetch(:desc)

  flag = "#{cli_name} STRING"
  from_option = "from_#{option_name}".to_sym
  to_option = "to_#{option_name}".to_sym
  parser.on("--#{flag}", "#{desc} globally") do |x|
    validate_option(opts, x)
    translated = translate_option(opts[:translator], x)
    options[to_option] ||= translated
    options[from_option] ||= translated
    post_process(opts[:post_process], options)
  end
  parser.on("--to-#{flag}", "#{desc} for the to branch") do |x|
    validate_option(opts, x)
    options[to_option] = translate_option(opts[:translator], x)
    post_process(opts[:post_process], options)
  end
  parser.on("--from-#{flag}", "#{desc} for the from branch") do |x|
    validate_option(opts, x)
    options[from_option] = translate_option(opts[:translator], x)
    post_process(opts[:post_process], options)
  end
end

.parse_options(argv, defaults = {}) ⇒ Hash

Method to call all of the other methods in this class. Except in very specific circumstances, this should be the method called from outside of this class.

Parameters:

  • argv (Array)

    Array of command line arguments

  • defaults (Hash) (defaults to: {})

    Default values

Returns:

  • (Hash)

    Parsed options



63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/octocatalog-diff/cli/options.rb', line 63

def self.parse_options(argv, defaults = {})
  options = defaults.dup
  Options.classes.clear
  ::OptionParser.new do |parser|
    parser.banner = "#{BANNER}\n\n"
    option_classes.each do |klass|
      obj = klass.new
      obj.parse(parser, options)
    end
    parser.on_tail('-v', '--version', 'Show version information about this program and quit.') do
      puts "octocatalog-diff #{OctocatalogDiff::Version::VERSION}"
      exit
    end
  end.parse! argv
  options
end

.post_process(processor, options) ⇒ Object

Code that can run after a translation and operate upon all options. This returns nothing but may modify options that were input.

Parameters:

  • processor (Code)

    Processor function

  • options (Hash)

    Options hash



245
246
247
248
# File 'lib/octocatalog-diff/cli/options.rb', line 245

def self.post_process(processor, options)
  return if processor.nil?
  processor.call(options)
end

.translate_option(translator, value) ⇒ ?

If a translator was provided, run the translator on the supplied value. The translator is expected to return the data type needed for the option (typically a String but can really be anything). Note that the translator runs after the validator if both a validator and translator are supplied.

Parameters:

  • translator (Code)

    Translator function

  • value (?)

    Original input value

Returns:

  • (?)

    Translated value



236
237
238
239
# File 'lib/octocatalog-diff/cli/options.rb', line 236

def self.translate_option(translator, value)
  return value if translator.nil?
  translator.call(value)
end

.validate_option(opts, value) ⇒ Object

If a validator was provided, run the validator on the supplied value. The validator is expected to throw an error if there is a problem. Note that the validator runs before the translator if both a validator and translator are supplied.

Parameters:

  • opts (Hash)

    Options hash

  • value (?)

    Value to validate (typically a String but can really be anything)

Raises:



220
221
222
223
224
225
226
227
228
# File 'lib/octocatalog-diff/cli/options.rb', line 220

def self.validate_option(opts, value)
  # Special value to help build documentation automatically, since the source file location
  # for `option_globally_or_per_branch` is always this file.
  raise DocBuildError, opts[:filename] if value == :DOC_BUILD_FILENAME

  validator = opts[:validator]
  return true unless validator
  validator.call(value)
end