From: Josh Cheek Date: 2011-09-26T06:03:59+09:00 Subject: Re: Looking for better/familiar approach to command line opts --20cf3071d0527c8af704adca613b Content-Type: text/plain; charset=ISO-8859-1 On Sun, Sep 25, 2011 at 3:48 PM, Perl J. wrote: > 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/. > > Ruby has a builtin -s flag, which will parse args I don't know Perl so I can't say if it will meet your needs, but does this program do what you want? ----- #!/usr/bin/env ruby -s options = { :source_path => 's' :dest_path => 'd' :verbose => 'v' } p options --20cf3071d0527c8af704adca613b--