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
Post a Comment