From: "Ara.T.Howard" Date: 2005-06-14T06:03:54+09:00 Subject: [ANN] parseargs-0.1.0 URLS http://raa.ruby-lang.org/search.rhtml?search=parseargs http://codeforpeople.com/lib/ruby/parseargs ABOUT parseargs is a library that faciltates the parsing of arguments and keywords from method paramters, setting of default values, validation, contraints via class based or duck based typing, and coercion/convincing to type/ducktype when possible. HISTORY 0.1.0 several critical bug fixes and made a few mods the enable more compact argument specifications (it's gone positive!) 0.0.0 initial version AUTHOR ara [dot] t [dot] howard [at] noaa [dot] gov SAMPLES <========< sample/a.rb >========> ~ > cat sample/a.rb require 'parseargs' include ParseArgs # # simple use will declare which required and optional arguments a method can # accept. default values may be specifed if a hash is given as the argument # specification. an exception is thrown if required arguments are not given at # method invocation. # def method(*a) pa = parseargs(a) { required_argument :a optional_argument :b => 2 } p pa end method 4 #=> {:a=>4, :b=>2} ~ > ruby sample/a.rb {:a=>4, :b=>2} <========< sample/b.rb >========> ~ > cat sample/b.rb require 'parseargs' include ParseArgs # # keywords can be declared in exactly the same way, and can be given at # invocation as either strings or symbols. default values may also be named for # both arguments and keywords. note that a required keyword with a default # specified is really an optional keyword ;-) # def method(*a) pa = parseargs(a) { required_argument :a required_keyword :b, :default => 2 optional_keyword :c } p pa end method 4, 'b' => 2 #=> {:a=>4, :b=>2, :c=>nil} ~ > ruby sample/b.rb {:a=>4, :b=>2, :c=>nil} <========< sample/c.rb >========> ~ > cat sample/c.rb require 'parseargs' include ParseArgs # # several abbreviations exist to make the declaration more compact. # def method(*a) pa = parseargs(a) { r_arg :a r_kw :b o_kw :c } if pa.c puts "#{ pa.c }" else puts "#{ pa.a }#{ pa.b }" end end method 4, :b => 2 #=> 42 method 4, :b => 2, 'c' => 42 #=> 42 # # groups of definitions can be specified, here x, y, and z all share a default # value of 1 # def method(*a) pa = parseargs(a){ arg 'a'; kws %w( x y z ) => 1 } puts "#{ pa.a + pa.x }#{ pa.y + pa.z }" end method 3 #=> 42 ~ > ruby sample/c.rb 42 42 42 <========< sample/d.rb >========> ~ > cat sample/d.rb require 'parseargs' include ParseArgs # # many keywords or arguments can be specified at once using a list or something # enumerable - this example specifies 26 possible keywords # def method(*a) pa = parseargs(a) { r_arg 'arg' o_kws 'a' .. 'z' } puts "#{ pa.arg }#{ pa.a ? pa.a : pa.z }" end method 4, 'a' => 2 #=> 42 method 4, 'z' => 2 #=> 42 ~ > ruby sample/d.rb 42 42 <========< sample/e.rb >========> ~ > cat sample/e.rb require 'parseargs' include ParseArgs # # a single, or list of types may be given and the argument of invocation must be # one of those types as reports by '===' # def method(*a) pa = parseargs(a) { req_arg 'number', 'types' => [Float, Fixnum] } p pa.number end method 42 #=> 42 method 42.0 #=> 42.0 method '42.0' #=> ./lib/parseargs.rb:112:in `value=': value given not of type(Float,Fixnum) in 'number=' (TypeError) ~ > ruby sample/e.rb 42 42.0 ./lib/parseargs.rb:112:in `value=': value given not of type(Float,Fixnum) in 'number=' (TypeError) from ./lib/parseargs.rb:344:in `parse' from ./lib/parseargs.rb:339:in `each' from ./lib/parseargs.rb:339:in `parse' from ./lib/parseargs.rb:447:in `parseargs' from ./lib/parseargs.rb:430:in `parseargs' from sample/e.rb:10:in `method' from sample/e.rb:19 <========< sample/f.rb >========> ~ > cat sample/f.rb require 'parseargs' include ParseArgs # # failure of an argument to match a given type will cause coercion to be applied # if specified. the coerce argument may be either a method name or a proc that # receives the obj to be coerced. in either case the return value is used as # the new argument. # def method(*a) pa = parseargs(a) { arg :a, :types => Fixnum, :coerce => 'to_i' kw :b, :types => Fixnum, :coerce => lambda{|obj| obj.to_i} } p pa end method 4, :b => 2 #=> {:a=>4, :b=>2} method '4', :b => '2' #=> {:a=>4, :b=>2} ~ > ruby sample/f.rb {:a=>4, :b=>2} {:a=>4, :b=>2} <========< sample/g.rb >========> ~ > cat sample/g.rb require 'parseargs' include ParseArgs # # ducktyping is supported as a method name, or list of method names - all of # which an argument must respond_to? in order for an exception not to be thrown. # this is a very simple ducktype signature. # def method(*a) pa = parseargs(a) { r_arg 'string', 'ducktype' => [:upcase, :downcase] } puts pa.string.upcase.downcase end method '42' #=> 42 method :fubar #=> ./lib/parseargs.rb:127:in `value=': value given not of ducktype(upcase,downcase) in 'string=' (TypeError) ~ > ruby sample/g.rb 42 ./lib/parseargs.rb:127:in `value=': value given not of ducktype(upcase,downcase) in 'string=' (TypeError) from ./lib/parseargs.rb:344:in `parse' from ./lib/parseargs.rb:339:in `each' from ./lib/parseargs.rb:339:in `parse' from ./lib/parseargs.rb:447:in `parseargs' from ./lib/parseargs.rb:430:in `parseargs' from sample/g.rb:11:in `method' from sample/g.rb:19 <========< sample/h.rb >========> ~ > cat sample/h.rb require 'parseargs' include ParseArgs # # a kind of ducktype 'coercion' - somthing i'm calling 'convincing' - may be # applied in order to convince an object that it really can play a certain role. # an argument may be 'convinced' via a module, which will be used to extend the # object on the fly, or a block which is passed the object and expected to # modify it's singleton class in such a way as to allow the object to become a # valid argument # module M def quack 2 end end def method(*a) pa = parseargs(a) { ra 'a', 'ducktype' => :quack, 'convince' => lambda{|obj| class << obj; def quack; 4; end; end} ra 'b', 'ducktype' => :quack, 'convince' => M } puts "#{ pa.a.quack }#{ pa.b.quack }" end method 'any ol', 'objects' #=> 42 ~ > ruby sample/h.rb 42 <========< sample/i.rb >========> ~ > cat sample/i.rb require 'parseargs' # # of course all this would be kind of silly for the simple cases shown - but it # can become very powerful as a form of meta-programming aid or when many # kewords are to be supported # class Command include ParseArgs KEYWORDS = %w( verbose quiet log help info force recursive stdin stdout stderr ) PARSER = ParseArgs::Parser::new { KEYWORDS.each{|kw| optional_keyword kw} } def initialize cmd @cmd = cmd end def execute(*argv) opts = PARSER.parse argv p @cmd => opts.select{|k,v| not v.nil?} end def background(*argv) opts = PARSER.parse argv p @cmd => opts.select{|k,v| not v.nil?} end end foo = Command::new 'foo.exe' foo.execute 'verbose' => true, 'stdin' => 'input.txt' #=> {"foo.exe"=>[["stdin", "input.txt"], ["verbose", true]]} bar = Command::new 'bar.exe' bar.execute 'verbose' => false, 'stdout' => 'output.txt' #=> {"bar.exe"=>[["stdout", "output.txt"], ["verbose", false]]} ~ > ruby sample/i.rb {"foo.exe"=>[["stdin", "input.txt"], ["verbose", true]]} {"bar.exe"=>[["stdout", "output.txt"], ["verbose", false]]} CAVEATS this library is __experimental__! -a -- =============================================================================== | email :: ara [dot] t [dot] howard [at] noaa [dot] gov | phone :: 303.497.6469 | My religion is very simple. My religion is kindness. | --Tenzin Gyatso ===============================================================================