command line interface - How to DRYly subclass (or otherwise share code with) rubys OptionParser to e.g. share options? -


i want share options multiple scripts , prefer use 'builtin' optparse on other cli-or-optionparsing-frameworks.

i looked @ mris optparse.rb , not understand how best sublass optionparser (the initializer takes block).

optimally arrive @ code this

# exe/a_script require 'mygem'  options = {whatever: 'default'} mygem::optionparser.new |opts|   opts.on('--whatever') |w|     options[:whatever] = w   end end.parse! 

and second script consumer:

# exe/other_script require 'mygem'   options = {and_another: 'default'} mygem::optionparser.new |opts|   opts.on('--and_another') |a|     options[:and_another] = w   end end.parse! 

and define "default option" (say "-v" verbose , "-h" help" in common custom optionparser.

# lib/mygem/mygem_optionparser.rb require 'optparse' module mygem   class optionparser < optionparser     # magic     # define opts.on("-v") -> set options[:verbose],     # define opts.on_tail("-h", "print , exit") ...   end end 

both scripts should end having , handling "-h" , "-v" flags, ideally filling "options" hash, exposing mygem::optionparser#default_option_values.

where start? or there clever way of handling differently, e.g.

# exe/b_script optionparser.new |opts|   define_custom_opts(opts) end 

i wonder have not found tutorial or example on scenario, assume not such rare use-case. , yes, absolutely want stick 'optparse'.

update got confused, not looking @ correct optpase-source , not seeing yields self (which freaked me out bit :) . great answers far.

i haven't used optionparser there may better way this, i'll take stab @ anyway.

the important thing optionparser#initialize (for our purposes) yields self block given. make subclass works same, have make initialize method yield self, too:

require 'optparse' require 'ostruct'  module mygem   class optionparser < ::optionparser     attr_reader :options      def initialize(*args)       @options = openstruct.new        super *args       default_options!        yield(self, options) if block_given?     end      private     def default_options!       on '--whatever=whatever' |w|         options.whatever = w       end     end   end end 

this calls super of passed arguments except passed block (if given). calls default_options! create default options (this have done passing block super, find above cleaner).

finally, yields given block superclass did, passes second argument, options object. user can use this:

require 'my_gem/option_parser'  opts = mygem::optionparser.new |parser, options|   parser.on '--and-another=another' |a|     options.another =   end end  opts.parse! p opts.options 

this give user results following:

$ ruby script.rb --whatever=www --and-another=aaa #<openstruct whatever="www", another="aaa"> 

as alternative yield(self, options), use yield self, user need e.g. parser.options.whatever = ... inside block.

another alternative add &block argument initialize , instance_eval(&block) instead of yield. evaluate block in instance context, user access options attribute (and other instance methods, etc.) directly, e.g.:

parser = mygem::optionparser.new   on '--and-another=another' |a|     options.another =   end end  parser.parse! 

that has downside, however, user must know block evaluated in instance context. prefer explicit yield(self, options).


Comments

Popular posts from this blog

ios - UITEXTFIELD InputView Uipicker not working in swift -

Hatching array of circles in AutoCAD using c# -