From: "Perl J." Date: 2011-09-26T05:48:44+09:00 Subject: Looking for better/familiar approach to command line opts So I guess the warning to the reader upfront is... I'm a bit of a Perl hack who should have moved to Ruby a decade ago and just couldn't let go of Perl. Perl still does stuff that I use extensively that I can't (take the time to) figure out how to do in Ruby, so... that's why I'm here. I've got a small framework I wrote in Perl I've been using for years that is lightweight and yet powerful. A lot of it centers around the use of AUTOLOAD, which some Perlers say is bad -- I say it's extremely powerful if used properly, and actually, AUTOLOAD forms a lot of the backbone for my framework. And honestly, it's helped me do some things in Perl that I see in Ruby. So there's some irony here in that I wrote a framework to give me some of the power I see in Ruby in Perl. :-) With all that as a backdrop, here's how I can process command line arguments in Perl (*everything* I do in Perl is OO!!) and I want the same thing in Ruby. OptParser in Ruby is WAY more than I'm looking for -- not as easy as what I'm used to (or maybe I don't understand OptParser, which is likely). In Perl, I can do this: options = MyFramework::Options->new( sourcePath => 's:' destPath => 'd:' verbose => 'v' ); What ends up happening behind the scenes is a class instance is created dynamically that essentially gives me the ability to say: ## I actually have a puts() I created in Perl as well, ## borrowed from Ruby! puts( "Source path.......: " . $options->sourcePath, "Destination path..: " . $options->destPath, "Verbose is........: " . ($options->verbose ? 'ON' : 'OFF'), ); So I have a getter for sourcePath, a getter for destPath and a getter for verbose, automagically created for that instance loaded with the values from the command line. If I said: whatever = MyFramework::Options->new( foo => 'f:', bar => 'b:', ); Then I would have an instance of 'whatever' with foo and bar as getters, etc. with the values of 'f' and 'b' from the command line loaded appropriately. Now how to do this in Ruby? Like I said, the OptParser seems WAY too complicated for what I want and am trying to do. It seems like you still are coding some kind of OptParser class for the specific options you want -- I don't want to create classes that mirror the command line options. I want to tell the class instance at the time I create it (kind of like OpenStruct) what it looks like and it just creates the right instance. I want to be able to do this in Ruby, assuming I would "define" this dynamically on the fly using maybe a hash as initial input... I like the flexibility of hashes: options = Options.new({ :sPath => 's:', :dPath => 'd:', :verbose => 'v', }) puts "Source path.......: #{options.sPath}" puts "Destination path..: #{options.dPath}" puts "Verbose is........: #{options.verbose ? 'ON' : 'OFF'}" What this is saying is "map the value of 's' from the command line into @sPath, map the value of 'd' from the command line into @dPath, and map whether 'v' exists, true or false, into @verbose." Now how much more simple can you get??!! Again, the warning of "trying to do Ruby stuff in a Perl way" comes to me, but what I do in Perl is so stinking simple, it's unbelievable, and this is one reason I haven't switched over to Ruby yet. But now I'm trying. Things I've tried: A lot of different combinations of... -- missing_method() -- define_method() (I don't understand why a lot of d_m() examples use self.class.send()!!) -- Struct() -- OpenStruct() So far, requiring "optparse" and doing ARGV.getopts() does some of what I want. This is as close as I've gotten and it's not working: require "optparse" class Options attr_reader :cmdline, :options_list def initialize( options ) @cmdline = ARGV.join( ' ' ) @options_list = options.values.join params = ARGV.getopts( @options_list ) options.each do |key,value| ## Why do I need to send( :define_method, ... ) here? ## Why can't I just say self.define_method? ## This seems like it would create proper closure ## on params[] elements?! self.class.send( :define_method, key ) { params[value] } end end end options = Options.new({ :sPath => 's:', :dPath => 'd:', :verbose => 'v', }) If someone can tell me how to do this using OptParser, so be it. But from an encapsulation standpoint, I'd like to be able to call it as I do above. If the innards of the Options class use OptParser, fine. -pj -- Posted via http://www.ruby-forum.com/.