module OptParseGen
Small lib for generating an OptionParser from an OpenStruct
Constants
- SPECIAL_POSTFIXES
Special postfixes for Hash keys
Public Class Methods
Does the magic
@todo write documentation :( @todo split this up @param ostruct [OpenStruct] Default values with special values @param :ignore_collisions [Boolean] ignore bool key collisions see OptionCollision
@param :generate_no_help [Boolean] when set to true donesn't generates help command
# File lib/optsparser_generator.rb, line 60 def self.[](ostruct, **options) defaults = handle_arguments(ostruct) optparser = OptionParser.new do |opts| opts.instance_variable_set(:@required, {}) defaults.each_pair do |key, val| trigger = key.to_s.tr('_', '-') next if trigger.end_with?(*SPECIAL_POSTFIXES) arguments = generate_arguments(defaults, key, val) case val when FalseClass, TrueClass uneven_no = /\Ano(-no-no)*-(?!no)/ =~ trigger if trigger.start_with?('no-') trigger.gsub!(/\A(no-)+/, '') # removes no- prefixes check_collisions(trigger, key, defaults) unless options[:ignore_collisions] end arguments.unshift "--[no-]#{trigger}" block = lambda do |bool| # inverted when it starts with no_ bool ^ uneven_no end else klass = val.class klass = val.is_a?(Integer) ? Integer : klass klass = defaults.special_value(key, 'class') || klass arguments.push klass values = defaults.special_value(key, 'values') arguments.push values if values arguments.unshift "--#{trigger}=ARG" block = lambda do |str| str end end if (proc = defaults.special_value(key, 'proc')) block = proc end opts.on(*arguments) do |arg| opts.instance_variable_get(:@required)[key] = true opts.instance_variable_get(:@out)[key] = block.call(arg) end if defaults.special_value(key, 'required') opts.instance_variable_get(:@required)[key] = false end end unless options[:generate_no_help] opts.on('-h', '--help') do puts opts exit end end end # add default values optparser.instance_variable_set(:@defaults, defaults) optparser.extend(OptParsePatch) end
Shorthand when parsing is only needed once.
Generates an OptionParser and calls parse on it @see OptionParserGenerator#[] @return [OpenStruct]
# File lib/optsparser_generator.rb, line 173 def self.parse(ostruct, argv, **opt) self[ostruct, **opt].parse(argv) end
Same as parse, removes parsed elements from argv @see OptionParserGenerator#parse @return [OpenStruct]
# File lib/optsparser_generator.rb, line 180 def self.parse!(ostruct, argv = ARGV, **opt) self[ostruct, **opt].parse!(argv) end
Private Class Methods
@api private
# File lib/optsparser_generator.rb, line 140 def self.check_collisions(trigger, key, defaults) if defaults.each_pair.map{ |v| v.first.to_s }.include?(trigger) raise OptionCollision, "on #{key}" end end
returns an array of helptext and if set the short version of trigger @api private
# File lib/optsparser_generator.rb, line 123 def self.generate_arguments(defaults, key, val) short = defaults.special_value(key, 'short') || '' if short.length > 1 raise ArgumentError, 'short is too long, it has to be only one character' end help = "#{defaults.special_value(key, 'help')} (Default: #{val})" if short.empty? [help] else [help, "-#{short}"] end end
Does some sanity checks and prepares the OpenStruct @todo preprocess data here instead of doing it adhoc @todo raise more exceptions @api private @param ostruct [OpenStruct]
# File lib/optsparser_generator.rb, line 43 def self.handle_arguments(ostruct) unless ostruct.is_a?(OpenStruct) raise WrongArgumentType, 'needs an OpenStruct' end ostruct = ostruct.dup ostruct.extend(OpenStructExtension) ostruct.freeze # freeze is not needed but makes development easier end