NAME main.rb SYNOPSIS a class factory and dsl for generating command line programs real quick URI http://codeforpeople.com/lib/ruby/ http://rubyforge.org/projects/codeforpeople/ http://codeforpeople.rubyforge.org/svn/ INSTALL gem install main DESCRIPTION main.rb features the following: - unification of option, argument, keyword, and environment parameter parsing - auto generation of usage and help messages - support for mode/sub-commands - io redirection support - logging hooks using ruby's built-in logging mechanism - intelligent error handling and exit codes - use as dsl or library for building Main objects - parsing user defined ARGV and ENV - zero requirements for understanding the obtuse apis of *any* command line option parsers - leather pants in short main.rb aims to drastically lower the barrier to writing uniform command line applications. for instance, this program require 'main' Main { argument 'foo' option 'bar' def run p params['foo'] p params['bar'] exit_success! end } sets up a program which requires one argument, 'bar', and which may accept one command line switch, '--foo' in addition to the single option/mode which is always accepted and handled appropriately: 'help', '--help', '-h'. for the most part main.rb stays out of your command line namespace but insists that your application has at least a help mode/option. main.rb supports sub-commands in a very simple way require 'main' Main { mode 'install' do def run() puts 'installing...' end end mode 'uninstall' do def run() puts 'uninstalling...' end end } which allows a program, called 'a.rb', to be invoked as ruby a.rb install and ruby a.rb uninstall for simple programs main.rb is a real time saver but it's for more complex applications where main.rb's unification of parameter parsing, class configuration dsl, and auto-generation of usage messages can really streamline command line application development. for example the following 'a.rb' program: require 'main' Main { argument('foo'){ cast :int } keyword('bar'){ arity 2 cast :float defaults 0.0, 1.0 } option('foobar'){ argument :optional description 'the foobar option is very handy' } environment('BARFOO'){ cast :list_of_bool synopsis 'export barfoo=value' } def run p params['foo'].value p params['bar'].values p params['foobar'].value p params['BARFOO'].value end } when run with a command line of BARFOO=true,false,false ruby a.rb 42 bar=40 bar=2 --foobar=a will produce 42 [40.0, 2.0] "a" [true, false, false] while a command line of ruby a.rb --help will produce NAME a.rb SYNOPSIS a.rb foo [bar=bar] [options]+ PARAMETERS * foo [ 1 -> int(foo) ] * bar=bar [ 2 ~> float(bar=0.0,1.0) ] * --foobar=[foobar] [ 1 ~> foobar ] the foobar option is very handy * --help, -h * export barfoo=value and this shows how all of argument, keyword, option, and environment parsing can be declartively dealt with in a unified fashion - the dsl for all parameter types is the same - and how auto synopsis and usage generation saves keystrokes. the parameter synopsis is compact and can be read as * foo [ 1 -> int(foo) ] 'one argument will get processed via int(argument_name)' 1 : one argument -> : will get processed (the argument is required) int(foo) : the cast is int, the arg name is foo * bar=bar [ 2 ~> float(bar=0.0,1.0) ] 'two keyword arguments might be processed via float(bar=0.0,1.0)' 2 : two arguments ~> : might be processed (the argument is optional) float(bar=0.0,1.0) : the cast will be float, the default values are 0.0 and 1.0 * --foobar=[foobar] [ 1 ~> foobar ] 'one option with optional argument may be given directly' * --help, -h no synopsis, simple switch takes no args and is not required * export barfoo=value a user defined synopsis SAMPLES @samples DOCS test/main.rb find ./lib |xargs vim -o API section below HISTORY 2.7.0 - removed bundled arrayfields and attributes. these are now dependancies mananged by rubygems. a.k.a. you must have rubygems installed for main to work. 2.6.0 - added 'mixin' feaature for storing, and later evaluating a block of code. the purpose of this is for use with modes where you want to keep your code dry, but may not want to define something in the base class for all to inherit. 'mixin' allows you to define the code to inherit once and the selectively drop it in child classes (modes) on demand. for example Main { mixin :foobar do option 'foo' option 'bar' end mode :install do mixin :foobar end mode :uninstall do mixin :foobar end mode :clean do end } - mode definitions are now deferred to the end of the Main block, so you can do this Main { mode 'a' do mixin :foo end mode 'b' do mixin :foo end def inherited_method 42 end mixin 'foo' do def another_inherited_method 'forty-two' end end } - added sanity check at end of paramter contruction - improved auto usage generation when arity is used with arguments - removed 'p' shortcut in paramerter dsl because it collided with Kernel.p. it's now called 'param'. this method is availble *inside* a parameter definition option('foo', 'f'){ synopsis "arity = #{ param.arity }" } - fixed bug where '--' did not signal the end of parameter parsing in a getoptlong compliant way - added (before/after)_parse_parameters, (before/after)_initialize, and (before/after)_run hooks - fixed bug where adding to usage via usage['my_section'] = 'custom message' totally horked the default auto generated usage message - updated dependancies in gemspec.rb for attributes (~> 5.0.0) and arrayfields (~> 4.3.0) - check that client co