[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 :wink:
     #

     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

   <========< 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

   <========< 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}

   <========< 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

===============================================================================