From: Jeremy Hinegardner Date: 2007-05-28T12:15:37+09:00 Subject: Re: please help me with OptionParser --dc+cDN39EJAMEtIO Content-Type: text/plain; charset=us-ascii Content-Disposition: inline On Mon, May 28, 2007 at 03:17:32AM +0900, Christopher J. Bottaro wrote: > Here's the pastebin of this post if you prefer looking at formatted > source: > http://pastebin.ca/514353 > > Ok, I'm having a multitude of problems with OptionParser. First, I > can't get it to work following the online documentation. Which online documentation are you using? http://www.ruby-doc.org/stdlib/libdoc/optparse/rdoc/classes/OptionParser.html That's the documentation that I use. > Second, I got it to work by adding :REQUIRED to the on() method call, > but that doesn't work as expected: the argument isn't really > "required"; OptionParser does not bomb if the argument is omitted. That's not actually how you do it. The style to code up a required argument is: opts.on("-c", "--client ID", "client id to migrate for") Putting something after the option tells option parser that you require an argument on that option. In this cases putting ID after --client tells the parser that this option has a required argument. use [ID] to designate option parameters. To force ID to be an integer, you can change the option to be: opts.on("-c", "--client ID", Integer, "client id to migrate for") ... This will make sure that ID is an Integer before passing to the block. If it isn't it will throw and exception. > Third, I cannot get a switch to accept multiple arguments. > --my_arg 1 2 3 > I want an array [1, 2, 3]. Array style arguments are done as comma separated items that are passed to the block as an Array. So ch opts.on("-c", "--client ID,ID", Array, "client id(s) to migrate for") ... In your case, it seems you want to make sure that the option parameters to ID is an Array of Integers. Which means you'll have to tweak it a bit for yourself. I've written up one solution in the attached .rb file. > Thanks for the help, the rest of the message contains my pastebin > post: > Play with the attached test cases and make it do what you want. I made tests to describe what you wanted, and the Application class that is tested meets those test. enjoy, -jeremy -- ======================================================================== Jeremy Hinegardner jeremy@hinegardner.org --dc+cDN39EJAMEtIO Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="integer-array-options.rb" #!/usr/bin/env ruby require 'optparse' require 'ostruct' require 'test/unit' class OptionParserTestApplication attr_accessor :options def initialize @options = default_options @parser = option_parser end def run(argv = []) begin @parser.parse!(argv) rescue OptionParser::ParseError => pe puts pe puts @parser exit 1 end end def default_options op = OpenStruct.new op.client_ids = [] op.save = false return op end def option_parser OptionParser.new do |opts| opts.on("-c", "--client ID,LIST", Array,"client id to migrate for") do |client_id_list| client_id_list.each do |cid| begin @options.client_ids << Integer(cid) rescue ArgumentError => e raise OptionParser::ParseError, "#{cid} is not an integer" end end end opts.on_tail("-h", "--help", "Show this message") do puts opts exit end end end end class TestOptions < Test::Unit::TestCase def setup @app = OptionParserTestApplication.new end def test_client_id_required argv = %w(--client) assert_raise(SystemExit) { @app.run(argv) } end def test_client_ids_are_integer argv = %w(--client 123) @app.run(argv) assert_equal(123,@app.options.client_ids.first) end def test_client_ids_as_array argv = %w(--client 123,456) @app.run(argv) assert_equal(2,@app.options.client_ids.size) assert(@app.options.client_ids.include?(123)) assert(@app.options.client_ids.include?(456)) end def test_client_ids_as_array_of_integers argv = %w(--client 123,not-a-number) assert_raise(SystemExit) { @app.run(argv) } end end --dc+cDN39EJAMEtIO--